// -*- c-indentation-style:"stroustrup" c-basic-offset: 4 -*- /* Rosegarden A sequencer and musical notation editor. This program is Copyright 2000-2008 Guillaume Laurent , Chris Cannam , Richard Bown The moral right of the authors to claim authorship of this work has been asserted. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include "RosegardenSequencerApp.h" #include #include #include #include #include #include #include #include #include "base/Profiler.h" #include "sound/MappedComposition.h" #include "gui/application/RosegardenDCOP.h" #include "misc/Debug.h" using std::cout; using std::cerr; using std::endl; using namespace Rosegarden; static const char *description = I18N_NOOP("RosegardenSequencer"); static RosegardenSequencerApp *roseSeq = 0; static KCmdLineOptions options[] = { // { "+[File]", I18N_NOOP("file to open"), 0 }, // INSERT YOUR COMMANDLINE OPTIONS HERE { "+[playback_1 playback_2 capture_1 capture_2]", I18N_NOOP("JACK playback and capture ports"), 0 }, { 0, 0, 0 } }; static bool _exiting = false; static sigset_t _signals; static void signalHandler(int /*sig*/) { _exiting = true; std::cerr << "Is that the time!?" << endl; } int main(int argc, char *argv[]) { srandom((unsigned int)time(0) * (unsigned int)getpid()); // Block signals during startup, so that child threads (inheriting // this tqmask) ignore them; then after startup we can unblock them // for this thread only. This trick picked up from the jackd code. sigemptyset (&_signals); sigaddset(&_signals, SIGHUP); sigaddset(&_signals, SIGINT); sigaddset(&_signals, SIGQUIT); sigaddset(&_signals, SIGPIPE); sigaddset(&_signals, SIGTERM); sigaddset(&_signals, SIGUSR1); sigaddset(&_signals, SIGUSR2); pthread_sigmask(SIG_BLOCK, &_signals, 0); KAboutData aboutData( "rosegardensequencer", I18N_NOOP("RosegardenSequencer"), VERSION, description, KAboutData::License_GPL, "(c) 2000-2008, Guillaume Laurent, Chris Cannam, Richard Bown"); aboutData.addAuthor("Guillaume Laurent, Chris Cannam, Richard Bown", 0, "glaurent@telegraph-road.org, cannam@all-day-breakfast.com, bownie@bownie.com"); KCmdLineArgs::init( argc, argv, &aboutData ); KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. // Parse cmd line args // /*KCmdLineArgs *args =*/ KCmdLineArgs::parsedArgs(); KApplication app; if (app.isRestored()) { SEQUENCER_DEBUG << "RosegardenSequencer - we're being session-restored - that's not supposed to happen\n"; app.quit(); // don't do session restore -- GUI will start a sequencer } else { roseSeq = new RosegardenSequencerApp; } TQObject::connect(&app, TQT_SIGNAL(lastWindowClosed()), &app, TQT_SLOT(quit())); app.disableSessionManagement(); // we don't want to be // saved/restored by session // management, only run by the GUI // Started OK // SEQUENCER_DEBUG << "RosegardenSequencer - started OK" << endl; // Register signal handlers and unblock signals // signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); signal(SIGHUP, signalHandler); signal(SIGQUIT, signalHandler); pthread_sigmask(SIG_UNBLOCK, &_signals, 0); // Now we can enter our specialised event loop. // For each pass through we wait for some pending // events. We check status on the way through and // act accordingly. DCOP events fire back and // forth processed in the event loop changing // state and hopefully controlling and providing // feedback. We also put in some sleep time to // make sure the loop doesn't eat up all the // processor - we're not in that much of a rush! // TransporttqStatus lastSeqtqStatus = roseSeq->gettqStatus(); RealTime sleepTime = RealTime(0, 10000000); while (!_exiting && roseSeq && roseSeq->gettqStatus() != TQUIT) { bool atLeisure = true; switch (roseSeq->gettqStatus()) { case STARTING_TO_PLAY: if (!roseSeq->startPlaying()) { // send result failed and stop Sequencer roseSeq->settqStatus(STOPPING); } else { roseSeq->settqStatus(PLAYING); } break; case PLAYING: if (!roseSeq->keepPlaying()) { // there's a problem or the piece has // finished - so stop playing roseSeq->settqStatus(STOPPING); } else { // process any async events // roseSeq->processAsynchronousEvents(); } break; case STARTING_TO_RECORD: if (!roseSeq->startPlaying()) { roseSeq->settqStatus(STOPPING); } else { roseSeq->settqStatus(RECORDING); } break; case RECORDING: if (!roseSeq->keepPlaying()) { // there's a problem or the piece has // finished - so stop playing roseSeq->settqStatus(STOPPING); } else { // Now process any incoming MIDI events // and return them to the gui // roseSeq->processRecordedMidi(); // Now process any incoming audio // and return it to the gui // roseSeq->processRecordedAudio(); // Still process these so we can send up // audio levels as MappedEvents // roseSeq->processAsynchronousEvents(); } break; case STOPPING: // There's no call to roseSeq to actually process the // stop, because this arises from a DCOP call from the GUI // direct to roseSeq to start with roseSeq->settqStatus(STOPPED); SEQUENCER_DEBUG << "RosegardenSequencer - Stopped" << endl; break; case RECORDING_ARMED: SEQUENCER_DEBUG << "RosegardenSequencer - " << "Sequencer can't enter \"" << "RECORDING_ARMED\" state - " << "internal error" << endl; break; case STOPPED: default: roseSeq->processAsynchronousEvents(); break; } // Update internal clock and send pointer position // change event to GUI - this is the heartbeat of // the Sequencer - it doesn't tick over without // this call. // // Also attempt to send the MIDI clock at this point. // roseSeq->updateClocks(); // we want to process transport changes immediately if (roseSeq->checkExternalTransport()) { atLeisure = false; } else if (lastSeqtqStatus != roseSeq->gettqStatus()) { SEQUENCER_DEBUG << "Sequencer status changed from " << lastSeqtqStatus << " to " << roseSeq->gettqStatus() << endl; roseSeq->notifySequencertqStatus(); lastSeqtqStatus = roseSeq->gettqStatus(); atLeisure = false; } app.processEvents(); if (atLeisure) roseSeq->sleep(sleepTime); } delete roseSeq; std::cerr << "Toodle-pip." << endl; return 0; }