Пример #1
0
// return 0: ok
// return 1: cannot activate client
// return 2: cannot connect output port
// return 3: Jack server not running
// return 4: output port = NULL
int JackOutput::connect()
{
	INFOLOG( "connect" );

	if ( jack_activate ( client ) ) {
		Hydrogen::get_instance()->raiseError( Hydrogen::JACK_CANNOT_ACTIVATE_CLIENT );
		return 1;
	}


	bool connect_output_ports = m_bConnectOutFlag;

	memset( track_output_ports_L, 0, sizeof(track_output_ports_L) );
	memset( track_output_ports_R, 0, sizeof(track_output_ports_R) );

#ifdef H2CORE_HAVE_LASH
	if ( Preferences::get_instance()->useLash() ){
		LashClient* lashClient = LashClient::get_instance();
		if (lashClient && lashClient->isConnected())
		{
			//		infoLog("[LASH] Sending Jack client name to LASH server");
			lashClient->sendJackClientName();

			if (!lashClient->isNewProject())
			{
				connect_output_ports = false;
			}
		}
	}
#endif

	if ( connect_output_ports ) {
		//	if ( m_bConnectOutFlag ) {
		// connect the ports
		if ( jack_connect( client, jack_port_name( output_port_1 ), output_port_name_1.toLocal8Bit() ) == 0 &&
			 jack_connect ( client, jack_port_name( output_port_2 ), output_port_name_2.toLocal8Bit() ) == 0 ) {
			return 0;
		}

		INFOLOG( "Could not connect so saved out-ports. Connecting to first pair of in-ports" );
		const char ** portnames = jack_get_ports ( client, NULL, NULL, JackPortIsInput );
		if ( !portnames || !portnames[0] || !portnames[1] ) {
			ERRORLOG( "Could't locate two Jack input port" );
			Hydrogen::get_instance()->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
			return 2;
		}
		if ( jack_connect( client, jack_port_name( output_port_1 ), portnames[0] ) != 0 ||
			 jack_connect( client, jack_port_name( output_port_2 ), portnames[1] ) != 0 ) {
			ERRORLOG( "Could't connect to first pair of Jack input ports" );
			Hydrogen::get_instance()->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
			return 2;
		}
		free( portnames );
	}

	return 0;
}
Пример #2
0
MainForm::MainForm( QApplication *app, const QString& songFilename )
	: QMainWindow( 0, 0 )
	, Object( __class_name )
{
	setMinimumSize( QSize( 1000, 500 ) );
	setWindowIcon( QPixmap( Skin::getImagePath() + "/icon16.png" ) );

#ifndef WIN32
	if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigusr1Fd))
		qFatal("Couldn't create HUP socketpair");
	snUsr1 = new QSocketNotifier(sigusr1Fd[1], QSocketNotifier::Read, this);
	connect(snUsr1, SIGNAL(activated(int)), this, SLOT( handleSigUsr1() ));
#endif


	m_pQApp = app;

	m_pQApp->processEvents();

	// Load default song
	Song *pSong = NULL;

	if ( !songFilename.isEmpty() ) {
		pSong = Song::load( songFilename );

		/*
		 * If the song could not be loaded, create
		 * a new one with the specified filename
		 */
		if (pSong == NULL) {
			pSong = Song::get_empty_song();
			pSong->set_filename( songFilename );
		}
	}
	else {
		Preferences *pref = Preferences::get_instance();
		bool restoreLastSong = pref->isRestoreLastSongEnabled();
		QString filename = pref->getLastSongFilename();
		if ( restoreLastSong && ( !filename.isEmpty() )) {
			pSong = Song::load( filename );
			if (pSong == NULL) {
				//QMessageBox::warning( this, "Hydrogen", trUtf8("Error restoring last song.") );
				pSong = Song::get_empty_song();
				pSong->set_filename( "" );
			}
		}
		else {
			pSong = Song::get_empty_song();
			pSong->set_filename( "" );
		}
	}

	h2app = new HydrogenApp( this, pSong );
	h2app->addEventListener( this );
	createMenuBar();

	h2app->setStatusBarMessage( trUtf8("Hydrogen Ready."), 10000 );

	initKeyInstMap();

	// we need to do all this to support the keyboard playing
	// for all the window modes
	h2app->getMixer()->installEventFilter (this);
	h2app->getPatternEditorPanel()->installEventFilter (this);
	h2app->getPatternEditorPanel()->getPianoRollEditor()->installEventFilter (this);
	h2app->getSongEditorPanel()->installEventFilter (this);
	h2app->getPlayerControl()->installEventFilter(this);
	InstrumentEditorPanel::get_instance()->installEventFilter(this);
	h2app->getAudioEngineInfoForm()->installEventFilter(this);
	h2app->getDirector()->installEventFilter(this);
	//	h2app->getPlayListDialog()->installEventFilter(this);
	installEventFilter( this );

	showDevelWarning();

	connect( &m_autosaveTimer, SIGNAL(timeout()), this, SLOT(onAutoSaveTimer()));
	m_autosaveTimer.start( 60 * 1000 );


#ifdef H2CORE_HAVE_LASH

	if ( Preferences::get_instance()->useLash() ){
		LashClient* lashClient = LashClient::get_instance();
		if (lashClient->isConnected())
		{
			// send alsa client id now since it can only be sent
			// after the audio engine has been started.
			Preferences *pref = Preferences::get_instance();
			if ( pref->m_sMidiDriver == "ALSA" ) {
				//			infoLog("[LASH] Sending alsa seq id to LASH server");
				lashClient->sendAlsaClientId();
			}
			// start timer for polling lash events
			lashPollTimer = new QTimer(this);
			connect( lashPollTimer, SIGNAL( timeout() ), this, SLOT( onLashPollTimer() ) );
			lashPollTimer->start(500);
		}
	}
