// 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; }
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" ); } } }
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 }
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; }
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; }
// 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; }
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; }
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; }