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