1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 #define RG_MODULE_STRING "[SequenceManager]"
19 
20 #define RG_NO_DEBUG_PRINT 1
21 
22 #include "SequenceManager.h"
23 
24 #include "sound/Midi.h"  // for MIDI_SYSTEM_RESET
25 #include "sound/ControlBlock.h"
26 #include "sound/ExternalController.h"
27 #include "misc/Debug.h"
28 #include "misc/Strings.h"  // for qStrToBool()
29 #include "misc/ConfigGroups.h"
30 #include "base/Composition.h"
31 #include "base/Device.h"
32 #include "base/Exception.h"
33 #include "base/Instrument.h"
34 #include "base/MidiProgram.h"  // for MidiFilter
35 #include "base/RealTime.h"
36 #include "base/Segment.h"
37 #include "base/Studio.h"
38 #include "base/Track.h"
39 #include "base/TriggerSegment.h"
40 #include "CompositionMapper.h"
41 #include "document/RosegardenDocument.h"
42 #include "document/CommandHistory.h"
43 #include "gui/dialogs/AudioManagerDialog.h"
44 #include "gui/dialogs/CountdownDialog.h"
45 #include "gui/application/RosegardenMainWindow.h"
46 #include "gui/widgets/StartupLogo.h"
47 #include "gui/studio/StudioControl.h"
48 #include "gui/widgets/WarningWidget.h"
49 #include "sequencer/RosegardenSequencer.h"
50 #include "MarkerMapper.h"
51 #include "MetronomeMapper.h"
52 #include "TempoSegmentMapper.h"
53 #include "TimeSigSegmentMapper.h"
54 #include "sound/AudioFile.h"  // For AudioFileId
55 #include "sound/MappedEventList.h"
56 #include "sound/MappedEvent.h"
57 #include "sound/MappedInstrument.h"
58 
59 #include "rosegarden-version.h"  // for VERSION
60 
61 #include <QSettings>
62 #include <QMessageBox>
63 #include <QApplication>
64 #include <QCursor>
65 #include <QEvent>
66 #include <QString>
67 #include <QTimer>
68 #include <QElapsedTimer>
69 
70 #include <utility>  // For std::pair.
71 
72 namespace Rosegarden
73 {
74 
SequenceManager()75 SequenceManager::SequenceManager() :
76     m_doc(nullptr),
77     m_soundDriverStatus(NO_DRIVER),
78     m_compositionMapper(),
79     m_metronomeMapper(nullptr),
80     m_tempoSegmentMapper(nullptr),
81     m_timeSigSegmentMapper(nullptr),
82     m_refreshRequested(true),
83     m_segments(),
84     m_triggerSegments(),
85     m_addedSegments(),
86     m_removedSegments(),
87     m_shownOverrunWarning(false),
88     m_reportTimer(nullptr),
89     m_canReport(true),
90     m_transportStatus(STOPPED),
91     m_lastRewoundAt(clock()),
92     m_countdownDialog(nullptr),
93     m_countdownTimer(nullptr),
94     m_recordTime(new QElapsedTimer()),
95     m_lastTransportStartPosition(0),
96     m_realRecordStart(RealTime::zeroTime),
97     m_sampleRate(0),
98     m_tempo(0)
99 {
100 }
101 
~SequenceManager()102 SequenceManager::~SequenceManager()
103 {
104     RG_DEBUG << "dtor...";
105 
106     if (m_doc)
107         m_doc->getComposition().removeObserver(this);
108 }
109 
110 void
setDocument(RosegardenDocument * doc)111 SequenceManager::setDocument(RosegardenDocument *doc)
112 {
113     RG_DEBUG << "setDocument(" << doc << ")";
114 
115     DataBlockRepository::clear();
116 
117     if (m_doc)
118         m_doc->getComposition().removeObserver(this);
119 
120     // Avoid duplicate connections.
121     disconnect(CommandHistory::getInstance(), SIGNAL(commandExecuted()));
122 
123     m_segments.clear();
124     m_triggerSegments.clear();
125 
126     m_doc = doc;
127 
128     m_doc->setSequenceManager(this);
129 
130     // Must recreate and reconnect the countdown timer and dialog
131     // (bug #200 was 729039 "audio recording bug")
132     //
133     delete m_countdownDialog;
134     delete m_countdownTimer;
135 
136     m_countdownDialog = new CountdownDialog(RosegardenMainWindow::self());
137 
138     // Bug #394: playback pointer wonkiness when stopping recording
139     // (was 933041)  No longer connect the CountdownDialog from
140     // SequenceManager; instead let the RosegardenMainWindow connect it to
141     // its own slotStop to ensure the right housekeeping is done
142 
143     m_countdownTimer = new QTimer(m_doc);
144     connect(m_countdownTimer, &QTimer::timeout,
145             this, &SequenceManager::slotCountdownTimerTimeout);
146 
147     m_doc->getComposition().addObserver(this);
148 
149     connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
150             this, SLOT(update()));
151 
152     if (doc->isSoundEnabled()) {
153         resetCompositionMapper();
154         populateCompositionMapper();
155     }
156 }
157 
158 void
play()159 SequenceManager::play()
160 {
161     if (!m_doc)
162         return;
163 
164     Composition &comp = m_doc->getComposition();
165 
166     // If already playing or recording then stop
167     if (m_transportStatus == PLAYING  ||
168         m_transportStatus == RECORDING) {
169         stop();
170         return;
171     }
172 
173     // This check may throw an exception
174     checkSoundDriverStatus(false);
175 
176     // Make sure RosegardenSequencer has the right Instrument objects.
177     preparePlayback();
178 
179     // Remember the last playback position so that we can return on stop.
180     m_lastTransportStartPosition = comp.getPosition();
181 
182     // Update play metronome status
183     ControlBlock::getInstance()->setInstrumentForMetronome(
184             m_metronomeMapper->getMetronomeInstrument());
185     ControlBlock::getInstance()->setMetronomeMuted(!comp.usePlayMetronome());
186 
187     // Depress the play button.
188     emit signalPlaying(true);
189 
190     if (comp.getCurrentTempo() == 0) {
191         RG_DEBUG << "play() - setting Tempo to Default value of 120.000";
192 
193         comp.setCompositionDefaultTempo(comp.getTempoForQpm(120.0));
194     }
195 
196     setTempo(comp.getCurrentTempo());
197 
198     RealTime startPos = comp.getElapsedRealTime(comp.getPosition());
199 
200     // If we're looping then jump to loop start
201     if (comp.isLooping())
202         startPos = comp.getElapsedRealTime(comp.getLoopStart());
203 
204     int result = RosegardenSequencer::getInstance()->play(startPos);
205 
206     // Failed?  Bail.
207     if (!result) {
208         RG_WARNING << "play(): WARNING: Failed to start playback!";
209         m_transportStatus = STOPPED;
210         return;
211     }
212 
213     m_transportStatus = STARTING_TO_PLAY;
214 }
215 
216 void
stop()217 SequenceManager::stop()
218 {
219     if (!m_doc)
220         return;
221 
222     if (m_countdownTimer)
223         m_countdownTimer->stop();
224     if (m_countdownDialog)
225         m_countdownDialog->hide();
226 
227     // If the user presses stop while stopped, return to where we last started.
228     if (m_transportStatus == STOPPED) {
229         m_doc->slotSetPointerPosition(m_lastTransportStartPosition);
230         return;
231     }
232 
233     // If recording hasn't started yet, drop back to STOPPED.
234     if (m_transportStatus == RECORDING_ARMED) {
235         m_transportStatus = STOPPED;
236 
237         emit signalRecording(false);
238         emit signalMetronomeActivated(m_doc->getComposition().usePlayMetronome());
239 
240         return;
241     }
242 
243     RG_DEBUG << "stop() - preparing to stop playback or recording in progress";
244 
245     if (m_transportStatus == RECORDING) {
246         emit signalRecording(false);
247         emit signalMetronomeActivated(m_doc->getComposition().usePlayMetronome());
248     }
249 
250     emit signalPlaying(false);
251 
252     // wait cursor
253     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
254 
255     // "call" the sequencer with a stop so we get a synchronous
256     // response - then we can fiddle about with the audio file
257     // without worrying about the sequencer causing problems
258     // with access to the same audio files.
259     RosegardenSequencer::getInstance()->stop();
260 
261     // restore
262     QApplication::restoreOverrideCursor();
263 
264     TransportStatus previousStatus = m_transportStatus;
265 
266     // set new transport status first, so that if we're stopping
267     // recording we don't risk the record segment being restored by a
268     // timer while the document is busy trying to do away with it
269     m_transportStatus = STOPPED;
270 
271     // if we were recording MIDI or Audio then tidy up the recording Segment
272     if (previousStatus == RECORDING) {
273         m_doc->stopRecordingMidi();
274         m_doc->stopRecordingAudio();
275 
276         RG_DEBUG << "stop() - stopped recording";
277     } else {
278         m_doc->stopPlaying();
279     }
280 
281     // always untoggle the play button at this stage
282     emit signalPlaying(false);
283 
284     RG_DEBUG << "stop() - stopped playing";
285 
286     m_shownOverrunWarning = false;
287 }
288 
289 void
rewind()290 SequenceManager::rewind()
291 {
292     if (!m_doc)
293         return;
294 
295     Composition &composition = m_doc->getComposition();
296 
297     timeT position = composition.getPosition();
298 
299     // Subtract one from position to make sure we go back one bar if we
300     // are stopped and sitting at the beginning of a bar.
301     std::pair<timeT, timeT> barRange =
302         composition.getBarRangeForTime(position - 1);
303 
304     if (m_transportStatus == PLAYING) {
305         // Compute elapsed time since last rewind press.
306         clock_t now = clock();
307         int elapsed = (now - m_lastRewoundAt) * 1000 / CLOCKS_PER_SEC;
308 
309         //RG_DEBUG << "rewind(): That was " << m_lastRewoundAt << ", this is " << now << ", elapsed is " << elapsed;
310 
311         // If we had a rewind press less than 200ms ago...
312         if (elapsed >= 0 && elapsed <= 200) {
313 
314             timeT halfway = barRange.first +
315                     (barRange.second - barRange.first) / 2;
316 
317             // If we're less than half way into the bar
318             if (position <= halfway) {
319                 // Rewind an additional bar.
320                 barRange = composition.getBarRangeForTime(barRange.first - 1);
321             }
322         }
323 
324         m_lastRewoundAt = now;
325     }
326 
327     if (barRange.first < composition.getStartMarker()) {
328         m_doc->slotSetPointerPosition(composition.getStartMarker());
329     } else {
330         m_doc->slotSetPointerPosition(barRange.first);
331     }
332 }
333 
334 void
fastforward()335 SequenceManager::fastforward()
336 {
337     if (!m_doc)
338         return;
339 
340     Composition &composition = m_doc->getComposition();
341 
342     timeT position = composition.getPosition();
343     timeT newPosition = composition.getBarEndForTime(position);
344 
345     // Don't skip past end marker.
346     if (newPosition > composition.getEndMarker())
347         newPosition = composition.getEndMarker();
348 
349     m_doc->slotSetPointerPosition(newPosition);
350 }
351 
352 void
jumpTo(const RealTime & time)353 SequenceManager::jumpTo(const RealTime &time)
354 {
355     RosegardenSequencer::getInstance()->jumpTo(time);
356 }
357 
358 void
record(bool toggled)359 SequenceManager::record(bool toggled)
360 {
361     if (!m_doc) return;
362 
363     m_realRecordStart = RealTime::zeroTime;
364 
365     RG_DEBUG << "record(" << toggled << ")";
366     Composition &comp = m_doc->getComposition();
367     Studio &studio = m_doc->getStudio();
368 
369     bool punchIn = false; // are we punching in?
370 
371     // If we have any audio tracks armed, then we need to check for
372     // a valid audio record path and a working audio subsystem before
373     // we go any further
374 
375     const Composition::recordtrackcontainer &recordTracks =
376         comp.getRecordTracks();
377 
378     for (Composition::recordtrackcontainer::const_iterator i =
379                 recordTracks.begin();
380             i != recordTracks.end(); ++i) {
381 
382         Track *track = comp.getTrackById(*i);
383         InstrumentId instrId = track->getInstrument();
384         Instrument *instr = studio.getInstrumentById(instrId);
385 
386         if (instr && instr->getType() == Instrument::Audio) {
387             if (!m_doc || !(m_soundDriverStatus & AUDIO_OK)) {
388                 emit signalRecording(false);
389                 throw(Exception(QObject::tr("Audio subsystem is not available - can't record audio")));
390             }
391             // throws BadAudioPathException if path is not valid:
392             m_doc->getAudioFileManager().testAudioPath();
393             break;
394         }
395     }
396 
397     if (toggled) { // preparing record or punch-in record
398 
399         if (m_transportStatus == RECORDING_ARMED) {
400             RG_DEBUG << "record() - unarming record";
401             m_transportStatus = STOPPED;
402 
403             // Toggle the buttons
404             emit signalMetronomeActivated(comp.usePlayMetronome());
405             emit signalRecording(false);
406 
407             return ;
408         }
409 
410         if (m_transportStatus == STOPPED) {
411             RG_DEBUG << "record() - armed record";
412 
413             // Recording is now armed, but will not start until the countdown
414             // is over.  Then RosegardenMainWindow::slotHandleInputs() will
415             // sync us up to the current sequencer state.  If there is no
416             // countdown, we will likely go directly to RECORDING.
417             // ??? If there is a CountdownDialog, wouldn't we go directly to
418             //     STOPPED due to RMW::slotHandleInputs()?  Or is that off in
419             //     STOPPED?
420             m_transportStatus = RECORDING_ARMED;
421 
422             // Toggle the buttons
423             emit signalMetronomeActivated(comp.useRecordMetronome());
424             emit signalRecording(true);
425 
426             return ;
427         }
428 
429         if (m_transportStatus == RECORDING) {
430             RG_DEBUG << "record() - stop recording and keep playing";
431             if (!RosegardenSequencer::getInstance()->punchOut()) {
432 
433                 // #1797873 - set new transport status first, so that
434                 // if we're stopping recording we don't risk the
435                 // record segment being restored by a timer while the
436                 // document is busy trying to do away with it
437                 m_transportStatus = STOPPED;
438 
439                 m_doc->stopRecordingMidi();
440                 m_doc->stopRecordingAudio();
441                 return ;
442             }
443 
444             // #1797873 - as above
445             m_transportStatus = PLAYING;
446 
447             m_doc->stopRecordingMidi();
448             m_doc->stopRecordingAudio();
449 
450             return ;
451         }
452 
453         if (m_transportStatus == PLAYING) {
454             RG_DEBUG << "record() - punch in recording";
455             punchIn = true;
456             goto punchin;
457         }
458 
459     } else {
460 
461         m_lastTransportStartPosition = comp.getPosition();
462 
463 punchin:
464 
465         // Get the record tracks and check we have a record instrument
466 
467         bool haveInstrument = false;
468         bool haveAudioInstrument = false;
469         bool haveMIDIInstrument = false;
470         //TrackId recordMIDITrack = 0;
471 
472         for (Composition::recordtrackcontainer::const_iterator i =
473                     comp.getRecordTracks().begin();
474                 i != comp.getRecordTracks().end(); ++i) {
475 
476             InstrumentId iid =
477                 comp.getTrackById(*i)->getInstrument();
478 
479             Instrument *inst = studio.getInstrumentById(iid);
480             if (inst) {
481                 haveInstrument = true;
482                 if (inst->getType() == Instrument::Audio) {
483                     haveAudioInstrument = true;
484                     break;
485                 } else { // soft synths count as MIDI for our purposes here
486                     haveMIDIInstrument = true;
487                     //recordMIDITrack = *i;
488                 }
489             }
490         }
491 
492         if (!haveInstrument) {
493             // TRANSLATORS: the pixmap in this error string contains no English
494             // text and is suitable for use by all languages
495             throw(Exception(QObject::tr("<qt><p>No tracks were armed for recording.</p><p>Please arm at least one of the recording LEDs <img src=\":pixmaps/tooltip/record-leds.png\"> and try again</p></qt>")));
496         }
497 
498         // may throw an exception
499         checkSoundDriverStatus(false);
500 
501         // toggle the Metronome button if it's in use
502         emit signalMetronomeActivated(comp.useRecordMetronome());
503 
504         // Update record metronome status
505         //
506         ControlBlock::getInstance()->setInstrumentForMetronome
507             (m_metronomeMapper->getMetronomeInstrument());
508         ControlBlock::getInstance()->setMetronomeMuted(!comp.useRecordMetronome());
509 
510         QSettings settings;
511         settings.beginGroup(GeneralOptionsConfigGroup);
512 
513         // If we are looping then jump to start of loop and start recording,
514         // if we're not take off the number of count-in bars and start
515         // recording.
516         //
517         if (comp.isLooping())
518             m_doc->slotSetPointerPosition(comp.getLoopStart());
519         else {
520             if (m_transportStatus != RECORDING_ARMED && punchIn == false) {
521                 int startBar = comp.getBarNumber(comp.getPosition());
522                 m_realRecordStart = comp.getElapsedRealTime(
523                         comp.getBarRange(startBar).first);
524                 startBar -= settings.value("countinbars", 0).toUInt();
525                 m_doc->slotSetPointerPosition(comp.getBarRange(startBar).first);
526             }
527         }
528 
529         settings.endGroup();
530 
531         m_doc->setRecordStartTime(m_doc->getComposition().getPosition());
532 
533         if (haveAudioInstrument) {
534             // Ask the document to update its record latencies so as to
535             // do latency compensation when we stop
536             m_doc->updateAudioRecordLatency();
537         }
538 
539         if (haveMIDIInstrument) {
540             // For each recording segment...
541             for (Composition::recordtrackcontainer::const_iterator i =
542                         comp.getRecordTracks().begin(); i != comp.getRecordTracks().end(); ++i) {
543                 // Get the Instrument for this Track
544                 InstrumentId iid = comp.getTrackById(*i)->getInstrument();
545                 Instrument *inst = studio.getInstrumentById(iid);
546 
547                 // If this is a MIDI instrument
548                 if (inst && (inst->getType() != Instrument::Audio)) {
549                     RG_DEBUG << "record(): mdoc->addRecordMIDISegment(" << *i << ")";
550                     // Create the record MIDI segment now, so that the
551                     // composition view has a real segment to display.  It
552                     // won't actually be added to the composition until the
553                     // first recorded event arrives.  We don't have to do this
554                     // from here for audio, because for audio the sequencer
555                     // calls back on createRecordAudioFiles so as to find out
556                     // what files it needs to write to.
557                     m_doc->addRecordMIDISegment(*i);
558 
559                     // ??? Why not softsynths too?
560                     if (inst->getType() == Instrument::Midi) {
561                         // Send Program Changes on recording tracks like 11.11.42
562                         // used to.  Fix for bug #1356 "Wrong instrument when
563                         // recording on multiple tracks/channels".  This is a
564                         // simple way to support multiple MIDI controllers.
565                         inst->sendChannelSetup();
566                     }
567                 }
568             }
569         }
570 
571         // set the buttons
572         emit signalRecording(true);
573         emit signalPlaying(true);
574 
575         if (comp.getCurrentTempo() == 0) {
576             RG_DEBUG << "record() - setting Tempo to Default value of 120.000";
577             comp.setCompositionDefaultTempo(comp.getTempoForQpm(120.0));
578         } else {
579             RG_DEBUG << "record() - starting to record";
580         }
581 
582         setTempo(comp.getCurrentTempo());
583 
584         // The arguments for the Sequencer - record is similar to playback,
585         // we must being playing to record.
586         //
587         RealTime startPos =
588             comp.getElapsedRealTime(comp.getPosition());
589 
590         int result = RosegardenSequencer::getInstance()->record(
591                 startPos,
592                 STARTING_TO_RECORD);  // recordMode
593 
594         if (result) {
595 
596             // completed successfully
597             m_transportStatus = STARTING_TO_RECORD;
598 
599             // Create the countdown timer dialog to show recording time
600             // remaining.  (Note (dmm) this has changed, and it now reports
601             // the time remaining during both MIDI and audio recording.)
602             //
603             timeT p = comp.getPosition();
604             timeT d = comp.getEndMarker();
605             // end marker less current position == available duration
606             d -= p;
607 
608             // set seconds to total possible time, initially
609             RealTime rtd = comp.getElapsedRealTime(d);
610             int seconds = rtd.sec;
611 
612             // re-initialise
613             m_countdownDialog->setTotalTime(seconds);
614 
615             // Create the timer
616             //
617             m_recordTime->start();
618 
619             // Start an elapse timer for updating the dialog -
620             // it will fire every second.
621             //
622             m_countdownTimer->start(1000);
623 
624             // Pop-up the dialog (don't use exec())
625             //
626             // bug #941 (old #1505805), abolish recording countdown dialog.
627             // ??? This was removed way back in [r7366] (2006-07-07).  But
628             //     there appears to be renewed interest in feature request
629             //     #453.  Should we clean this up or not?
630             //m_countdownDialog->show();
631 
632         } else {
633             // Stop immediately - turn off buttons in parent
634             //
635             m_transportStatus = STOPPED;
636 
637             if (haveAudioInstrument) {
638                 throw(Exception(QObject::tr("<qt><p>Couldn't start recording audio.</p><p>Please set a valid recording path in <b>Composition -> Edit Document Properties... -> Audio</b></p></qt>")));
639             }
640         }
641     }
642 }
643 
644 void
processAsynchronousMidi(const MappedEventList & mC,AudioManagerDialog * audioManagerDialog)645 SequenceManager::processAsynchronousMidi(const MappedEventList &mC,
646                                          AudioManagerDialog *audioManagerDialog)
647 {
648 #ifdef REPORT_XRUNS
649     static bool boolShowingWarning = false;
650 #endif
651     static bool boolShowingALSAWarning = false;
652     static long warningShownAt = 0;
653 
654     if (m_doc == nullptr || mC.size() == 0)
655         return ;
656 
657     MappedEventList::const_iterator i;
658 
659     // Before applying thru filter, catch program changes and
660     // send them to MIPP.
661 
662     int bankMSB = -1;
663     int bankLSB = -1;
664 
665     // For each event
666     for (i = mC.begin(); i != mC.end(); ++i) {
667 
668         const MappedEvent *event = (*i);
669 
670         // Bank Select
671 
672         // ??? This *requires* that BS and PC come in together.  Is there a
673         //     guarantee that they will come in together?
674 
675         if (event->getType() == MappedEvent::MidiController) {
676             int controlNumber = event->getData1();
677 
678             // If Bank Select LSB
679             if (controlNumber == 32) {
680                 bankLSB = event->getData2();
681             } else if (controlNumber == 0) {  // Bank Select MSB
682                 bankMSB = event->getData2();
683             }
684         }
685 
686         // Program Change
687 
688         if (event->getType() == MappedEvent::MidiProgramChange) {
689             int programChange = event->getData1();
690 
691             // Send to MIPP.  If "Receive external" is checked, the MIPP
692             // will update to show this bank and program.
693             emit sigProgramChange(bankMSB, bankLSB, programChange);
694         }
695 
696     }
697 
698     // send to the MIDI labels (which can only hold one event at a time)
699 
700     i = mC.begin();
701     if (i != mC.end())
702         emit signalMidiInLabel(*i);
703 
704     // Thru filtering is done at the sequencer for the actual sound
705     // output, but here we need both filtered (for OUT display) and
706     // unfiltered (for insertable note callbacks) compositions, so
707     // we've received the unfiltered copy and will filter here
708 
709     MappedEvent::MappedEventType filter = MappedEvent::MappedEventType(
710             m_doc->getStudio().getMIDIThruFilter());
711 
712     // For each event
713     for (MappedEventList::const_iterator it = mC.begin();
714          it != mC.end();
715          ++it) {
716         // Skip events destined for the "external controller" port.
717         if ((*it)->getRecordedDevice() == Device::EXTERNAL_CONTROLLER)
718             continue;
719 
720         // Skip events that are filtered.
721         if (((*it)->getType() & filter) != 0)
722             continue;
723 
724         // Show the event on the TransportDialog's MIDI out label.
725         emit signalMidiOutLabel(*it);
726 
727         // We can only show one at a time.
728         break;
729     }
730 
731     for (i = mC.begin(); i != mC.end(); ++i ) {
732         if ((*i)->getType() >= MappedEvent::Audio) {
733             if ((*i)->getType() == MappedEvent::AudioStopped) {
734                 //RG_DEBUG << "AUDIO FILE ID = " << int((*i)->getData1()) << " - FILE STOPPED - " << "INSTRUMENT = " << (*i)->getInstrument();
735 
736                 if (audioManagerDialog && (*i)->getInstrument() ==
737                         m_doc->getStudio().getAudioPreviewInstrument()) {
738                     audioManagerDialog->
739                     closePlayingDialog(
740                         AudioFileId((*i)->getData1()));
741                 }
742             }
743 
744             if ((*i)->getType() ==
745                     MappedEvent::AudioGeneratePreview) {
746                 RG_DEBUG << "processAsynchronousMidi(): Received AudioGeneratePreview: data1 is "
747                          << int((*i)->getData1()) << ", data2 "
748                          << int((*i)->getData2()) << ", instrument is "
749                          << (*i)->getInstrument();
750                 m_doc->finalizeAudioFile((int)(*i)->getData1() +
751                                          (int)(*i)->getData2() * 256);
752             }
753 
754             if ((*i)->getType() == MappedEvent::SystemUpdateInstruments) {
755 
756                 // resync Devices and Instruments
757                 //
758 //!DEVPUSH                m_doc->syncDevices();
759             }
760 
761             // ??? Error handling appears to start here.  Can we pluck this
762             //     out into a routine?  The indentation walls are closing in
763             //     on us...
764 
765             if (m_transportStatus == PLAYING ||
766                 m_transportStatus == RECORDING) {
767                 if ((*i)->getType() == MappedEvent::SystemFailure) {
768 
769                     RG_DEBUG << "processAsynchronousMidi(): Failure of some sort...";
770 
771                     bool handling = true;
772 
773                     /* These are the ones that we always report or handle. */
774 
775                     if ((*i)->getData1() == MappedEvent::FailureJackDied) {
776 
777                         // Something horrible has happened to JACK or we got
778                         // bumped out of the graph.  Either way stop playback.
779                         //
780                         stop();
781 
782                     } else if ((*i)->getData1() == MappedEvent::FailureJackRestartFailed) {
783 
784                         QMessageBox::critical(
785                             dynamic_cast<QWidget*>(m_doc->parent())->parentWidget(), "",
786                             tr("The JACK Audio subsystem has failed or it has stopped Rosegarden from processing audio.\nPlease restart Rosegarden to continue working with audio.\nQuitting other running applications may improve Rosegarden's performance."));
787 
788                     } else if ((*i)->getData1() == MappedEvent::FailureJackRestart) {
789 
790                         QMessageBox::critical(
791                             dynamic_cast<QWidget*>(m_doc->parent())->parentWidget(), "",
792                             tr("The JACK Audio subsystem has stopped Rosegarden from processing audio, probably because of a processing overload.\nAn attempt to restart the audio service has been made, but some problems may remain.\nQuitting other running applications may improve Rosegarden's performance."));
793 
794                     } else if ((*i)->getData1() == MappedEvent::FailureCPUOverload) {
795 
796 #define REPORT_CPU_OVERLOAD 1
797 #ifdef REPORT_CPU_OVERLOAD
798 
799                         stop();
800 
801                         QMessageBox::critical(
802                             dynamic_cast<QWidget*>(m_doc->parent())->parentWidget(), "",
803                             tr("Out of processor power for real-time audio processing.  Cannot continue."));
804 
805 #endif
806 
807                     } else {
808 
809                         handling = false;
810                     }
811 
812                     if (handling)
813                         continue;
814 
815                     if (!m_canReport) {
816                         RG_DEBUG << "processAsynchronousMidi(): Not reporting it to user just yet";
817                         continue;
818                     }
819 
820                     if ((*i)->getData1() == MappedEvent::FailureALSACallFailed) {
821 
822                         struct timeval tv;
823                         (void)gettimeofday(&tv, nullptr);
824 
825                         if (tv.tv_sec - warningShownAt >= 5 &&
826                                 !boolShowingALSAWarning) {
827 
828                             QString message = tr("A serious error has occurred in the ALSA MIDI subsystem.  It may not be possible to continue sequencing.  Please check console output for more information.");
829                             boolShowingALSAWarning = true;
830 
831                             QMessageBox::information(
832                               nullptr,
833                               "", /* no title */
834                               message,
835                               QMessageBox::Ok,
836                               QMessageBox::Ok);
837                             boolShowingALSAWarning = false;
838 
839                             (void)gettimeofday(&tv, nullptr);
840                             warningShownAt = tv.tv_sec;
841                         }
842 
843                     } else if ((*i)->getData1() == MappedEvent::FailureXRuns) {
844 
845                         //#define REPORT_XRUNS 1
846 #ifdef REPORT_XRUNS
847 
848                         struct timeval tv;
849                         (void)gettimeofday(&tv, 0);
850 
851                         if (tv.tv_sec - warningShownAt >= 5 &&
852                                 !boolShowingWarning) {
853 
854                             QString message = tr("JACK Audio subsystem is losing sample frames.");
855                             boolShowingWarning = true;
856 
857                             QMessageBox::information(0, message);
858                             boolShowingWarning = false;
859 
860                             (void)gettimeofday(&tv, 0);
861                             warningShownAt = tv.tv_sec;
862                         }
863 #endif
864 
865                     } else if (!m_shownOverrunWarning) {
866 
867                         QString message;
868 
869                         switch ((*i)->getData1()) {
870 
871                         case MappedEvent::FailureDiscUnderrun:
872                             message = tr("Failed to read audio data from disk in time to service the audio subsystem.");
873                             break;
874 
875                         case MappedEvent::FailureDiscOverrun:
876                             message = tr("Failed to write audio data to disk fast enough to service the audio subsystem.");
877                             break;
878 
879                         case MappedEvent::FailureBussMixUnderrun:
880                             message = tr("The audio mixing subsystem is failing to keep up.");
881                             break;
882 
883                         case MappedEvent::FailureMixUnderrun:
884                             message = tr("The audio subsystem is failing to keep up.");
885                             break;
886 
887                         default:
888                             message = tr("Unknown sequencer failure mode!");
889                             break;
890                         }
891 
892                         m_shownOverrunWarning = true;
893 
894 #ifdef REPORT_XRUNS
895 
896                         QMessageBox::information(0, message);
897 #else
898 
899                         if ((*i)->getData1() == MappedEvent::FailureDiscOverrun) {
900                             // the error you can't hear
901                             QMessageBox::information(
902                               nullptr,
903                               "", /* no title */
904                               message,
905                               QMessageBox::Ok,
906                               QMessageBox::Ok);
907                         } else {
908                             RG_WARNING << message;
909                         }
910 #endif
911 
912                     }
913 
914                     // Turn off the report flag and set off a one-shot
915                     // timer for 5 seconds.
916                     if (!m_reportTimer->isActive()) {
917                         // ??? This is never set back to true.
918                         m_canReport = false;
919                         // ??? This timer isn't connected to anything.  Looks
920                         //     like it was supposed to be connected to
921                         //     slotAllowReport().
922                         m_reportTimer->setSingleShot(true);
923                         m_reportTimer->start(5000);
924                     }
925                 }
926             } else {
927 //                StartupLogo::hideIfStillThere();
928 
929                 if ((*i)->getType() == MappedEvent::SystemFailure) {
930 
931                     QString text(tr("<h3>System timer resolution is too low!</h3>"));
932                     QString informativeText("");
933 
934                     if ((*i)->getData1() == MappedEvent::FailureJackRestartFailed) {
935 
936                         QMessageBox::critical(
937                             RosegardenMainWindow::self(), "",
938                             tr("The JACK Audio subsystem has failed or it has stopped Rosegarden from processing audio.\nPlease restart Rosegarden to continue working with audio.\nQuitting other running applications may improve Rosegarden's performance."));
939 
940                     } else if ((*i)->getData1() == MappedEvent::FailureJackRestart) {
941                         // !!! Does this attempt to restart the "audio service"
942                         //     EVER work?  I don't think I've ever seen that work.
943                         //     When this is gone, it's gone, and time to restart.
944                         //     But let's not change the translated message.
945                         QMessageBox::critical(
946                             RosegardenMainWindow::self(), "",
947                             tr("The JACK Audio subsystem has stopped Rosegarden from processing audio, probably because of a processing overload.\nAn attempt to restart the audio service has been made, but some problems may remain.\nQuitting other running applications may improve Rosegarden's performance."));
948 
949                     } else if ((*i)->getData1() == MappedEvent::WarningImpreciseTimer &&
950                                shouldWarnForImpreciseTimer()) {
951 
952                         RG_WARNING << "Rosegarden: WARNING: No accurate sequencer timer available";
953 
954 //                        StartupLogo::hideIfStillThere();
955 //
956 //                        RosegardenMainWindow::self()->awaitDialogClearance();
957 
958                         // This is to avoid us ever showing the same
959                         // dialog more than once during a single run
960                         // of the program -- it's quite separate from
961                         // the suppression function
962                         static bool showTimerWarning = true;
963 
964                         if (showTimerWarning) {
965                             informativeText =tr("<p>Rosegarden was unable to find a high-resolution timing source for MIDI performance.</p><p>This may mean you are using a Linux system with the kernel timer resolution set too low.  Please contact your Linux distributor for more information.</p><p>Some Linux distributors already provide low latency kernels, see the <a style=\"color:gold\" href=\"http://www.rosegardenmusic.com/wiki/low-latency_kernels\">Rosegarden website</a> for instructions.</p>");
966 
967                             // whatever, don't show again during this run
968                             showTimerWarning = false;
969                         }
970 
971                     } else if ((*i)->getData1() == MappedEvent::WarningImpreciseTimerTryRTC &&
972                                shouldWarnForImpreciseTimer()) {
973 
974                         RG_WARNING << "Rosegarden: WARNING: No accurate sequencer timer available (and kernel is new enough for RTC addendum)";
975 
976 //                        StartupLogo::hideIfStillThere();
977 //
978 //                        RosegardenMainWindow::self()->awaitDialogClearance();
979 
980                         // This is to avoid us ever showing the same
981                         // dialog more than once during a single run
982                         // of the program -- it's quite separate from
983                         // the suppression function
984                         static bool showAltTimerWarning = true;
985 
986                         if (showAltTimerWarning) {
987                             informativeText = tr("<p>Rosegarden was unable to find a high-resolution timing source for MIDI performance.</p><p>You may be able to solve this problem by loading the RTC timer kernel module.  To do this, try running <b>sudo modprobe snd-rtctimer</b> in a terminal window and then restarting Rosegarden.</p><p>Alternatively, check whether your Linux distributor provides a multimedia-optimized kernel.  See the <a style=\"color:gold\"  href=\"http://www.rosegardenmusic.com/wiki/low-latency_kernels\">Rosegarden website</a> for notes about this.</p>");
988 
989                             // whatever, don't show again during this run
990                             showAltTimerWarning = false;
991                         }
992 
993                         // if we got some informative text, shoot it out to the
994                         // warning widget queue
995                         if (informativeText != "")
996                             emit sendWarning(WarningWidget::Timer, text, informativeText);
997                     }
998                 }
999             }
1000         }
1001     }
1002 
1003     // if we aren't playing or recording, consider invoking any
1004     // step-by-step clients (using unfiltered composition).  send
1005     // out any incoming external controller events
1006 
1007     for (i = mC.begin(); i != mC.end(); ++i ) {
1008         if (m_transportStatus == STOPPED ||
1009             m_transportStatus == RECORDING_ARMED) {
1010             if ((*i)->getType() == MappedEvent::MidiNote) {
1011                 if ((*i)->getVelocity() == 0) {
1012                     emit insertableNoteOffReceived((*i)->getPitch(), (*i)->getVelocity());
1013                 } else {
1014                     emit insertableNoteOnReceived((*i)->getPitch(), (*i)->getVelocity());
1015                 }
1016             }
1017         }
1018         if ((*i)->getRecordedDevice() == Device::EXTERNAL_CONTROLLER) {
1019             RG_DEBUG << "processAsynchronousMidi(): Calling ExternalController::processEvent()...";
1020             ExternalController::self().processEvent(*i);
1021         }
1022     }
1023 }
1024 
1025 void
rewindToBeginning()1026 SequenceManager::rewindToBeginning()
1027 {
1028     RG_DEBUG << "rewindToBeginning()";
1029     m_doc->slotSetPointerPosition(m_doc->getComposition().getStartMarker());
1030 }
1031 
1032 void
fastForwardToEnd()1033 SequenceManager::fastForwardToEnd()
1034 {
1035     RG_DEBUG << "fastForwardToEnd()";
1036     Composition &comp = m_doc->getComposition();
1037     m_doc->slotSetPointerPosition(comp.getEndMarker());
1038 }
1039 
1040 void
setLoop(const timeT & lhs,const timeT & rhs)1041 SequenceManager::setLoop(const timeT &lhs, const timeT &rhs)
1042 {
1043     // !!!  So who disabled the following, why?  Are loops with JACK transport
1044     //      sync no longer hideously broken?
1045     //
1046     // do not set a loop if JACK transport sync is enabled, because this is
1047     // completely broken, and apparently broken due to a limitation of JACK
1048     // transport itself.  #1240039 - DMM
1049     //    QSettings settings;
1050     //    settings.beginGroup( SequencerOptionsConfigGroup );
1051     //
1052 
1053     //    if ( qStrToBool( settings.value("jacktransport", "false" ) ) )
1054     //    {
1055     //	// !!! message box should go here to inform user of why the loop was
1056     //	//     not set, but I can't add it at the moment due to to the pre-release
1057     //	//     freeze - DMM
1058     //    settings.endGroup();
1059     //	return;
1060     //    }
1061 
1062     RealTime loopStart =
1063         m_doc->getComposition().getElapsedRealTime(lhs);
1064     RealTime loopEnd =
1065         m_doc->getComposition().getElapsedRealTime(rhs);
1066 
1067     RosegardenSequencer::getInstance()->setLoop(loopStart, loopEnd);
1068 }
1069 
inCountIn(const RealTime & time) const1070 bool SequenceManager::inCountIn(const RealTime &time) const
1071 {
1072     if (m_transportStatus == RECORDING  ||
1073         m_transportStatus == STARTING_TO_RECORD) {
1074         if (time < m_realRecordStart)
1075             return true;
1076     }
1077     return false;
1078 }
1079 
1080 void
checkSoundDriverStatus(bool warnUser)1081 SequenceManager::checkSoundDriverStatus(bool warnUser)
1082 {
1083     // Keep a local copy of the status to avoid calling
1084     // RosegardenSequencer::getSoundDriverStatus() which uses a lock.
1085     m_soundDriverStatus =
1086             RosegardenSequencer::getInstance()->getSoundDriverStatus();
1087 
1088     RG_DEBUG << "checkSoundDriverStatus(): Sound driver status:" <<
1089             "MIDI" << (((m_soundDriverStatus & MIDI_OK) != 0) ? "ok" : "NOT OK") << "|" <<
1090             "Audio" << (((m_soundDriverStatus & AUDIO_OK) != 0) ? "ok" : "NOT OK");
1091 
1092     if (!warnUser)
1093         return;
1094 
1095 #ifdef HAVE_LIBJACK
1096     // Audio and MIDI ok?  Bail.
1097     if ((m_soundDriverStatus & AUDIO_OK)  &&
1098         (m_soundDriverStatus & MIDI_OK))
1099         return;
1100 #else
1101     // MIDI ok?  Bail.
1102     if (m_soundDriverStatus & MIDI_OK)
1103         return;
1104 #endif
1105 
1106     // Either MIDI or Audio are not ok...
1107 
1108     StartupLogo::hideIfStillThere();
1109 
1110     QString text;
1111     QString informativeText;
1112 
1113     if (m_soundDriverStatus == NO_DRIVER) {
1114         text = tr("<h3>Sequencer engine unavailable!</h3>");
1115         informativeText = tr("<p>Both MIDI and Audio subsystems have failed to initialize.</p><p>If you wish to run with no sequencer by design, then use \"rosegarden --nosound\" to avoid seeing this error in the future.  Otherwise, we recommend that you repair your system configuration and start Rosegarden again.</p>");
1116     } else if (!(m_soundDriverStatus & MIDI_OK)) {
1117         text = tr("<h3>MIDI sequencing unavailable!</h3>");
1118         informativeText = tr("<p>The MIDI subsystem has failed to initialize.</p><p>You may continue without the sequencer, but we suggest closing Rosegarden, running \"modprobe snd-seq-midi\" as root, and starting Rosegarden again.  If you wish to run with no sequencer by design, then use \"rosegarden --nosound\" to avoid seeing this error in the future.</p>");
1119     }
1120 
1121     if (!text.isEmpty()) {
1122         emit sendWarning(WarningWidget::Midi, text, informativeText);
1123         return;
1124     }
1125 
1126 #ifdef HAVE_LIBJACK
1127     // If audio driver is not ok...
1128     if (!(m_soundDriverStatus & AUDIO_OK)) {
1129         // This is to avoid us ever showing the same dialog more than
1130         // once during a single run of the program -- it's quite
1131         // separate from the suppression function
1132         // ??? But this routine is only ever called once.  From
1133         //     RMW's ctor.  There is no need for this.  Plus the warning dialogs
1134         //     are now hidden in the warning button in the WarningWidget in
1135         //     the status bar.
1136         static bool showJackWarning = true;
1137 
1138         if (showJackWarning) {
1139             text = tr("<h3>Audio sequencing and synth plugins unavailable!</h3>");
1140             informativeText = tr("<p>Rosegarden could not connect to the JACK audio server.  This probably means that Rosegarden was unable to start the audio server due to a problem with your configuration, your system installation, or both.</p><p>If you want to be able to play or record audio files or use plugins, we suggest that you exit Rosegarden and use the JACK Control utility (qjackctl) to try different settings until you arrive at a configuration that permits JACK to start.  You may also need to install a realtime kernel, edit your system security configuration, and so on.  Unfortunately, this is an extremely complex subject.</p><p> Once you establish a working JACK configuration, Rosegarden will be able to start the audio server automatically in the future.</p>");
1141             emit sendWarning(WarningWidget::Audio, text, informativeText);
1142 
1143             showJackWarning = false;
1144         }
1145     }
1146 #endif
1147 }
1148 
1149 void
preparePlayback()1150 SequenceManager::preparePlayback()
1151 {
1152     // ??? rename: setMappedInstruments()
1153 
1154     // ??? Where does this function really belong?  It iterates over the
1155     //     Instrument's in the Studio and calls
1156     //     RosegardenSequencer::setMappedInstrument().  Seems like
1157     //     RosegardenSequencer might be a better place.  Or would Studio
1158     //     make more sense?
1159 
1160     Studio &studio = m_doc->getStudio();
1161     const InstrumentList list = studio.getAllInstruments();
1162 
1163     // Send the MappedInstruments full information to the Sequencer
1164     InstrumentList::const_iterator it = list.begin();
1165     for (; it != list.end(); ++it) {
1166         StudioControl::sendMappedInstrument(MappedInstrument(*it));
1167     }
1168 }
1169 
1170 void
reinitialiseSequencerStudio()1171 SequenceManager::reinitialiseSequencerStudio()
1172 {
1173     // ??? static function.  What class does this really belong in?
1174     //     RosegardenSequencer seems logical since all this does is call
1175     //     RosegardenSequencer::processMappedEvent() based on the config file.
1176 
1177     QSettings settings;
1178     settings.beginGroup( SequencerOptionsConfigGroup );
1179 
1180     // Toggle JACK audio ports appropriately
1181 
1182     MidiByte ports = 0;
1183 
1184     bool faderOuts =
1185             qStrToBool( settings.value("audiofaderouts", "false" ) ) ;
1186     if (faderOuts)
1187         ports |= MappedEvent::FaderOuts;
1188 
1189     bool submasterOuts =
1190             qStrToBool( settings.value("audiosubmasterouts", "false" ) ) ;
1191     if (submasterOuts)
1192         ports |= MappedEvent::SubmasterOuts;
1193 
1194     MappedEvent mEports(
1195             MidiInstrumentBase, MappedEvent::SystemAudioPorts, ports);
1196     StudioControl::sendMappedEvent(mEports);
1197 
1198     // Audio File Format
1199 
1200     unsigned int audioFileFormat =
1201             settings.value("audiorecordfileformat", 1).toUInt() ;
1202 
1203     MappedEvent mEff(
1204             MidiInstrumentBase, MappedEvent::SystemAudioFileFormat,
1205             audioFileFormat);
1206     StudioControl::sendMappedEvent(mEff);
1207 
1208     settings.endGroup();
1209 }
1210 
1211 void
panic()1212 SequenceManager::panic()
1213 {
1214     RG_DEBUG << "panic()";
1215 
1216     stop();
1217 
1218     MappedEvent mE(MidiInstrumentBase, MappedEvent::Panic, 0, 0);
1219     StudioControl::sendMappedEvent(mE);
1220 }
1221 
setTempo(const tempoT tempo)1222 void SequenceManager::setTempo(const tempoT tempo)
1223 {
1224     if (m_tempo == tempo)
1225         return;
1226     m_tempo = tempo;
1227 
1228     // Send the quarter note length to the sequencer.
1229     // Quarter Note Length is sent (MIDI CLOCK) at 24ppqn.
1230     //
1231     double qnD = 60.0 / Composition::getTempoQpm(tempo);
1232     RealTime qnTime =
1233         RealTime(long(qnD),
1234                  long((qnD - double(long(qnD))) * 1000000000.0));
1235 
1236     StudioControl::sendQuarterNoteLength(qnTime);
1237 
1238     // set the tempo in the transport
1239     emit signalTempoChanged(tempo);
1240 }
1241 
resetCompositionMapper()1242 void SequenceManager::resetCompositionMapper()
1243 {
1244     RG_DEBUG << "resetCompositionMapper()";
1245 
1246     RosegardenSequencer::getInstance()->compositionAboutToBeDeleted();
1247 
1248     m_compositionMapper.reset(new CompositionMapper(m_doc));
1249 
1250     resetMetronomeMapper();
1251     resetTempoSegmentMapper();
1252     resetTimeSigSegmentMapper();
1253 
1254     // Reset ControlBlock.
1255     ControlBlock::getInstance()->setDocument(m_doc);
1256 }
1257 
populateCompositionMapper()1258 void SequenceManager::populateCompositionMapper()
1259 {
1260     Composition &comp = m_doc->getComposition();
1261 
1262     for (Composition::iterator i = comp.begin(); i != comp.end(); ++i) {
1263         RG_DEBUG << "populateCompositionMapper(): Adding segment with rid " << (*i)->getRuntimeId();
1264         segmentAdded(*i);
1265     }
1266 
1267     for (Composition::triggersegmentcontaineriterator i =
1268                 comp.getTriggerSegments().begin();
1269          i != comp.getTriggerSegments().end(); ++i) {
1270         m_triggerSegments.insert(SegmentRefreshMap::value_type
1271                                  ((*i)->getSegment(),
1272                                   (*i)->getSegment()->getNewRefreshStatusId()));
1273     }
1274 
1275 }
resetMetronomeMapper()1276 void SequenceManager::resetMetronomeMapper()
1277 {
1278     RG_DEBUG << "resetMetronomeMapper()";
1279 
1280     if (m_metronomeMapper) {
1281         RosegardenSequencer::getInstance()->segmentAboutToBeDeleted
1282             (m_metronomeMapper);
1283     }
1284 
1285     m_metronomeMapper =
1286             QSharedPointer<MetronomeMapper>(new MetronomeMapper(m_doc));
1287     RosegardenSequencer::getInstance()->segmentAdded
1288         (m_metronomeMapper);
1289 }
1290 
resetTempoSegmentMapper()1291 void SequenceManager::resetTempoSegmentMapper()
1292 {
1293     RG_DEBUG << "resetTempoSegmentMapper()";
1294 
1295     if (m_tempoSegmentMapper) {
1296         RosegardenSequencer::getInstance()->segmentAboutToBeDeleted
1297             (m_tempoSegmentMapper);
1298     }
1299 
1300     m_tempoSegmentMapper =
1301             QSharedPointer<TempoSegmentMapper>(new TempoSegmentMapper(m_doc));
1302     RosegardenSequencer::getInstance()->segmentAdded
1303         (m_tempoSegmentMapper);
1304 }
1305 
resetTimeSigSegmentMapper()1306 void SequenceManager::resetTimeSigSegmentMapper()
1307 {
1308     RG_DEBUG << "resetTimeSigSegmentMapper()";
1309 
1310     if (m_timeSigSegmentMapper) {
1311         RosegardenSequencer::getInstance()->segmentAboutToBeDeleted
1312             (m_timeSigSegmentMapper);
1313     }
1314 
1315     m_timeSigSegmentMapper =
1316             QSharedPointer<TimeSigSegmentMapper>(new TimeSigSegmentMapper(m_doc));
1317     RosegardenSequencer::getInstance()->segmentAdded
1318         (m_timeSigSegmentMapper);
1319 }
1320 
event(QEvent * e)1321 bool SequenceManager::event(QEvent *e)
1322 {
1323     if (e->type() == QEvent::User) {
1324         //RG_DEBUG << "event() with user event";
1325         if (m_refreshRequested) {
1326             //RG_DEBUG << "event(): update requested";
1327             refresh();
1328             m_refreshRequested = false;
1329         }
1330         return true;
1331     } else {
1332         return QObject::event(e);
1333     }
1334 }
1335 
update()1336 void SequenceManager::update()
1337 {
1338     //RG_DEBUG << "update()";
1339     // schedule a refresh-status check for the next event loop
1340     QEvent *e = new QEvent(QEvent::User);
1341     // Let the handler know we want a refresh().
1342     // ??? But we always want a refresh().  When wouldn't we?  Are
1343     //     we getting QEvent::User events from elsewhere?
1344     m_refreshRequested = true;
1345     QApplication::postEvent(this, e);
1346 }
1347 
refresh()1348 void SequenceManager::refresh()
1349 {
1350     RG_DEBUG << "refresh()";
1351 
1352     Composition &comp = m_doc->getComposition();
1353 
1354     // ??? See Segment::m_refreshStatusArray for insight into what this
1355     //     is doing.
1356 
1357     // Look at trigger segments first: if one of those has changed, we'll
1358     // need to be aware of it when scanning segments subsequently
1359 
1360     // List of Segments modified by changes to trigger Segments.  These
1361     // will need a refresh.
1362     // ??? Instead of gathering these, can't we just set the refresh
1363     //     status for the Segment?  Or would that cause others to do
1364     //     refreshes?  Can we just set *our* refresh status?
1365     // ??? rename: triggerRefreshSet
1366     TriggerSegmentRec::SegmentRuntimeIdSet ridset;
1367 
1368     // List of all trigger Segments.
1369     SegmentRefreshMap newTriggerMap;
1370 
1371     // For each trigger Segment in the composition
1372     for (Composition::triggersegmentcontaineriterator i =
1373              comp.getTriggerSegments().begin();
1374          i != comp.getTriggerSegments().end(); ++i) {
1375 
1376         Segment *s = (*i)->getSegment();
1377 
1378         // If we don't have this one
1379         if (m_triggerSegments.find(s) == m_triggerSegments.end()) {
1380             // Make a new trigger Segment entry.
1381             newTriggerMap[s] = s->getNewRefreshStatusId();
1382         } else {
1383             // Use the existing entry.
1384             newTriggerMap[s] = m_triggerSegments[s];
1385         }
1386 
1387         // If this trigger Segment needs a refresh
1388         if (s->getRefreshStatus(newTriggerMap[s]).needsRefresh()) {
1389             // Collect all the Segments this will affect.
1390             TriggerSegmentRec::SegmentRuntimeIdSet &thisSet =
1391                     (*i)->getReferences();
1392             ridset.insert(thisSet.begin(), thisSet.end());
1393 
1394             // Clear the trigger Segment's refresh flag.
1395             s->getRefreshStatus(newTriggerMap[s]).setNeedsRefresh(false);
1396         }
1397     }
1398 
1399     m_triggerSegments = newTriggerMap;
1400 
1401 #if 0
1402     RG_DEBUG << "refresh(): segments modified by changes to trigger segments are:";
1403     int x = 0;
1404     for (TriggerSegmentRec::SegmentRuntimeIdSet::iterator i = ridset.begin();
1405             i != ridset.end(); ++i) {
1406         RG_DEBUG << x << ": " << *i;
1407         ++x;
1408     }
1409 #endif
1410 
1411     std::vector<Segment*>::iterator i;
1412 
1413     // Removed Segments
1414 
1415     for (i = m_removedSegments.begin(); i != m_removedSegments.end(); ++i) {
1416         segmentDeleted(*i);
1417     }
1418     m_removedSegments.clear();
1419 
1420     RG_DEBUG << "refresh(): we have " << m_segments.size() << " segments";
1421 
1422     // Current Segments
1423 
1424     for (SegmentRefreshMap::iterator i = m_segments.begin();
1425             i != m_segments.end(); ++i) {
1426         // If this Segment needs a refresh
1427         if (i->first->getRefreshStatus(i->second).needsRefresh() ||
1428                 ridset.find(i->first->getRuntimeId()) != ridset.end()) {
1429             segmentModified(i->first);
1430             i->first->getRefreshStatus(i->second).setNeedsRefresh(false);
1431         }
1432     }
1433 
1434     // Added Segments
1435 
1436     for (i = m_addedSegments.begin(); i != m_addedSegments.end(); ++i) {
1437         segmentAdded(*i);
1438     }
1439     m_addedSegments.clear();
1440 }
1441 
1442 void
segmentModified(Segment * s)1443 SequenceManager::segmentModified(Segment* s)
1444 {
1445     RG_DEBUG << "segmentModified(" << s << ")";
1446 
1447     bool sizeChanged = m_compositionMapper->segmentModified(s);
1448 
1449     RG_DEBUG << "segmentModified() : size changed = " << sizeChanged;
1450 
1451     RosegardenSequencer::getInstance()->segmentModified
1452         (m_compositionMapper->getMappedEventBuffer(s));
1453 }
1454 
segmentAdded(const Composition *,Segment * s)1455 void SequenceManager::segmentAdded(const Composition*, Segment* s)
1456 {
1457     RG_DEBUG << "segmentAdded(" << s << "); queueing";
1458     m_addedSegments.push_back(s);
1459 }
1460 
segmentRemoved(const Composition *,Segment * s)1461 void SequenceManager::segmentRemoved(const Composition*, Segment* s)
1462 {
1463     RG_DEBUG << "segmentRemoved(" << s << ")";
1464 
1465     // !!! WARNING !!!
1466     // The segment pointer "s" is about to be deleted by
1467     // Composition::deleteSegment(Composition::iterator).  After this routine
1468     // ends, this pointer cannot be dereferenced.
1469     m_removedSegments.push_back(s);
1470 
1471     std::vector<Segment*>::iterator i =
1472         find(m_addedSegments.begin(), m_addedSegments.end(), s);
1473     if (i != m_addedSegments.end()) {
1474         m_addedSegments.erase(i);
1475     }
1476 }
1477 
segmentRepeatChanged(const Composition *,Segment * s,bool repeat)1478 void SequenceManager::segmentRepeatChanged(const Composition*, Segment* s, bool repeat)
1479 {
1480     RG_DEBUG << "segmentRepeatChanged(" << s << ", " << repeat << ")";
1481     segmentModified(s);
1482 }
1483 
segmentRepeatEndChanged(const Composition *,Segment * s,timeT newEndTime)1484 void SequenceManager::segmentRepeatEndChanged(const Composition*, Segment* s, timeT newEndTime)
1485 {
1486     RG_DEBUG << "segmentRepeatEndChanged(" << s << ", " << newEndTime << ")";
1487     segmentModified(s);
1488 }
1489 
segmentEventsTimingChanged(const Composition *,Segment * s,timeT t,RealTime)1490 void SequenceManager::segmentEventsTimingChanged(const Composition*, Segment * s, timeT t, RealTime)
1491 {
1492     RG_DEBUG << "segmentEventsTimingChanged(" << s << ", " << t << ")";
1493     segmentModified(s);
1494     if (s && s->getType() == Segment::Audio && m_transportStatus == PLAYING) {
1495         RosegardenSequencer::getInstance()->remapTracks();
1496     }
1497 }
1498 
segmentTransposeChanged(const Composition *,Segment * s,int transpose)1499 void SequenceManager::segmentTransposeChanged(const Composition*, Segment *s, int transpose)
1500 {
1501     RG_DEBUG << "segmentTransposeChanged(" << s << ", " << transpose << ")";
1502     segmentModified(s);
1503 }
1504 
segmentTrackChanged(const Composition *,Segment * s,TrackId id)1505 void SequenceManager::segmentTrackChanged(const Composition*, Segment *s, TrackId id)
1506 {
1507     RG_DEBUG << "segmentTrackChanged(" << s << ", " << id << ")";
1508     segmentModified(s);
1509     if (s && s->getType() == Segment::Audio && m_transportStatus == PLAYING) {
1510         RosegardenSequencer::getInstance()->remapTracks();
1511     }
1512 }
1513 
segmentEndMarkerChanged(const Composition *,Segment * s,bool)1514 void SequenceManager::segmentEndMarkerChanged(const Composition*, Segment *s, bool)
1515 {
1516     RG_DEBUG << "segmentEndMarkerChanged(" << s << ")";
1517     segmentModified(s);
1518 }
1519 
segmentInstrumentChanged(Segment * s)1520 void SequenceManager::segmentInstrumentChanged(Segment *s)
1521 {
1522     RG_DEBUG << "segmentInstrumentChanged(" << s << ")";
1523     // Quick and dirty: Redo the whole segment.
1524     segmentModified(s);
1525 }
1526 
segmentAdded(Segment * s)1527 void SequenceManager::segmentAdded(Segment* s)
1528 {
1529     RG_DEBUG << "segmentAdded(" << s << ")";
1530     m_compositionMapper->segmentAdded(s);
1531 
1532     RosegardenSequencer::getInstance()->segmentAdded
1533         (m_compositionMapper->getMappedEventBuffer(s));
1534 
1535     // Add to segments map
1536     int id = s->getNewRefreshStatusId();
1537     m_segments.insert(SegmentRefreshMap::value_type(s, id));
1538 }
1539 
segmentDeleted(Segment * s)1540 void SequenceManager::segmentDeleted(Segment* s)
1541 {
1542     RG_DEBUG << "segmentDeleted(" << s << ")";
1543 
1544     // !!! WARNING !!!
1545     // The "s" segment pointer that is coming in to this routine has already
1546     // been deleted.  This is a POINTER TO DELETED MEMORY.  It cannot be
1547     // dereferenced in any way.  Each of the following lines of code will be
1548     // explained to make it clear that the pointer is not being dereferenced.
1549     // ??? This needs to be fixed.  Passing around pointers that point to
1550     //     nowhere is just asking for trouble.  E.g. what if the same memory
1551     //     address is allocated to a new Segment, that Segment is added, then
1552     //     this routine is called for the old Segment?  We remove the
1553     //     new Segment.
1554 
1555     {
1556         // getMappedEventBuffer() uses the segment pointer value as an
1557     	// index into a map.  So this is not a dereference.
1558         QSharedPointer<MappedEventBuffer> mapper =
1559             m_compositionMapper->getMappedEventBuffer(s);
1560         // segmentDeleted() has been reviewed and should only be using
1561         // the pointer as an index into a container.  segmentDeleted()
1562         // doesn't delete the mapper, which the metaiterators own.
1563         m_compositionMapper->segmentDeleted(s);
1564         RosegardenSequencer::getInstance()->segmentAboutToBeDeleted(mapper);
1565         // Now mapper may have been deleted.
1566     }
1567     // Remove from segments map
1568     // This uses "s" as an index.  It is not dereferenced.
1569     m_segments.erase(s);
1570 }
1571 
endMarkerTimeChanged(const Composition *,bool)1572 void SequenceManager::endMarkerTimeChanged(const Composition *, bool /*shorten*/)
1573 {
1574     RG_DEBUG << "endMarkerTimeChanged()";
1575 
1576     if (m_transportStatus == RECORDING) {
1577         // When recording, we just need to extend the metronome segment
1578         // to include the new bars.
1579         // ??? This is pretty extreme as it destroys and recreates the
1580         //     segment.  Can't we just add events to the existing segment
1581         //     instead?  Maybe always have one or two bars extra so there
1582         //     is no interruption.  As it is, this will likely cause an
1583         //     interruption in metronome events when the composition is
1584         //     expanded.
1585         resetMetronomeMapper();
1586     } else {
1587         // Reset the composition mapper.  The main thing this does is
1588         // update the metronome segment.  There appear to be other
1589         // important things that need to be done as well.
1590         slotScheduledCompositionMapperReset();
1591     }
1592 }
1593 
timeSignatureChanged(const Composition *)1594 void SequenceManager::timeSignatureChanged(const Composition *)
1595 {
1596     resetMetronomeMapper();
1597 }
1598 
tracksAdded(const Composition * c,std::vector<TrackId> & trackIds)1599 void SequenceManager::tracksAdded(const Composition* c, std::vector<TrackId> &trackIds)
1600 {
1601     RG_DEBUG << "tracksAdded()  tracks: " << trackIds.size();
1602 
1603     // For each track added, call ControlBlock::updateTrackData()
1604     for (unsigned i = 0; i < trackIds.size(); ++i) {
1605         RG_DEBUG << "  ID: " << trackIds[i];
1606 
1607         Track *t = c->getTrackById(trackIds[i]);
1608         ControlBlock::getInstance()->updateTrackData(t);
1609 
1610         // ??? Can we move this out of this for loop and call it once after
1611         //     we are done calling updateTrackData() for each track?
1612         if (m_transportStatus == PLAYING) {
1613             RosegardenSequencer::getInstance()->remapTracks();
1614         }
1615     }
1616 }
1617 
trackChanged(const Composition *,Track * t)1618 void SequenceManager::trackChanged(const Composition *, Track* t)
1619 {
1620     RG_DEBUG << "trackChanged()  ID: " << t->getId();
1621 
1622     ControlBlock::getInstance()->updateTrackData(t);
1623 
1624     if (m_transportStatus == PLAYING) {
1625         RosegardenSequencer::getInstance()->remapTracks();
1626     }
1627 }
1628 
tracksDeleted(const Composition *,std::vector<TrackId> & trackIds)1629 void SequenceManager::tracksDeleted(const Composition *, std::vector<TrackId> &trackIds)
1630 {
1631     RG_DEBUG << "tracksDeleted()  tracks:" << trackIds.size();
1632 
1633     for (unsigned i = 0; i < trackIds.size(); ++i) {
1634         RG_DEBUG << "  ID: " << trackIds[i];
1635         ControlBlock::getInstance()->setTrackDeleted(trackIds[i], true);
1636     }
1637 }
1638 
metronomeChanged(InstrumentId id,bool regenerateTicks)1639 void SequenceManager::metronomeChanged(InstrumentId id,
1640                                        bool regenerateTicks)
1641 {
1642     // This method is called when the user has changed the
1643     // metronome instrument, pitch etc
1644 
1645     RG_DEBUG << "metronomeChanged() (simple)" << ", instrument = " << id;
1646     if (regenerateTicks) resetMetronomeMapper();
1647 
1648     Composition &comp = m_doc->getComposition();
1649     ControlBlock::getInstance()->setInstrumentForMetronome(id);
1650 
1651     if (m_transportStatus == PLAYING) {
1652         ControlBlock::getInstance()->setMetronomeMuted(!comp.usePlayMetronome());
1653     } else {
1654         ControlBlock::getInstance()->setMetronomeMuted(!comp.useRecordMetronome());
1655     }
1656 
1657     m_metronomeMapper->refresh();
1658     m_timeSigSegmentMapper->refresh();
1659     m_tempoSegmentMapper->refresh();
1660 }
1661 
metronomeChanged(const Composition * comp)1662 void SequenceManager::metronomeChanged(const Composition *comp)
1663 {
1664     // This method is called when the muting status in the composition
1665     // has changed -- the metronome itself has not actually changed
1666 
1667     RG_DEBUG << "metronomeChanged() " << ", instrument = " << m_metronomeMapper->getMetronomeInstrument();
1668     if (!comp) comp = &m_doc->getComposition();
1669     ControlBlock::getInstance()->setInstrumentForMetronome
1670         (m_metronomeMapper->getMetronomeInstrument());
1671 
1672     if (m_transportStatus == PLAYING) {
1673         ControlBlock::getInstance()->setMetronomeMuted(!comp->usePlayMetronome());
1674     } else {
1675         ControlBlock::getInstance()->setMetronomeMuted(!comp->useRecordMetronome());
1676     }
1677 }
1678 
filtersChanged(MidiFilter thruFilter,MidiFilter recordFilter)1679 void SequenceManager::filtersChanged(MidiFilter thruFilter,
1680                                      MidiFilter recordFilter)
1681 {
1682     ControlBlock::getInstance()->setThruFilter(thruFilter);
1683     ControlBlock::getInstance()->setRecordFilter(recordFilter);
1684 }
1685 
selectedTrackChanged(const Composition * composition)1686 void SequenceManager::selectedTrackChanged(const Composition *composition)
1687 {
1688     TrackId selectedTrackId = composition->getSelectedTrack();
1689     ControlBlock::getInstance()->setSelectedTrack(selectedTrackId);
1690 }
1691 
tempoChanged(const Composition * c)1692 void SequenceManager::tempoChanged(const Composition *c)
1693 {
1694     RG_DEBUG << "tempoChanged()";
1695 
1696     // Refresh all segments
1697     //
1698     for (SegmentRefreshMap::iterator i = m_segments.begin();
1699          i != m_segments.end(); ++i) {
1700         segmentModified(i->first);
1701     }
1702 
1703     // and metronome, time sig and tempo
1704     //
1705     m_metronomeMapper->refresh();
1706     m_timeSigSegmentMapper->refresh();
1707     m_tempoSegmentMapper->refresh();
1708 
1709     if (c->isLooping())
1710         setLoop(c->getLoopStart(), c->getLoopEnd());
1711     else if (m_transportStatus == PLAYING) {
1712 
1713         // Tempo has changed during playback.
1714 
1715         // Reset the playback position because the sequencer keeps track of
1716         // position in real time (seconds) and we want to maintain the same
1717         // position in musical time (bars/beats).
1718         m_doc->slotSetPointerPosition(c->getPosition());
1719 
1720     }
1721 }
1722 
1723 void
sendTransportControlStatuses()1724 SequenceManager::sendTransportControlStatuses()
1725 {
1726     // ??? static function.  Where does this really belong?  I suspect
1727     //     RosegardenSequencer.
1728 
1729     QSettings settings;
1730     settings.beginGroup( SequencerOptionsConfigGroup );
1731 
1732     // Get the settings values
1733     //
1734     bool jackTransport = qStrToBool( settings.value("jacktransport", "false" ) ) ;
1735     bool jackMaster = qStrToBool( settings.value("jackmaster", "false" ) ) ;
1736 
1737     int mmcMode = settings.value("mmcmode", 0).toInt() ;
1738     int mtcMode = settings.value("mtcmode", 0).toInt() ;
1739 
1740     int midiClock = settings.value("midiclock", 0).toInt() ;
1741     bool midiSyncAuto = qStrToBool( settings.value("midisyncautoconnect", "false" ) ) ;
1742 
1743     // Send JACK transport
1744     //
1745     int jackValue = 0;
1746     if (jackTransport && jackMaster)
1747         jackValue = 2;
1748     else {
1749         if (jackTransport)
1750             jackValue = 1;
1751         else
1752             jackValue = 0;
1753     }
1754 
1755     MappedEvent mEjackValue(MidiInstrumentBase,  // InstrumentId
1756                             MappedEvent::SystemJackTransport,
1757                             MidiByte(jackValue));
1758     StudioControl::sendMappedEvent(mEjackValue);
1759 
1760 
1761     // Send MMC transport
1762     //
1763     MappedEvent mEmmcValue(MidiInstrumentBase,  // InstrumentId
1764                            MappedEvent::SystemMMCTransport,
1765                            MidiByte(mmcMode));
1766 
1767     StudioControl::sendMappedEvent(mEmmcValue);
1768 
1769 
1770     // Send MTC transport
1771     //
1772     MappedEvent mEmtcValue(MidiInstrumentBase,  // InstrumentId
1773                            MappedEvent::SystemMTCTransport,
1774                            MidiByte(mtcMode));
1775 
1776     StudioControl::sendMappedEvent(mEmtcValue);
1777 
1778 
1779     // Send MIDI Clock
1780     //
1781     MappedEvent mEmidiClock(MidiInstrumentBase,  // InstrumentId
1782                             MappedEvent::SystemMIDIClock,
1783                             MidiByte(midiClock));
1784 
1785     StudioControl::sendMappedEvent(mEmidiClock);
1786 
1787 
1788     // Send MIDI Sync Auto-Connect
1789     //
1790     MappedEvent mEmidiSyncAuto(MidiInstrumentBase,  // InstrumentId
1791                                MappedEvent::SystemMIDISyncAuto,
1792                                MidiByte(midiSyncAuto ? 1 : 0));
1793 
1794     StudioControl::sendMappedEvent(mEmidiSyncAuto);
1795 
1796     settings.endGroup();
1797 }
1798 
1799 void
slotCountdownTimerTimeout()1800 SequenceManager::slotCountdownTimerTimeout()
1801 {
1802     // Set the elapsed time in seconds
1803     //
1804     m_countdownDialog->setElapsedTime(m_recordTime->elapsed() / 1000);
1805 }
1806 
1807 void
slotScheduledCompositionMapperReset()1808 SequenceManager::slotScheduledCompositionMapperReset()
1809 {
1810     // ??? Inline into only caller.
1811     resetCompositionMapper();
1812     populateCompositionMapper();
1813 }
1814 
1815 int
getSampleRate() const1816 SequenceManager::getSampleRate() const
1817 {
1818     // Get from cache if it's there.
1819     if (m_sampleRate != 0)
1820         return m_sampleRate;
1821 
1822     // Cache the result to avoid locks.
1823     m_sampleRate = RosegardenSequencer::getInstance()->getSampleRate();
1824 
1825     return m_sampleRate;
1826 }
1827 
1828 bool
shouldWarnForImpreciseTimer()1829 SequenceManager::shouldWarnForImpreciseTimer()
1830 {
1831     const QString timer =
1832             RosegardenSequencer::getInstance()->getCurrentTimer();
1833 
1834     // If no specific timer has been chosen by the user, do warnings
1835     if (timer == "(auto)"  ||  timer == "")
1836         return true;
1837     else  // The user has chosen a specific timer, leave them alone.
1838         return false;
1839 }
1840 
1841 // Return a new metaiterator on the current composition (suitable
1842 // for MidiFile)
1843 MappedBufMetaIterator *
1844 SequenceManager::
makeTempMetaiterator()1845 makeTempMetaiterator()
1846 {
1847     MappedBufMetaIterator *metaiterator = new MappedBufMetaIterator;
1848     // Add the mappers we know of.  Not the metronome because we don't
1849     // export that.
1850     metaiterator->addBuffer(m_tempoSegmentMapper);
1851     metaiterator->addBuffer(m_timeSigSegmentMapper);
1852     // We don't hold on to the marker mapper because we only use it
1853     // when exporting.
1854     metaiterator->addBuffer(QSharedPointer<MarkerMapper>(new MarkerMapper(m_doc)));
1855     typedef CompositionMapper::SegmentMappers container;
1856     typedef container::iterator iterator;
1857     container &mapperContainer = m_compositionMapper->m_segmentMappers;
1858     for (iterator i = mapperContainer.begin();
1859          i != mapperContainer.end();
1860          ++i) {
1861         metaiterator->addBuffer(i->second);
1862     }
1863     return metaiterator;
1864 }
1865 
1866 }
1867