summaryrefslogtreecommitdiffstats
path: root/src/sequencer/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sequencer/main.cpp')
-rw-r--r--src/sequencer/main.cpp246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/sequencer/main.cpp b/src/sequencer/main.cpp
new file mode 100644
index 0000000..aee5bc5
--- /dev/null
+++ b/src/sequencer/main.cpp
@@ -0,0 +1,246 @@
+// -*- c-indentation-style:"stroustrup" c-basic-offset: 4 -*-
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <glaurent@telegraph-road.org>,
+ Chris Cannam <cannam@all-day-breakfast.com>,
+ Richard Bown <bownie@bownie.com>
+
+ 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 <signal.h>
+#include <iostream>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <dcopclient.h>
+
+#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 mask) 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;
+ }
+
+ QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, 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!
+ //
+ TransportStatus lastSeqStatus = roseSeq->getStatus();
+
+ RealTime sleepTime = RealTime(0, 10000000);
+
+ while (!_exiting && roseSeq && roseSeq->getStatus() != QUIT) {
+
+ bool atLeisure = true;
+
+ switch (roseSeq->getStatus()) {
+ case STARTING_TO_PLAY:
+ if (!roseSeq->startPlaying()) {
+ // send result failed and stop Sequencer
+ roseSeq->setStatus(STOPPING);
+ } else {
+ roseSeq->setStatus(PLAYING);
+ }
+ break;
+
+ case PLAYING:
+ if (!roseSeq->keepPlaying()) {
+ // there's a problem or the piece has
+ // finished - so stop playing
+ roseSeq->setStatus(STOPPING);
+ } else {
+ // process any async events
+ //
+ roseSeq->processAsynchronousEvents();
+ }
+ break;
+
+ case STARTING_TO_RECORD:
+ if (!roseSeq->startPlaying()) {
+ roseSeq->setStatus(STOPPING);
+ } else {
+ roseSeq->setStatus(RECORDING);
+ }
+ break;
+
+ case RECORDING:
+ if (!roseSeq->keepPlaying()) {
+ // there's a problem or the piece has
+ // finished - so stop playing
+ roseSeq->setStatus(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->setStatus(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 (lastSeqStatus != roseSeq->getStatus()) {
+ SEQUENCER_DEBUG << "Sequencer status changed from " << lastSeqStatus << " to " << roseSeq->getStatus() << endl;
+ roseSeq->notifySequencerStatus();
+ lastSeqStatus = roseSeq->getStatus();
+ atLeisure = false;
+ }
+
+ app.processEvents();
+ if (atLeisure)
+ roseSeq->sleep(sleepTime);
+ }
+
+ delete roseSeq;
+
+ std::cerr << "Toodle-pip." << endl;
+ return 0;
+}
+