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