#endif


	//playlist display timer
	QTimer *playlistDisplayTimer = new QTimer(this);
	connect( playlistDisplayTimer, SIGNAL( timeout() ), this, SLOT( onPlaylistDisplayTimer() ) );
	playlistDisplayTimer->start(30000);	// update player control at
	// ~ playlist display timer

	//beatcouter
	Hydrogen::get_instance()->setBcOffsetAdjust();
	// director
	EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 );
	EventQueue::get_instance()->push_event( EVENT_METRONOME, 3 );

	undoView = new QUndoView(h2app->m_undoStack);
	undoView->setWindowTitle(tr("Undo history"));
	undoView->setWindowIcon( QPixmap( Skin::getImagePath() + "/icon16.png" ) );

	//restore last playlist
	if( Preferences::get_instance()->isRestoreLastPlaylistEnabled() ){
		bool loadlist = h2app->getPlayListDialog()->loadListByFileName( Preferences::get_instance()->getLastPlaylistFilename() );
		if( !loadlist ){
			_ERRORLOG ( "Error loading the playlist" );
		}
	}
}
Пример #3
0
void MainForm::onLashPollTimer()
{
#ifdef H2CORE_HAVE_LASH
	if ( Preferences::get_instance()->useLash() ){
		LashClient* client = LashClient::get_instance();

		if (!client->isConnected())
		{
			WARNINGLOG("[LASH] Not connected to server!");
			return;
		}

		bool keep_running = true;

		lash_event_t* event;

		string songFilename;
		QString filenameSong;
		Song *song = Hydrogen::get_instance()->getSong();
		// Extra parentheses for -Wparentheses
		while ( (event = client->getNextEvent()) ) {

			switch (lash_event_get_type(event)) {

			case LASH_Save_File:

				INFOLOG("[LASH] Save file");

				songFilename.append(lash_event_get_string(event));
				songFilename.append("/hydrogen.h2song");

				filenameSong = QString::fromLocal8Bit( songFilename.c_str() );
				song->set_filename( filenameSong );
				action_file_save();

				client->sendEvent(LASH_Save_File);

				break;

			case LASH_Restore_File:

				songFilename.append(lash_event_get_string(event));
				songFilename.append("/hydrogen.h2song");

				INFOLOG( QString("[LASH] Restore file: %1")
						 .arg( songFilename.c_str() ) );

				filenameSong = QString::fromLocal8Bit( songFilename.c_str() );

				openSongFile( filenameSong );

				client->sendEvent(LASH_Restore_File);

				break;

			case LASH_Quit:

				//				infoLog("[LASH] Quit!");
				keep_running = false;

				break;

			default:
				;
				//				infoLog("[LASH] Got unknown event!");

			}

			lash_event_destroy(event);

		}

		if (!keep_running)
		{
			lashPollTimer->stop();
			action_file_exit();
		}
	}
#endif
}
Пример #4
0
int JackOutput::init( unsigned /*nBufferSize*/ )
{
	Preferences* pref = Preferences::get_instance();
	output_port_name_1 = pref->m_sJackPortName1;
	output_port_name_2 = pref->m_sJackPortName2;

	QString sClientName = "Hydrogen";

#ifdef H2CORE_HAVE_NSMSESSION
	QString nsmClientId = pref->getNsmClientId();

	if(!nsmClientId.isEmpty()){
		sClientName = nsmClientId;
	}
#endif


	jack_status_t status;
	int tries = 2;  // Sometimes jackd doesn't stop and start fast enough.
	while ( tries > 0 ) {
		--tries;

#ifdef H2CORE_HAVE_JACKSESSION
		if (pref->getJackSessionUUID().isEmpty()){
			client = jack_client_open(
						 sClientName.toLocal8Bit(),
						 JackNullOption,
						 &status);
		} else {
			const QByteArray uuid = pref->getJackSessionUUID().toLocal8Bit();
			client = jack_client_open(
						 sClientName.toLocal8Bit(),
						 JackSessionID,
						 &status,
						 uuid.constData());
		}
#else
		client = jack_client_open(
					 sClientName.toLocal8Bit(),
					 JackNullOption,
					 &status);
#endif
		switch(status) {
			case JackFailure:
				CLIENT_FAILURE("unknown error");
				break;
			case JackInvalidOption:
				CLIENT_FAILURE("invalid option");
				break;
			case JackNameNotUnique:
				if (client) {
					sClientName = jack_get_client_name(client);
					CLIENT_SUCCESS(QString("Jack assigned the client name '%1'").arg(sClientName));
				} else {
					CLIENT_FAILURE("name not unique");
				}
				break;
			case JackServerStarted:
				CLIENT_SUCCESS("JACK Server started for Hydrogen.");
				break;
			case JackServerFailed:
				CLIENT_FAILURE("unable to connect");
				break;
			case JackServerError:
				CLIENT_FAILURE("communication error");
				break;
			case JackNoSuchClient:
				CLIENT_FAILURE("unknown client type");
				break;
			case JackLoadFailure:
				CLIENT_FAILURE("can't load internal client");
				break;
			case JackInitFailure:
				CLIENT_FAILURE("can't initialize client");
				break;
			case JackShmFailure:
				CLIENT_FAILURE("unable to access shared memory");
				break;
			case JackVersionError:
				CLIENT_FAILURE("client/server protocol version mismatch");
			default:
				if (status) {
					ERRORLOG("Unknown status with JACK server.");
					if (client) {
						CLIENT_SUCCESS("Client pointer is *not* null..."
									   " assuming we're OK");
					}
				} else {
					CLIENT_SUCCESS("Connected to JACK server");
				}
		}
	}

	if (client == 0) return -1;

	// Here, client should either be valid, or NULL.
	jack_server_sampleRate = jack_get_sample_rate ( client );
	jack_server_bufferSize = jack_get_buffer_size ( client );

	pref->m_nSampleRate = jack_server_sampleRate;
	pref->m_nBufferSize = jack_server_bufferSize;

	/* tell the JACK server to call `process()' whenever
	   there is work to be done.
	*/
	jack_set_process_callback ( client, this->processCallback, 0 );

	/* tell the JACK server to call `srate()' whenever
	   the sample rate of the system changes.
	*/
	jack_set_sample_rate_callback ( client, jackDriverSampleRate, this );

	/* tell JACK server to update us if the buffer size
	   (frames per process cycle) changes.
	*/
	jack_set_buffer_size_callback ( client, jackDriverBufferSize, 0 );

	/* tell the JACK server to call `jack_shutdown()' if
	   it ever shuts down, either entirely, or if it
	   just decides to stop calling us.
	*/
	jack_on_shutdown ( client, jackDriverShutdown, 0 );

	/* create two ports */
	output_port_1 = jack_port_register ( client, "out_L", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
	output_port_2 = jack_port_register ( client, "out_R", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );

	Hydrogen *H = Hydrogen::get_instance();
	if ( ( output_port_1 == NULL ) || ( output_port_2 == NULL ) ) {
		H->raiseError( Hydrogen::JACK_ERROR_IN_PORT_REGISTER );
		return 4;
	}

	// clear buffers
	//	jack_default_audio_sample_t *out_L = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port_1, jack_server_bufferSize);
	//	jack_default_audio_sample_t *out_R = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port_2, jack_server_bufferSize);
	//	memset( out_L, 0, nBufferSize * sizeof( float ) );
	//	memset( out_R, 0, nBufferSize * sizeof( float ) );

#ifdef H2CORE_HAVE_LASH
	if ( pref->useLash() ){
		LashClient* lashClient = LashClient::get_instance();
		if (lashClient->isConnected()) {
			lashClient->setJackClientName(sClientName.toLocal8Bit().constData());
		}
	}
#endif

#ifdef H2CORE_HAVE_JACKSESSION
	jack_set_session_callback (client, jack_session_callback, (void*)this);
#endif

	if ( pref->m_bJackMasterMode == Preferences::USE_JACK_TIME_MASTER )
		initTimeMaster();

	return 0;
}
Пример #5
0
int JackAudioDriver::init( unsigned bufferSize )
{
	// Destination ports the output of Hydrogen will be connected
	// to.
	Preferences* pPref = Preferences::get_instance();
	output_port_name_1 = pPref->m_sJackPortName1;
	output_port_name_2 = pPref->m_sJackPortName2;

	QString sClientName = "Hydrogen";

#ifdef H2CORE_HAVE_OSC
	QString sNsmClientId = pPref->getNsmClientId();

	if(!sNsmClientId.isEmpty()){
		sClientName = sNsmClientId;
	}
#endif

	// The address of the status object will be used by JACK to
	// return information from the open operation.
	jack_status_t status;
	// Sometimes jackd doesn't stop and start fast enough.
	int nTries = 2;
	while ( nTries > 0 ) {
		--nTries;

		// Open an external client session with the JACK
		// server.  The `jack_client_open' function is defined
		// in the jack/jack.h header. With it, clients may
		// choose which of several servers to connect, and
		// control whether and how to start the server
		// automatically, if it was not already running. Its
		// first argument _client_name_ of is at most
		// jack_client_name_size() characters. The name scope
		// is local to each server. Unless forbidden by the
		// JackUseExactName option, the server will modify
		// this name to create a unique variant, if
		// needed. The second argument _options_ is formed by
		// OR-ing together JackOptions bits. Only the
		// JackOpenOptions bits are allowed. _status_ (if
		// non-NULL) is an address for JACK to return
		// information from the open operation. This status
		// word is formed by OR-ing together the relevant
		// JackStatus bits.  Depending on the _status_, an
		// optional argument _server_name_ selects from among
		// several possible concurrent server
		// instances. Server names are unique to each user. It
		// returns an opaque client handle if successful. If
		// this is NULL, the open operation failed, *status
		// includes JackFailure and the caller is not a JACK
		// client.
#ifdef H2CORE_HAVE_JACKSESSION
		if (pPref->getJackSessionUUID().isEmpty()){
			m_pClient = jack_client_open( sClientName.toLocal8Bit(),
						      JackNullOption,
						      &status);
		} else {
			// Unique name of the JACK server used within
			// the JACK session.
			const QByteArray uuid = pPref->getJackSessionUUID().toLocal8Bit();
			// Using the JackSessionID option and the
			// supplied SessionID Token the sessionmanager
			// is able to identify the client again.
			m_pClient = jack_client_open( sClientName.toLocal8Bit(),
						      JackSessionID,
						      &status,
						      uuid.constData());
		}
#else
		m_pClient = jack_client_open( sClientName.toLocal8Bit(),
					      JackNullOption,
					      &status);
#endif
		// Check what did happen during the opening of the
		// client. CLIENT_SUCCESS sets the nTries variable
		// to 0 while CLIENT_FAILURE resets m_pClient to the
		// nullptr.
		switch(status) {
		case JackFailure:
			CLIENT_FAILURE("unknown error");
			break;
		case JackInvalidOption:
			CLIENT_FAILURE("invalid option");
			break;
		case JackNameNotUnique:
			if (m_pClient) {
				sClientName = jack_get_client_name(m_pClient);
				CLIENT_SUCCESS(QString("Jack assigned the client name '%1'").arg(sClientName));
			} else {
				CLIENT_FAILURE("name not unique");
			}
			break;
		case JackServerStarted:
			CLIENT_SUCCESS("JACK Server started for Hydrogen.");
			break;
		case JackServerFailed:
			CLIENT_FAILURE("unable to connect");
			break;
		case JackServerError:
			CLIENT_FAILURE("communication error");
			break;
		case JackNoSuchClient:
			CLIENT_FAILURE("unknown client type");
			break;
		case JackLoadFailure:
			CLIENT_FAILURE("can't load internal client");
			break;
		case JackInitFailure:
			CLIENT_FAILURE("can't initialize client");
			break;
		case JackShmFailure:
			CLIENT_FAILURE("unable to access shared memory");
			break;
		case JackVersionError:
			CLIENT_FAILURE("client/server protocol version mismatch");
			break;
		default:
			if (status) {
				ERRORLOG("Unknown status with JACK server.");
				if (m_pClient) {
					CLIENT_SUCCESS("Client pointer is *not* null..."
						       " assuming we're OK");
				}
			} else {
				CLIENT_SUCCESS("Connected to JACK server");
			}
		}
	}

	if (m_pClient == 0) return -1;

	// Here, client should either be valid, or NULL.
	jack_server_sampleRate = jack_get_sample_rate( m_pClient );
	jack_server_bufferSize = jack_get_buffer_size( m_pClient );

	pPref->m_nSampleRate = jack_server_sampleRate;
	pPref->m_nBufferSize = jack_server_bufferSize;

	/* tell the JACK server to call `process()' whenever
	   there is work to be done.
	*/
	jack_set_process_callback( m_pClient, this->processCallback, 0 );

	/* tell the JACK server to call `srate()' whenever
	   the sample rate of the system changes.
	*/
	jack_set_sample_rate_callback( m_pClient, jackDriverSampleRate, this );

	/* tell JACK server to update us if the buffer size
	   (frames per process cycle) changes.
	*/
	jack_set_buffer_size_callback( m_pClient, jackDriverBufferSize, 0 );

	/* tell the JACK server to call `jack_shutdown()' if
	   it ever shuts down, either entirely, or if it
	   just decides to stop calling us.
	*/
	jack_on_shutdown( m_pClient, jackDriverShutdown, 0 );

	// Create two new ports for Hydrogen's client. These are
	// objects used for moving data of any type in or out of the
	// client. Ports may be connected in various ways. The
	// function `jack_port_register' (jack/jack.h) is called like
	// jack_port_register( jack_client_t *client, 
	//                     const char *port_name,
        //                     const char *port_type,
        //                     unsigned long flags,
        //                     unsigned long buffer_size)
	//
	// All ports have a type, which may be any non-NULL and non-zero
	// length string, passed as an argument. Some port types are built
	// into the JACK API, currently only JACK_DEFAULT_AUDIO_TYPE.
	// It returns a _jack_port_t_ pointer on success, otherwise NULL.
	output_port_1 = jack_port_register( m_pClient, "out_L", JACK_DEFAULT_AUDIO_TYPE,
					    JackPortIsOutput, 0 );
	output_port_2 = jack_port_register( m_pClient, "out_R", JACK_DEFAULT_AUDIO_TYPE,
					    JackPortIsOutput, 0 );

	Hydrogen *pEngine = Hydrogen::get_instance();
	if ( ( output_port_1 == NULL ) || ( output_port_2 == NULL ) ) {
		pEngine->raiseError( Hydrogen::JACK_ERROR_IN_PORT_REGISTER );
		return 4;
	}

#ifdef H2CORE_HAVE_LASH
	if ( pPref->useLash() ){
		LashClient* lashClient = LashClient::get_instance();
		if (lashClient->isConnected()) {
			lashClient->setJackClientName(sClientName.toLocal8Bit().constData());
		}
	}
#endif

#ifdef H2CORE_HAVE_JACKSESSION
	jack_set_session_callback(m_pClient, jack_session_callback, (void*)this);
#endif

	if ( pPref->m_bJackMasterMode == Preferences::USE_JACK_TIME_MASTER ){
		// Make Hydrogen the timebase master, regardless if there
		// is already a timebase master present.
		m_nJackConditionalTakeOver = 0;
		// Make Hydrogen the JACK timebase master.
		initTimeMaster();
	}
	
	return 0;
}
Пример #6
0
// return 0: ok
// return 1: cannot activate client
// return 2: cannot connect output port
int JackAudioDriver::connect()
{
	INFOLOG( "connect" );

	// The `jack_activate' function is defined in the jack/jack.h
	// header files and tells the JACK server that the program is
	// ready to start processing audio. It returns 0 on success
	// and a non-zero error code otherwise.
	if ( jack_activate( m_pClient ) ) {
		Hydrogen::get_instance()->raiseError( Hydrogen::JACK_CANNOT_ACTIVATE_CLIENT );
		return 1;
	}


	bool connect_output_ports = m_bConnectOutFlag;

	memset( track_output_ports_L, 0, sizeof(track_output_ports_L) );
	memset( track_output_ports_R, 0, sizeof(track_output_ports_R) );

#ifdef H2CORE_HAVE_LASH
	if ( Preferences::get_instance()->useLash() ){
		LashClient* lashClient = LashClient::get_instance();
		if (lashClient && lashClient->isConnected()){
			// INFOLOG( "[LASH] Sending JACK client name to LASH server" );
			lashClient->sendJackClientName();

			if (!lashClient->isNewProject()){
				connect_output_ports = false;
			}
		}
	}
#endif

	if ( connect_output_ports ) {
		// Connect the ports.
		// The `jack_connect' function is defined in the
		// jack/jack.h file. It establishes a connection between
		// two ports. When a connection exists, data written
		// to the source port will be available to be read at
		// the destination port. Returns 0 on success, exits
		// if the connection is already made, and returns a
		// non-zero error code otherwise.
		// Syntax: jack_connect( jack_client_t jack_client,
		//                       const char *source_port )
		//                       const char *destination_port
		// )
		// The `jack_port_name' function is also defined in
		// the jack/jack.h header returns the full name of a
		// provided port of type jack_port_t.
		if ( jack_connect( m_pClient, jack_port_name( output_port_1 ),
				   output_port_name_1.toLocal8Bit() ) == 0 &&
		     jack_connect( m_pClient, jack_port_name( output_port_2 ),
				   output_port_name_2.toLocal8Bit() ) == 0 ) {
			return 0;
		}

		INFOLOG( "Could not connect to the saved output ports. Connect to the first pair of input ports instead." );
		// The `jack_get_ports' is defined in the jack/jack.h
		// header file and performs a lookup of ports of the
		// JACK server based on their e.g. flags. It returns a
		// NULL-terminated array of ports that match the
		// specified arguments. The caller is responsible for
		// calling jack_free() any non-NULL returned
		// value.
		const char ** portnames = jack_get_ports( m_pClient, NULL, NULL, JackPortIsInput );
		if ( !portnames || !portnames[0] || !portnames[1] ) {
			ERRORLOG( "Couldn't locate two Jack input ports" );
			Hydrogen::get_instance()->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
			return 2;
		}
		if ( jack_connect( m_pClient, jack_port_name( output_port_1 ),
				   portnames[0] ) != 0 ||
		     jack_connect( m_pClient, jack_port_name( output_port_2 ),
				   portnames[1] ) != 0 ) {
			ERRORLOG( "Couldn't connect to first pair of Jack input ports" );
			Hydrogen::get_instance()->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
			return 2;
		}
		free( portnames );
	}

	return 0;
}
Пример #7
0
int main(int argc, char *argv[])
{
	try {
		// Options...
		char *cp;
		struct option *op;
		char opts[NELEM(long_opts) * 3 + 1];

		// Build up the short option QString
		cp = opts;
		for (op = long_opts; op < &long_opts[NELEM(long_opts)]; op++) {
			*cp++ = op->val;
			if (op->has_arg)
				*cp++ = ':';
			if (op->has_arg == optional_argument )
				*cp++ = ':';  // gets another one
		}

		// Deal with the options
		QString songFilename;
		QString playlistFilename;
		QString outFilename = NULL;
		QString sSelectedDriver;
		bool showVersionOpt = false;
		const char* logLevelOpt = "Error";
		bool showHelpOpt = false;
		QString drumkitName;
		QString drumkitToLoad;
		short bits = 16;
		int rate = 44100;
		short interpolation = 0;
#ifdef H2CORE_HAVE_JACKSESSION
		QString sessionId;
#endif
		int c;
		while ( 1 ) {
			c = getopt_long(argc, argv, opts, long_opts, NULL);
			if ( c == -1 ) break;

			switch(c) {
			case 'd':
				sSelectedDriver = QString::fromLocal8Bit(optarg);
				break;
			case 's':
				songFilename = QString::fromLocal8Bit(optarg);
				break;
			case 'p':
				playlistFilename = QString::fromLocal8Bit(optarg);
				break;
			case 'o':
				outFilename = QString::fromLocal8Bit(optarg);
				break;
			case 'i':
				//install h2drumkit
				drumkitName = QString::fromLocal8Bit(optarg);
				break;
			case 'k':
				//load Drumkit
				drumkitToLoad = QString::fromLocal8Bit(optarg);
				break;
			case 'r':
				rate = strtol(optarg, NULL, 10);
				break;
			case 'b':
				bits = strtol(optarg, NULL, 10);
				break;
			case 'v':
				showVersionOpt = true;
				break;
			case 'V':
				logLevelOpt = (optarg) ? optarg : "Warning";
				break;
#ifdef H2CORE_HAVE_JACKSESSION
			case 'S':
				sessionId = QString::fromLocal8Bit(optarg);
				break;
#endif
			case 'h':
			case '?':
				showHelpOpt = true;
				break;
			}
		}

		if ( showVersionOpt ) {
			cout << get_version() << endl;
			exit(0);
		}

		showInfo();
		if ( showHelpOpt ) {
			showUsage();
			exit(0);
		}

		// Man your battle stations... this is not a drill.
		Logger* logger = Logger::bootstrap( Logger::parse_log_level( logLevelOpt ) );
		Object::bootstrap( logger, logger->should_log( Logger::Debug ) );
		Filesystem::bootstrap( logger );
		MidiMap::create_instance();
		Preferences::create_instance();
		Preferences* preferences = Preferences::get_instance();
		// See below for Hydrogen.

		___INFOLOG( QString("Using QT version ") + QString( qVersion() ) );
		___INFOLOG( "Using data path: " + Filesystem::sys_data_path() );

#ifdef H2CORE_HAVE_LASH
		LashClient::create_instance("hydrogen", "Hydrogen", &argc, &argv);
		LashClient* lashClient = LashClient::get_instance();
#endif

		if ( ! drumkitName.isEmpty() ){
			Drumkit::install( drumkitName );
			exit(0);
		}

		if (sSelectedDriver == "auto") {
			preferences->m_sAudioDriver = "Auto";
		}
		else if (sSelectedDriver == "jack") {
			preferences->m_sAudioDriver = "Jack";
		}
		else if ( sSelectedDriver == "oss" ) {
			preferences->m_sAudioDriver = "Oss";
		}
		else if ( sSelectedDriver == "alsa" ) {
			preferences->m_sAudioDriver = "Alsa";
		}
		else if (sSelectedDriver == "CoreAudio") {
			preferences->m_sAudioDriver = "CoreAudio";
		}
		else if (sSelectedDriver == "PulseAudio") {
			preferences->m_sAudioDriver = "PulseAudio";
		}

#ifdef H2CORE_HAVE_LASH
		if ( preferences->useLash() && lashClient->isConnected() ) {
			lash_event_t* lash_event = lashClient->getNextEvent();
			if (lash_event && lash_event_get_type(lash_event) == LASH_Restore_File) {
				// notify client that this project was not a new one
				lashClient->setNewProject(false);

				songFilename = "";
				songFilename.append( QString::fromLocal8Bit(lash_event_get_string(lash_event)) );
				songFilename.append("/hydrogen.h2song");

				//Logger::get_instance()->log("[LASH] Restore file: " + songFilename);

				lash_event_destroy(lash_event);
			} else if (lash_event) {
				//Logger::get_instance()->log("[LASH] ERROR: Instead of restore file got event: " + lash_event_get_type(lash_event));
				lash_event_destroy(lash_event);
			}
		}
#endif
#ifdef H2CORE_HAVE_JACKSESSION
		if (!sessionId.isEmpty()) {
			preferences->setJackSessionUUID ( sessionId );
			/* imo, jack sessions use jack as default audio driver.
			 * hydrogen remember last used audiodriver.
			 * here we make it save that hydrogen start in a jacksession case
			 * every time with jack as audio driver
			 */
			preferences->m_sAudioDriver = "Jack";

		}
		/* the use of applicationFilePath() make it
		 * possible to use different executables.
		 * for example if you start hydrogen from a local
		 * build directory.
		 */
//		QString path = pQApp->applicationFilePath();
//		preferences->setJackSessionApplicationPath ( path );
#endif
		Hydrogen::create_instance();
		Hydrogen *pHydrogen = Hydrogen::get_instance();
		Song *pSong = NULL;
		Playlist *pPlaylist = NULL;

		// Load playlist
		if ( ! playlistFilename.isEmpty() ) {
			pPlaylist = Playlist::load ( playlistFilename );
			if ( ! pPlaylist ) {
				___ERRORLOG( "Error loading the playlist" );
				return 0;
			}

			/* Load first song */
			preferences->setLastPlaylistFilename( playlistFilename );
			pPlaylist->loadSong( 0 );
			pSong = pHydrogen->getSong();
			show_playlist ( pHydrogen, pPlaylist->getActiveSongNumber() );
		}

		// Load song - if wasn't already loaded with playlist
		if ( ! pSong ) {
			if ( !songFilename.isEmpty() ) {
				pSong = Song::load( songFilename );
			} else {
				/* Try load last song */
				bool restoreLastSong = preferences->isRestoreLastSongEnabled();
				QString filename = preferences->getLastSongFilename();
				if ( restoreLastSong && ( !filename.isEmpty() ))
					pSong = Song::load( filename );
			}

			/* Still not loaded */
			if (! pSong) {
				___INFOLOG("Starting with empty song");
				pSong = Song::get_empty_song();
				pSong->set_filename( "" );
			}

			pHydrogen->setSong( pSong );
			preferences->setLastSongFilename( songFilename );
		}

		if ( ! drumkitToLoad.isEmpty() ){
			Drumkit* drumkitInfo = Drumkit::load_by_name( drumkitToLoad, true );
			if ( drumkitInfo ) {
				pHydrogen->loadDrumkit( drumkitInfo );
			} else {
				___ERRORLOG ( "Error loading the drumkit" );
			}
		}

		AudioEngine* AudioEngine = AudioEngine::get_instance();
		Sampler* sampler = AudioEngine->get_sampler();
		switch ( interpolation ) {
			case 1:
					sampler->setInterpolateMode( Sampler::COSINE );
					break;
			case 2:
					sampler->setInterpolateMode( Sampler::THIRD );
					break;
			case 3:
					sampler->setInterpolateMode( Sampler::CUBIC );
					break;
			case 4:
					sampler->setInterpolateMode( Sampler::HERMITE );
					break;
			case 0:
			default:
					sampler->setInterpolateMode( Sampler::LINEAR );
		}

		EventQueue *pQueue = EventQueue::get_instance();

		signal(SIGINT, signal_handler);

		bool ExportMode = false;
		if ( ! outFilename.isEmpty() ) {
			pHydrogen->startExportSong ( outFilename, rate, bits );
			cout << "Export Progress ... ";
			bool ExportMode = true;
		}

		// Interactive mode
		while ( ! quit ) {
			/* FIXME: Someday here will be The Real CLI ;-) */
			Event event = pQueue->pop_event();
			// if ( event.type > 0) cout << "EVENT TYPE: " << event.type << endl;

			/* Event handler */
			switch ( event.type ) {
			case EVENT_PROGRESS: /* event used only in export mode */
				if ( ! ExportMode ) break;
	
				if ( event.value < 100 ) {
					cout << "\rExport Progress ... " << event.value << "%";
				} else {
					cout << "\rExport Progress ... DONE" << endl;
					quit = true;
				}
				break;
			case EVENT_PLAYLIST_LOADSONG: /* Load new song on MIDI event */
				if ( pPlaylist->loadSong ( event.value ) ) {
					pSong = pHydrogen->getSong();
					show_playlist ( pHydrogen, pPlaylist->getActiveSongNumber() );
				}
				break;
			case EVENT_NONE: /* Sleep if there is no more events */
				Sleeper::msleep ( 100 );
				break;
			}
		}

		if ( pHydrogen->getState() == STATE_PLAYING )
			pHydrogen->sequencer_stop();

		delete pSong;
		delete pPlaylist;

		delete pQueue;
		delete pHydrogen;
		delete preferences;
		delete AudioEngine;

		delete MidiMap::get_instance();
		delete MidiActionManager::get_instance();

		___INFOLOG( "Quitting..." );
		delete Logger::get_instance();

		int nObj = Object::objects_count();
		if (nObj != 0) {
			cerr << "\n\n\n " << nObj << " alive objects\n\n" << endl << endl;
			Object::write_objects_map_to_cerr();
		}
	}
	catch ( const H2Exception& ex ) {
		cerr << "[main] Exception: " << ex.what() << endl;
	}
	catch (...) {
		cerr << "[main] Unknown exception X-(" << endl;
	}

	return 0;
}
Пример #8
0
int main(int argc, char *argv[])
{
	try {
		// Options...
		char *cp;
		struct option *op;
		char opts[NELEM(long_opts) * 3 + 1];

		// Build up the short option QString
		cp = opts;
		for (op = long_opts; op < &long_opts[NELEM(long_opts)]; op++) {
			*cp++ = op->val;
			if (op->has_arg)
				*cp++ = ':';
			if (op->has_arg == optional_argument )
				*cp++ = ':';  // gets another one
		}

		QApplication* pQApp = new QApplication(argc, argv);

		// Deal with the options
		QString songFilename;
#ifdef H2CORE_HAVE_JACKSESSION
		QString sessionId;
#endif
		QString playlistFilename;
		bool bNoSplash = false;
		QString sys_data_path;
		QString sSelectedDriver;
		bool showVersionOpt = false;
		unsigned logLevelOpt = H2Core::Logger::Error;
		QString drumkitName;
		QString drumkitToLoad;
		bool showHelpOpt = false;

		int c;
		for (;;) {
			c = getopt_long(argc, argv, opts, long_opts, NULL);
			if (c == -1)
				break;

			switch(c) {
			case 'P':
				sys_data_path = QString::fromLocal8Bit(optarg);
				break;

				case 'd':
					sSelectedDriver = QString::fromLocal8Bit(optarg);
					break;

				case 's':
					songFilename = QString::fromLocal8Bit(optarg);
					break;
#ifdef H2CORE_HAVE_JACKSESSION
			case 'S':
				sessionId = QString::fromLocal8Bit(optarg);
				break;
#endif

				case 'p':
					playlistFilename = QString::fromLocal8Bit(optarg);
					break;

				case 'k':
					//load Drumkit
					drumkitToLoad = QString::fromLocal8Bit(optarg);
					break;

				case 'v':
					showVersionOpt = true;
					break;

				case 'i':
					//install h2drumkit
					drumkitName = QString::fromLocal8Bit( optarg );
					break;

				case 'V':
					if( optarg ) {
						logLevelOpt = H2Core::Logger::parse_log_level( optarg );
					} else {
						logLevelOpt = H2Core::Logger::Error|H2Core::Logger::Warning;
					}
					break;
				case 'n':
					bNoSplash = true;
					break;

				case 'h':
				case '?':
					showHelpOpt = true;
					break;
			}
		}

		setup_unix_signal_handlers();

		if( showVersionOpt ) {
			std::cout << H2Core::get_version() << std::endl;
			exit(0);
		}
		showInfo();
		if( showHelpOpt ) {
			showUsage();
			exit(0);
		}

		// Man your battle stations... this is not a drill.
		H2Core::Logger::create_instance();
		H2Core::Logger::set_bit_mask( logLevelOpt );
		H2Core::Logger* logger = H2Core::Logger::get_instance();
		H2Core::Object::bootstrap( logger, logger->should_log(H2Core::Logger::Debug) );
		if(sys_data_path.length()==0 ) {
			H2Core::Filesystem::bootstrap( logger );
		} else {
			H2Core::Filesystem::bootstrap( logger, sys_data_path );
		}
		MidiMap::create_instance();
		H2Core::Preferences::create_instance();
		// See below for H2Core::Hydrogen.


		___INFOLOG( QString("Using QT version ") + QString( qVersion() ) );
		___INFOLOG( "Using data path: " + H2Core::Filesystem::sys_data_path() );

		H2Core::Preferences *pPref = H2Core::Preferences::get_instance();
		pPref->setH2ProcessName( QString(argv[0]) );

#ifdef H2CORE_HAVE_LASH

		LashClient::create_instance("hydrogen", "Hydrogen", &argc, &argv);
		LashClient* lashClient = LashClient::get_instance();

#endif
		if( ! drumkitName.isEmpty() ){
			H2Core::Drumkit::install( drumkitName );
			exit(0);
		}
		
		if (sSelectedDriver == "auto") {
			pPref->m_sAudioDriver = "Auto";
		}
		else if (sSelectedDriver == "jack") {
			pPref->m_sAudioDriver = "Jack";
		}
		else if ( sSelectedDriver == "oss" ) {
			pPref->m_sAudioDriver = "Oss";
		}
		else if ( sSelectedDriver == "alsa" ) {
			pPref->m_sAudioDriver = "Alsa";
		}

		QString family = pPref->getApplicationFontFamily();
		pQApp->setFont( QFont( family, pPref->getApplicationFontPointSize() ) );

		QTranslator qttor( 0 );
		QTranslator tor( 0 );
		QString sTranslationFile = QString("hydrogen.") + QLocale::system().name();
		QString sLocale = QLocale::system().name();
		if ( sLocale != "C") {
			if (qttor.load( QString( "qt_" ) + sLocale,
				QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
				pQApp->installTranslator( &qttor );
			else
				___INFOLOG( QString("Warning: No Qt translation for locale %1 found.").arg(QLocale::system().name()));


			QString sTranslationPath = "data/i18n";
			QString total = sTranslationPath + "/" + sTranslationFile + ".qm";

			bool bTransOk = tor.load( total, "." );
			if ( bTransOk ) {
				___INFOLOG( QString( "Using locale: %1/%2" ).arg( sTranslationPath ).arg( sTranslationFile ) );
			}
			else {
				sTranslationPath = H2Core::Filesystem::i18n_dir();
				total = sTranslationPath + "/" + sTranslationFile + ".qm";
				bTransOk = tor.load( total, "." );
				if (bTransOk) {
					___INFOLOG( "Using locale: " + sTranslationPath + "/" + sTranslationFile );
				}
				else {
					___INFOLOG( "Warning: no locale found: " + sTranslationPath + "/" + sTranslationFile );
				}
			}
			if (tor.isEmpty()) {
				___INFOLOG( "Warning: error loading locale: " +  total );
			}
		}
		pQApp->installTranslator( &tor );

		QString sStyle = pPref->getQTStyle();
		if ( !sStyle.isEmpty() ) {
			pQApp->setStyle( sStyle );
		}

		setPalette( pQApp );

		SplashScreen *pSplash = new SplashScreen();

		if (bNoSplash) {
			pSplash->hide();
		}
		else {
			pSplash->show();
		}

#ifdef H2CORE_HAVE_LASH
		if ( H2Core::Preferences::get_instance()->useLash() ){
			if (lashClient->isConnected())
			{
				lash_event_t* lash_event = lashClient->getNextEvent();
				if (lash_event && lash_event_get_type(lash_event) == LASH_Restore_File)
				{
					// notify client that this project was not a new one
					lashClient->setNewProject(false);

					songFilename = "";
					songFilename.append( QString::fromLocal8Bit(lash_event_get_string(lash_event)) );
					songFilename.append("/hydrogen.h2song");

					//        				H2Core::Logger::get_instance()->log("[LASH] Restore file: " + songFilename);

					lash_event_destroy(lash_event);
				}
				else if (lash_event)
				{
					//        				H2Core::Logger::get_instance()->log("[LASH] ERROR: Instead of restore file got event: " + lash_event_get_type(lash_event));
					lash_event_destroy(lash_event);
				}
			}
		}
#endif

#ifdef H2CORE_HAVE_JACKSESSION
		if(!sessionId.isEmpty()){
			pPref->setJackSessionUUID( sessionId );

			/*
					 * imo, jack sessions use jack as default audio driver.
					 * hydrogen remember last used audiodriver.
					 * here we make it save that hydrogen start in a jacksession case
					 * every time with jack as audio driver
					 */
			pPref->m_sAudioDriver = "Jack";

		}

		/*
		 * the use of applicationFilePath() make it
		 * possible to use different executables.
		* for example if you start hydrogen from a local
		* build directory.
		*/

		QString path = pQApp->applicationFilePath();
		pPref->setJackSessionApplicationPath( path );
#endif

		// Hydrogen here to honor all preferences.
		H2Core::Hydrogen::create_instance();

#ifdef H2CORE_HAVE_NSMSESSION
		H2Core::Hydrogen::get_instance()->startNsmClient();
		songFilename = pPref->getNsmSongName();
#endif

		MainForm *pMainForm = new MainForm( pQApp, songFilename );
		pMainForm->show();
		pSplash->finish( pMainForm );

		if( ! playlistFilename.isEmpty() ){
			bool loadlist = HydrogenApp::get_instance()->getPlayListDialog()->loadListByFileName( playlistFilename );
			if ( loadlist ){
				Playlist::get_instance()->setNextSongByNumber( 0 );
			} else {
				___ERRORLOG ( "Error loading the playlist" );
			}
		}

		if( ! drumkitToLoad.isEmpty() ) {
			H2Core::Drumkit* drumkitInfo = H2Core::Drumkit::load_by_name( drumkitToLoad, true );
			if ( drumkitInfo ) {
				H2Core::Hydrogen::get_instance()->loadDrumkit( drumkitInfo );
				HydrogenApp::get_instance()->onDrumkitLoad( drumkitInfo->get_name() );
			} else {
				___ERRORLOG ( "Error loading the drumkit" );
			}
		}

		pQApp->exec();

		delete pSplash;
		delete pMainForm;
		delete pQApp;
		delete pPref;
		delete H2Core::EventQueue::get_instance();
		delete H2Core::AudioEngine::get_instance();

		delete MidiMap::get_instance();
		delete MidiActionManager::get_instance();

		___INFOLOG( "Quitting..." );
		cout << "\nBye..." << endl;
		delete H2Core::Logger::get_instance();

		if (H2Core::Object::count_active()) {
			H2Core::Object::write_objects_map_to_cerr();
		}

	}
	catch ( const H2Core::H2Exception& ex ) {
		std::cerr << "[main] Exception: " << ex.what() << std::endl;
	}
	catch (...) {
		std::cerr << "[main] Unknown exception X-(" << std::endl;
	}

	return 0;
}