1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A sequencer and musical notation editor.
autoincnull6     Copyright 2000-2021 the Rosegarden development team.
7     See the AUTHORS file for more details.
8 
9     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14 */
15 
16 #define RG_MODULE_STRING "[Composition]"
17 
18 #include "Composition.h"
19 
20 #include "misc/Debug.h"
21 #include "base/Segment.h"
22 #include "base/SegmentLinker.h"
23 #include "base/BaseProperties.h"
24 #include "base/Profiler.h"
25 #include "BasicQuantizer.h"
26 #include "NotationQuantizer.h"
27 #include "base/AudioLevel.h"
28 
29 #include <algorithm>
30 #include <cmath>
31 #include <iomanip>
32 #include <iterator>  // for std::distance
33 #include <map>
34 #include <set>
35 #include <sstream>
36 
37 //#include <iostream>
38 //#include <typeinfo>
39 //#include <limits.h>
40 
41 //#define DEBUG_BAR_STUFF 1
42 //#define DEBUG_TEMPO_STUFF 1
43 
44 
45 namespace Rosegarden
46 {
47 
48 
49 const PropertyName Composition::NoAbsoluteTimeProperty = "NoAbsoluteTime";
50 const PropertyName Composition::BarNumberProperty = "BarNumber";
51 
52 const std::string Composition::TempoEventType = "tempo";
53 const PropertyName Composition::TempoProperty = "Tempo";
54 const PropertyName Composition::TargetTempoProperty = "TargetTempo";
55 const PropertyName Composition::TempoTimestampProperty = "TimestampSec";
56 
57 
58 bool
59 Composition::ReferenceSegmentEventCmp::operator()(const Event &e1,
60                                                   const Event &e2) const
61 {
62     if (e1.has(NoAbsoluteTimeProperty) ||
63         e2.has(NoAbsoluteTimeProperty)) {
64         RealTime r1 = getTempoTimestamp(&e1);
65         RealTime r2 = getTempoTimestamp(&e2);
66         return r1 < r2;
67     } else {
68         return e1 < e2;
69     }
70 }
71 
72 Composition::ReferenceSegment::ReferenceSegment(std::string eventType) :
73     m_eventType(eventType)
74 {
75     // nothing
76 }
77 
78 Composition::ReferenceSegment::~ReferenceSegment()
79 {
80     clear();
81 }
82 
83 Composition::ReferenceSegment::iterator Composition::ReferenceSegment::begin()
84 {
85     return m_events.begin();
86 }
87 
88 Composition::ReferenceSegment::const_iterator Composition::ReferenceSegment::begin() const
89 {
90     return m_events.begin();
91 }
92 
93 Composition::ReferenceSegment::iterator Composition::ReferenceSegment::end()
94 {
95     return m_events.end();
96 }
97 
98 Composition::ReferenceSegment::const_iterator Composition::ReferenceSegment::end() const
99 {
100     return m_events.end();
101 }
102 
103 Composition::ReferenceSegment::size_type Composition::ReferenceSegment::size() const
104 {
105     return m_events.size();
106 }
107 
108 bool Composition::ReferenceSegment::empty() const
109 {
110     return m_events.empty();
111 }
112 
113 Composition::ReferenceSegment::iterator
114 Composition::ReferenceSegment::erase(Composition::ReferenceSegment::iterator position)
115 {
116     return m_events.erase(position);
117 }
118 
119 void Composition::ReferenceSegment::clear()
120 {
121     for (iterator it = begin(); it != end(); ++it) delete (*it);
122     m_events.clear();
123 }
124 
125 Event* Composition::ReferenceSegment::operator[] (size_type n)
126 {
127     return m_events[n];
128 }
129 
130 const Event* Composition::ReferenceSegment::operator[] (size_type n) const
131 {
132     return m_events[n];
133 }
134 
135 timeT
136 Composition::ReferenceSegment::getDuration() const
137 {
138     const_iterator i = end();
139     if (i == begin()) return 0;
140     --i;
141 
142     return (*i)->getAbsoluteTime() + (*i)->getDuration();
143 }
144 
145 Composition::ReferenceSegment::iterator
146 Composition::ReferenceSegment::find(Event *e)
147 {
148     return std::lower_bound
149         (begin(), end(), e, ReferenceSegmentEventCmp());
150 }
151 
152 Composition::ReferenceSegment::iterator
153 Composition::ReferenceSegment::insertEvent(Event *e)
154 {
155     if (!e->isa(m_eventType)) {
156         throw Event::BadType(std::string("event in ReferenceSegment"),
157                              m_eventType, e->getType(), __FILE__, __LINE__);
158     }
159 
160     iterator i = find(e);
161 
162     if (i != end() && (*i)->getAbsoluteTime() == e->getAbsoluteTime()) {
163 
164         Event *old = (*i);
165         (*i) = e;
166         delete old;
167         return i;
168 
169     } else {
170         return m_events.insert(i, e);
171     }
172 }
173 
174 void
175 Composition::ReferenceSegment::eraseEvent(Event *e)
176 {
177     iterator i = find(e);
178     if (i != end()) m_events.erase(i);
179 }
180 
181 Composition::ReferenceSegment::iterator
182 Composition::ReferenceSegment::findTime(timeT t)
183 {
184     Event dummy("dummy", t, 0, MIN_SUBORDERING);
185     return find(&dummy);
186 }
187 
188 Composition::ReferenceSegment::iterator
189 Composition::ReferenceSegment::findRealTime(RealTime t)
190 {
191     Event dummy("dummy", 0, 0, MIN_SUBORDERING);
192     dummy.set<Bool>(NoAbsoluteTimeProperty, true);
193     setTempoTimestamp(&dummy, t);
194     return find(&dummy);
195 }
196 
197 Composition::ReferenceSegment::iterator
198 Composition::ReferenceSegment::findNearestTime(timeT t)
199 {
200     iterator i = findTime(t);
201     if (i == end() || (*i)->getAbsoluteTime() > t) {
202         if (i == begin()) return end();
203         else --i;
204     }
205     return i;
206 }
207 
208 Composition::ReferenceSegment::iterator
209 Composition::ReferenceSegment::findNearestRealTime(RealTime t)
210 {
211     iterator i = findRealTime(t);
212     if (i == end() || (getTempoTimestamp(*i) > t)) {
213         if (i == begin()) return end();
214         else --i;
215     }
216     return i;
217 }
218 
219 namespace
220 {
221     constexpr int defaultNumberOfBars = 100;
222 }
223 
224 Composition::Composition() :
225     m_notationSpacing(100),
226     m_selectedTrackId(0),
227     m_timeSigSegment(TimeSignature::EventType),
228     m_tempoSegment(TempoEventType),
229     m_barPositionsNeedCalculating(true),
230     m_tempoTimestampsNeedCalculating(true),
231     m_basicQuantizer(new BasicQuantizer()),
232     m_notationQuantizer(new NotationQuantizer()),
233     m_position(0),
234     m_defaultTempo(getTempoForQpm(120.0)),
235     m_minTempo(0),
236     m_maxTempo(0),
237     m_startMarker(0),
238     m_endMarker(getBarRange(defaultNumberOfBars).first),
239     m_autoExpand(false),
240     m_loopStart(0),
241     m_loopEnd(0),
242     m_playMetronome(false),
243     m_recordMetronome(true),
244     m_nextTriggerSegmentId(0)
245 {
246     // nothing else
247 }
248 
249 Composition::~Composition()
250 {
251     if (!m_observers.empty()) {
252         RG_WARNING << "dtor: WARNING:" << m_observers.size() << "observers still extant:";
253         for (const CompositionObserver *observer : m_observers) {
254             RG_WARNING << "  " << (void *)(observer) << ":" << typeid(*observer).name();
255         }
256     }
257 
258     notifySourceDeletion();
259     clear();
260     delete m_basicQuantizer;
261     delete m_notationQuantizer;
262 }
263 
264 Composition::iterator
265 Composition::addSegment(Segment *segment)
266 {
267     iterator res = weakAddSegment(segment);
268 
269     if (res != end()) {
270         updateRefreshStatuses();
271         distributeVerses();
272         notifySegmentAdded(segment);
273     }
274 
275     return res;
276 }
277 
278 Composition::iterator
279 Composition::weakAddSegment(Segment *segment)
280 {
281     if (!segment) return end();
282     clearVoiceCaches();
283 
284     iterator res = m_segments.insert(segment);
285     segment->setComposition(this);
286 
287     return res;
288 }
289 
290 void
291 Composition::deleteSegment(Composition::iterator i)
292 {
293     if (i == end()) return;
294     clearVoiceCaches();
295 
296     Segment *p = (*i);
297     p->setComposition(nullptr);
298 
299     m_segments.erase(i);
300     distributeVerses();
301     notifySegmentRemoved(p);
302 
303     // ??? If this delete occurs during playback, we may get a crash later in
304     //     MappedBufMetaIterator::fetchEvents().
305     delete p;
306 
307     updateRefreshStatuses();
308 }
309 
310 bool
311 Composition::deleteSegment(Segment *segment)
312 {
313     iterator i = findSegment(segment);
314     if (i == end()) return false;
315 
316     deleteSegment(i);
317     return true;
318 }
319 
320 bool
321 Composition::detachSegment(Segment *segment)
322 {
323     bool res = weakDetachSegment(segment);
324 
325     if (res) {
326         distributeVerses();
327         notifySegmentRemoved(segment);
328         updateRefreshStatuses();
329     }
330 
331     return res;
332 }
333 
334 bool
335 Composition::weakDetachSegment(Segment *segment)
336 {
337     iterator i = findSegment(segment);
338     if (i == end()) return false;
339     clearVoiceCaches();
340 
341     segment->setComposition(nullptr);
342     m_segments.erase(i);
343 
344     return true;
345 }
346 
347 // Add every segment in SegmentMultiSet
348 // @author Tom Breton (Tehom)
349 void
350 Composition::addAllSegments(SegmentMultiSet segments)
351 {
352     for (SegmentMultiSet::iterator i = segments.begin();
353          i != segments.end();
354          ++i)
355         { addSegment(*i); }
356 }
357 
358 void
359 Composition::addAllSegments(SegmentVec segments)
360 {
361     for (SegmentVec::iterator i = segments.begin();
362          i != segments.end();
363          ++i)
364         { addSegment(*i); }
365 }
366 
367 // Detach every segment in SegmentMultiSet
368 // @author Tom Breton (Tehom)
369 void
370 Composition::detachAllSegments(SegmentMultiSet segments)
371 {
372     for (SegmentMultiSet::iterator i = segments.begin();
373          i != segments.end();
374          ++i)
375         { detachSegment(*i); }
376 }
377 
378 void
379 Composition::detachAllSegments(SegmentVec segments)
380 {
381     for (SegmentVec::iterator i = segments.begin();
382          i != segments.end();
383          ++i)
384         { detachSegment(*i); }
385 }
386 
387 bool
388 Composition::contains(const Segment *s)
389 {
390     iterator i = findSegment(s);
391     return (i != end());
392 }
393 
394 Composition::iterator
395 Composition::findSegment(const Segment *s)
396 {
397     iterator i = m_segments.lower_bound(const_cast<Segment*>(s));
398 
399     while (i != end()) {
400         if (*i == s) break;
401         if ((*i)->getStartTime() > s->getStartTime()) return end();
402         ++i;
403     }
404 
405     return i;
406 }
407 
408 void Composition::setSegmentStartTime(Segment *segment, timeT startTime)
409 {
410     Profiler profiler("Composition::setSegmentStartTime");
411     // remove the segment from the multiset
412     iterator i = findSegment(segment);
413     if (i == end()) return;
414 
415     clearVoiceCaches();
416 
417     m_segments.erase(i);
418 
419     segment->setStartTimeDataMember(startTime);
420 
421     // re-add it
422     m_segments.insert(segment);
423 }
424 
425 void
426 Composition::clearVoiceCaches()
427 {
428     m_trackVoiceCountCache.clear();
429     m_segmentVoiceIndexCache.clear();
430 }
431 
432 void
433 Composition::rebuildVoiceCaches() const
434 {
435     Profiler profiler("Composition::rebuildVoiceCaches");
436 
437     // slow
438 
439     m_trackVoiceCountCache.clear();
440     m_segmentVoiceIndexCache.clear();
441 
442     for (trackcontainer::const_iterator tci = m_tracks.begin();
443          tci != m_tracks.end(); ++tci) {
444 
445         TrackId tid = tci->first;
446 
447         std::multimap<timeT, Segment *> ends;
448 
449         for (const_iterator i = begin(); i != end(); ++i) {
450             if ((*i)->getTrack() != tid) continue;
451             timeT t0 = (*i)->getStartTime();
452             timeT t1 = (*i)->getRepeatEndTime();
453             int index = 0;
454             std::multimap<timeT, Segment *>::iterator ei = ends.end();
455             std::set<int> used;
456             while (ei != ends.begin()) {
457                 --ei;
458                 if (ei->first <= t0) break;
459                 used.insert(m_segmentVoiceIndexCache[ei->second]);
460             }
461             if (!used.empty()) {
462                 for (index = 0; ; ++index) {
463                     if (used.find(index) == used.end()) break;
464                 }
465             }
466             m_segmentVoiceIndexCache[*i] = index;
467             if (index >= m_trackVoiceCountCache[tid]) {
468                 m_trackVoiceCountCache[tid] = index + 1;
469             }
470             ends.insert(std::multimap<timeT, Segment *>::value_type(t1, *i));
471         }
472     }
473 }
474 
475 int
476 Composition::getMaxContemporaneousSegmentsOnTrack(TrackId track) const
477 {
478     Profiler profiler("Composition::getMaxContemporaneousSegmentsOnTrack");
479 
480     if (m_trackVoiceCountCache.empty()) {
481         rebuildVoiceCaches();
482     }
483 
484     int count = m_trackVoiceCountCache[track];
485 
486     return count;
487 }
488 
489 int
490 Composition::getSegmentVoiceIndex(const Segment *segment) const
491 {
492     if (m_segmentVoiceIndexCache.empty()) {
493         rebuildVoiceCaches();
494     }
495 
496     return m_segmentVoiceIndexCache[segment];
497 }
498 
499 void
500 Composition::resetLinkedSegmentRefreshStatuses()
501 {
502     std::set<const SegmentLinker *> linkers;
503     for (iterator itr = begin(); itr != end(); ++itr) {
504         Segment *segment = *itr;
505         if (segment->isLinked()) {
506             SegmentLinker *linker = segment->getLinker();
507             std::set<const SegmentLinker *>::const_iterator finder =
508                                                            linkers.find(linker);
509             if (finder == linkers.end()) {
510                 linker->clearRefreshStatuses();
511                 linkers.insert(linker);
512             }
513         }
514     }
515 }
516 
517 TriggerSegmentRec *
518 Composition::addTriggerSegment(Segment *s, int pitch, int velocity)
519 {
520     TriggerSegmentId id = m_nextTriggerSegmentId;
521     return addTriggerSegment(s, id, pitch, velocity);
522 }
523 
524 TriggerSegmentRec *
525 Composition::addTriggerSegment(Segment *s, TriggerSegmentId id, int pitch, int velocity)
526 {
527     TriggerSegmentRec *rec = getTriggerSegmentRec(id);
528     if (rec) return nullptr;
529     rec = new TriggerSegmentRec(id, s, pitch, velocity);
530     m_triggerSegments.insert(rec);
531     s->setComposition(this);
532     if (m_nextTriggerSegmentId <= id) m_nextTriggerSegmentId = id + 1;
533     return rec;
534 }
535 
536 void
537 Composition::deleteTriggerSegment(TriggerSegmentId id)
538 {
539     TriggerSegmentRec dummyRec(id, nullptr);
540     triggersegmentcontaineriterator i = m_triggerSegments.find(&dummyRec);
541     if (i == m_triggerSegments.end()) return;
542     (*i)->getSegment()->setComposition(nullptr);
543     delete (*i)->getSegment();
544     delete *i;
545     m_triggerSegments.erase(i);
546 }
547 
548 void
549 Composition::detachTriggerSegment(TriggerSegmentId id)
550 {
551     TriggerSegmentRec dummyRec(id, nullptr);
552     triggersegmentcontaineriterator i = m_triggerSegments.find(&dummyRec);
553     if (i == m_triggerSegments.end()) return;
554     (*i)->getSegment()->setComposition(nullptr);
555     delete *i;
556     m_triggerSegments.erase(i);
557 }
558 
559 void
560 Composition::clearTriggerSegments()
561 {
562     for (triggersegmentcontaineriterator i = m_triggerSegments.begin();
563          i != m_triggerSegments.end(); ++i) {
564         delete (*i)->getSegment();
565         delete *i;
566     }
567     m_triggerSegments.clear();
568 }
569 
570 int
571 Composition::getTriggerSegmentId(Segment *s)
572 {
573     for (triggersegmentcontaineriterator i = m_triggerSegments.begin();
574          i != m_triggerSegments.end(); ++i) {
575         if ((*i)->getSegment() == s) return (*i)->getId();
576     }
577     return -1;
578 }
579 
580 Segment *
581 Composition::getTriggerSegment(TriggerSegmentId id)
582 {
583     TriggerSegmentRec *rec = getTriggerSegmentRec(id);
584     if (!rec) return nullptr;
585     return rec->getSegment();
586 }
587 
588 TriggerSegmentRec *
589 Composition::getTriggerSegmentRec(TriggerSegmentId id)
590 {
591     TriggerSegmentRec dummyRec(id, nullptr);
592     triggersegmentcontaineriterator i = m_triggerSegments.find(&dummyRec);
593     if (i == m_triggerSegments.end()) return nullptr;
594     return *i;
595 }
596 
597 TriggerSegmentRec *
598 Composition::getTriggerSegmentRec(Event* e)
599 {
600     if (!e->has(BaseProperties::TRIGGER_SEGMENT_ID))
601         { return nullptr; }
602 
603     const int id = e->get<Int>(BaseProperties::TRIGGER_SEGMENT_ID);
604     return getTriggerSegmentRec(id);
605 }
606 
607 TriggerSegmentId
608 Composition::getNextTriggerSegmentId() const
609 {
610     return m_nextTriggerSegmentId;
611 }
612 
613 void
614 Composition::setNextTriggerSegmentId(TriggerSegmentId id)
615 {
616     m_nextTriggerSegmentId = id;
617 }
618 
619 void
620 Composition::updateTriggerSegmentReferences()
621 {
622     std::map<TriggerSegmentId, TriggerSegmentRec::SegmentRuntimeIdSet> refs;
623 
624     for (iterator i = begin(); i != end(); ++i) {
625         for (Segment::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
626             if ((*j)->has(BaseProperties::TRIGGER_SEGMENT_ID)) {
627                 TriggerSegmentId id =
628                     (*j)->get<Int>(BaseProperties::TRIGGER_SEGMENT_ID);
629                 refs[id].insert((*i)->getRuntimeId());
630             }
631         }
632     }
633 
634     for (std::map<TriggerSegmentId,
635                   TriggerSegmentRec::SegmentRuntimeIdSet>::iterator i = refs.begin();
636          i != refs.end(); ++i) {
637         TriggerSegmentRec *rec = getTriggerSegmentRec(i->first);
638         if (rec) rec->setReferences(i->second);
639     }
640 }
641 
642 
643 timeT
644 Composition::getDuration() const
645 {
646     timeT maxDuration = 0;
647 
648     for (SegmentMultiSet::const_iterator i = m_segments.begin();
649          i != m_segments.end(); ++i) {
650 
651         timeT segmentTotal = (*i)->getEndTime();
652 
653         if (segmentTotal > maxDuration) {
654             maxDuration = segmentTotal;
655         }
656     }
657 
658     return maxDuration;
659 }
660 
661 void
662 Composition::setStartMarker(const timeT &sM)
663 {
664     m_startMarker = sM;
665     updateRefreshStatuses();
666 }
667 
668 void
669 Composition::setEndMarker(const timeT &eM)
670 {
671     bool shorten = (eM < m_endMarker);
672     m_endMarker = eM;
673     clearVoiceCaches();
674     updateRefreshStatuses();
675     notifyEndMarkerChange(shorten);
676 }
677 
678 void
679 Composition::clear()
680 {
681     while (m_segments.size() > 0) {
682         deleteSegment(begin());
683     }
684 
685     clearTracks();
686     clearMarkers();
687     clearTriggerSegments();
688 
689     m_timeSigSegment.clear();
690     m_tempoSegment.clear();
691     m_defaultTempo = getTempoForQpm(120.0);
692     m_minTempo = 0;
693     m_maxTempo = 0;
694     m_loopStart = 0;
695     m_loopEnd = 0;
696     m_position = 0;
697     m_startMarker = 0;
698     m_endMarker = getBarRange(defaultNumberOfBars).first;
699     m_selectedTrackId = 0;
700     updateRefreshStatuses();
701 }
702 
703 void
704 Composition::calculateBarPositions() const
705 {
706     if (!m_barPositionsNeedCalculating) return;
707 
708 #ifdef DEBUG_BAR_STUFF
709     RG_DEBUG << "calculateBarPositions()";
710 #endif
711 
712     ReferenceSegment &t = m_timeSigSegment;
713     ReferenceSegment::iterator i;
714 
715     timeT lastBarNo = 0;
716     timeT lastSigTime = 0;
717     timeT barDuration = TimeSignature().getBarDuration();
718 
719     if (getStartMarker() < 0) {
720         if (!t.empty() && (*t.begin())->getAbsoluteTime() <= 0) {
721             barDuration = TimeSignature(**t.begin()).getBarDuration();
722         }
723         lastBarNo = getStartMarker() / barDuration;
724         lastSigTime = getStartMarker();
725 #ifdef DEBUG_BAR_STUFF
726         RG_DEBUG << "calculateBarPositions(): start marker = " << getStartMarker() << ", so initial bar number = " << lastBarNo;
727 #endif
728     }
729 
730     for (i = t.begin(); i != t.end(); ++i) {
731 
732         timeT myTime = (*i)->getAbsoluteTime();
733         int n = (myTime - lastSigTime) / barDuration;
734 
735         // should only happen for first time sig, when it's at time < 0:
736         if (myTime < lastSigTime) --n;
737 
738         // would there be a new bar here anyway?
739         if (barDuration * n + lastSigTime == myTime) { // yes
740             n += lastBarNo;
741         } else { // no
742             n += lastBarNo + 1;
743         }
744 
745 #ifdef DEBUG_BAR_STUFF
746         RG_DEBUG << "calculateBarPositions(): bar " << n << " at " << myTime;
747 #endif
748 
749         (*i)->set<Int>(BarNumberProperty, n);
750 
751         lastBarNo = n;
752         lastSigTime = myTime;
753         barDuration = TimeSignature(**i).getBarDuration();
754     }
755 
756     m_barPositionsNeedCalculating = false;
757 }
758 
759 int
760 Composition::getNbBars() const
761 {
762     calculateBarPositions();
763 
764     // the "-1" is a small kludge to deal with the case where the
765     // composition has a duration that's an exact number of bars
766     int bars = getBarNumber(getDuration() - 1) + 1;
767 
768 #ifdef DEBUG_BAR_STUFF
769     RG_DEBUG << "getNbBars(): returning " << bars;
770 #endif
771     return bars;
772 }
773 
774 int
775 Composition::getBarNumber(timeT t) const
776 {
777     calculateBarPositions();
778     ReferenceSegment::iterator i = m_timeSigSegment.findNearestTime(t);
779     int n;
780 
781     if (i == m_timeSigSegment.end()) { // precedes any time signatures
782 
783         timeT bd = TimeSignature().getBarDuration();
784         if (t < 0) { // see comment in getTimeSignatureAtAux
785             i = m_timeSigSegment.begin();
786             if (i != m_timeSigSegment.end() && (*i)->getAbsoluteTime() <= 0) {
787                 bd = TimeSignature(**i).getBarDuration();
788             }
789         }
790 
791         n = t / bd;
792         if (t < 0) {
793             // negative bars should be rounded down, except where
794             // the time is on a barline in which case we already
795             // have the right value (i.e. time -1920 is bar -1,
796             // but time -3840 is also bar -1, in 4/4)
797             if (n * bd != t) --n;
798         }
799 
800     } else {
801 
802         n = (*i)->get<Int>(BarNumberProperty);
803         timeT offset = t - (*i)->getAbsoluteTime();
804         n += offset / TimeSignature(**i).getBarDuration();
805     }
806 
807 #ifdef DEBUG_BAR_STUFF
808     RG_DEBUG << "getBarNumber(" << t << "): returning " << n;
809 #endif
810     return n;
811 }
812 
813 
814 std::pair<timeT, timeT>
815 Composition::getBarRangeForTime(timeT t) const
816 {
817     return getBarRange(getBarNumber(t));
818 }
819 
820 
821 std::pair<timeT, timeT>
822 Composition::getBarRange(int n) const
823 {
824     calculateBarPositions();
825 
826     Event dummy("dummy", 0);
827     dummy.set<Int>(BarNumberProperty, n);
828 
829     ReferenceSegment::iterator j = std::lower_bound
830         (m_timeSigSegment.begin(), m_timeSigSegment.end(),
831          &dummy, BarNumberComparator());
832     ReferenceSegment::iterator i = j;
833 
834     if (i == m_timeSigSegment.end() || (*i)->get<Int>(BarNumberProperty) > n) {
835         if (i == m_timeSigSegment.begin()) i = m_timeSigSegment.end();
836         else --i;
837     } else ++j; // j needs to point to following barline
838 
839     timeT start, finish;
840 
841     if (i == m_timeSigSegment.end()) { // precedes any time sig changes
842 
843         timeT barDuration = TimeSignature().getBarDuration();
844         if (n < 0) { // see comment in getTimeSignatureAtAux
845             i = m_timeSigSegment.begin();
846             if (i != m_timeSigSegment.end() && (*i)->getAbsoluteTime() <= 0) {
847                 barDuration = TimeSignature(**i).getBarDuration();
848             }
849         }
850 
851         start = n * barDuration;
852         finish = start + barDuration;
853 
854 #ifdef DEBUG_BAR_STUFF
855     RG_DEBUG << "getBarRange(): [1] bar " << n << ": (" << start << " -> " << finish << ")";
856 #endif
857 
858     } else {
859 
860         timeT barDuration = TimeSignature(**i).getBarDuration();
861         start = (*i)->getAbsoluteTime() +
862             (n - (*i)->get<Int>(BarNumberProperty)) * barDuration;
863         finish = start + barDuration;
864 
865 #ifdef DEBUG_BAR_STUFF
866     RG_DEBUG << "getBarRange(): [2] bar " << n << ": (" << start << " -> " << finish << ")";
867 #endif
868     }
869 
870     // partial bar
871     if (j != m_timeSigSegment.end() && finish > (*j)->getAbsoluteTime()) {
872         finish = (*j)->getAbsoluteTime();
873 #ifdef DEBUG_BAR_STUFF
874     RG_DEBUG << "getBarRange(): [3] bar " << n << ": (" << start << " -> " << finish << ")";
875 #endif
876     }
877 
878     return std::pair<timeT, timeT>(start, finish);
879 }
880 
881 int
882 Composition::addTimeSignature(timeT t, TimeSignature timeSig)
883 {
884 #ifdef DEBUG_BAR_STUFF
885     RG_DEBUG << "addTimeSignature(" << t << ", " << timeSig.getNumerator() << "/" << timeSig.getDenominator() << ")";
886 #endif
887 
888     ReferenceSegment::iterator i =
889         m_timeSigSegment.insertEvent(timeSig.getAsEvent(t));
890     m_barPositionsNeedCalculating = true;
891 
892     updateRefreshStatuses();
893     notifyTimeSignatureChanged();
894 
895     return std::distance(m_timeSigSegment.begin(), i);
896 }
897 
898 TimeSignature
899 Composition::getTimeSignatureAt(timeT t) const
900 {
901     TimeSignature timeSig;
902     (void)getTimeSignatureAt(t, timeSig);
903     return timeSig;
904 }
905 
906 timeT
907 Composition::getTimeSignatureAt(timeT t, TimeSignature &timeSig) const
908 {
909     ReferenceSegment::iterator i = getTimeSignatureAtAux(t);
910 
911     if (i == m_timeSigSegment.end()) {
912         timeSig = TimeSignature();
913         return 0;
914     } else {
915         timeSig = TimeSignature(**i);
916         return (*i)->getAbsoluteTime();
917     }
918 }
919 
920 TimeSignature
921 Composition::getTimeSignatureInBar(int barNo, bool &isNew) const
922 {
923     isNew = false;
924     timeT t = getBarRange(barNo).first;
925 
926     ReferenceSegment::iterator i = getTimeSignatureAtAux(t);
927 
928     if (i == m_timeSigSegment.end()) return TimeSignature();
929     if (t == (*i)->getAbsoluteTime()) isNew = true;
930 
931     return TimeSignature(**i);
932 }
933 
934 Composition::ReferenceSegment::iterator
935 Composition::getTimeSignatureAtAux(timeT t) const
936 {
937     ReferenceSegment::iterator i = m_timeSigSegment.findNearestTime(t);
938 
939     // In negative time, if there's no time signature actually defined
940     // prior to the point of interest then we use the next time
941     // signature after it, so long as it's no later than time zero.
942     // This is the only rational way to deal with count-in bars where
943     // the correct time signature otherwise won't appear until we hit
944     // bar zero.
945 
946     if (t < 0 && i == m_timeSigSegment.end()) {
947         i = m_timeSigSegment.begin();
948         if (i != m_timeSigSegment.end() && (*i)->getAbsoluteTime() > 0) {
949             i  = m_timeSigSegment.end();
950         }
951     }
952 
953     return i;
954 }
955 
956 int
957 Composition::getTimeSignatureCount() const
958 {
959     return int(m_timeSigSegment.size());
960 }
961 
962 int
963 Composition::getTimeSignatureNumberAt(timeT t) const
964 {
965     ReferenceSegment::iterator i = getTimeSignatureAtAux(t);
966     if (i == m_timeSigSegment.end()) return -1;
967     else return std::distance(m_timeSigSegment.begin(), i);
968 }
969 
970 std::pair<timeT, TimeSignature>
971 Composition::getTimeSignatureChange(int n) const
972 {
973     return std::pair<timeT, TimeSignature>
974         (m_timeSigSegment[n]->getAbsoluteTime(),
975          TimeSignature(*m_timeSigSegment[n]));
976 }
977 
978 void
979 Composition::removeTimeSignature(int n)
980 {
981     m_timeSigSegment.eraseEvent(m_timeSigSegment[n]);
982     m_barPositionsNeedCalculating = true;
983     updateRefreshStatuses();
984     notifyTimeSignatureChanged();
985 }
986 
987 
988 tempoT
989 Composition::getTempoAtTime(timeT t) const
990 {
991     ReferenceSegment::iterator i = m_tempoSegment.findNearestTime(t);
992 
993     // In negative time, if there's no tempo event actually defined
994     // prior to the point of interest then we use the next one after
995     // it, so long as it's no later than time zero.  This is the only
996     // rational way to deal with count-in bars where the correct
997     // tempo otherwise won't appear until we hit bar zero.  See also
998     // getTimeSignatureAt
999 
1000     if (i == m_tempoSegment.end()) {
1001         if (t < 0) {
1002 #ifdef DEBUG_TEMPO_STUFF
1003             RG_DEBUG << "getTempoAtTime(): Negative time " << t << " for tempo, using 0";
1004 #endif
1005             return getTempoAtTime(0);
1006         }
1007         else return m_defaultTempo;
1008     }
1009 
1010     tempoT tempo = (tempoT)((*i)->get<Int>(TempoProperty));
1011 
1012     if ((*i)->has(TargetTempoProperty)) {
1013 
1014         tempoT target = (tempoT)((*i)->get<Int>(TargetTempoProperty));
1015         ReferenceSegment::iterator j = i;
1016         ++j;
1017 
1018         if (target > 0 || (target == 0 && j != m_tempoSegment.end())) {
1019 
1020             timeT t0 = (*i)->getAbsoluteTime();
1021             timeT t1 = (j != m_tempoSegment.end() ?
1022                         (*j)->getAbsoluteTime() : getEndMarker());
1023 
1024             if (t1 < t0) return tempo;
1025 
1026             if (target == 0) {
1027                 target = (tempoT)((*j)->get<Int>(TempoProperty));
1028             }
1029 
1030             // tempo ramps are linear in 1/tempo
1031             double s0 = 1.0 / double(tempo);
1032             double s1 = 1.0 / double(target);
1033             double s = s0 + (t - t0) * ((s1 - s0) / (t1 - t0));
1034 
1035             tempoT result = tempoT((1.0 / s) + 0.01);
1036 
1037 #ifdef DEBUG_TEMPO_STUFF
1038             RG_DEBUG << "getTempoAtTime(): Calculated tempo " << result << " at " << t;
1039 #endif
1040 
1041             return result;
1042         }
1043     }
1044 
1045 #ifdef DEBUG_TEMPO_STUFF
1046     RG_DEBUG << "getTempoAtTime(): Found tempo " << tempo << " at " << t;
1047 #endif
1048     return tempo;
1049 }
1050 
1051 int
1052 Composition::addTempoAtTime(timeT time, tempoT tempo, tempoT targetTempo)
1053 {
1054     // If there's an existing tempo at this time, the ReferenceSegment
1055     // object will remove the duplicate, but we have to ensure that
1056     // the minimum and maximum tempos are updated if necessary.
1057 
1058     bool fullTempoUpdate = false;
1059 
1060     int n = getTempoChangeNumberAt(time);
1061     if (n >= 0) {
1062         std::pair<timeT, tempoT> tc = getTempoChange(n);
1063         if (tc.first == time) {
1064             if (tc.second == m_minTempo || tc.second == m_maxTempo) {
1065                 fullTempoUpdate = true;
1066             } else {
1067                 std::pair<bool, tempoT> tr = getTempoRamping(n);
1068                 if (tr.first &&
1069                     (tr.second == m_minTempo || tr.second == m_maxTempo)) {
1070                     fullTempoUpdate = true;
1071                 }
1072             }
1073         }
1074     }
1075 
1076     Event *tempoEvent = new Event(TempoEventType, time);
1077     tempoEvent->set<Int>(TempoProperty, tempo);
1078 
1079     if (targetTempo >= 0) {
1080         tempoEvent->set<Int>(TargetTempoProperty, targetTempo);
1081     }
1082 
1083     ReferenceSegment::iterator i = m_tempoSegment.insertEvent(tempoEvent);
1084 
1085     if (fullTempoUpdate) {
1086 
1087         updateExtremeTempos();
1088 
1089     } else {
1090 
1091         if (tempo < m_minTempo || m_minTempo == 0) m_minTempo = tempo;
1092         if (targetTempo > 0 && targetTempo < m_minTempo) m_minTempo = targetTempo;
1093 
1094         if (tempo > m_maxTempo || m_maxTempo == 0) m_maxTempo = tempo;
1095         if (targetTempo > 0 && targetTempo > m_maxTempo) m_maxTempo = targetTempo;
1096     }
1097 
1098     m_tempoTimestampsNeedCalculating = true;
1099     updateRefreshStatuses();
1100 
1101 #ifdef DEBUG_TEMPO_STUFF
1102     RG_DEBUG << "addTempoAtTime(): Added tempo " << tempo << " at " << time;
1103 #endif
1104     notifyTempoChanged();
1105 
1106     return std::distance(m_tempoSegment.begin(), i);
1107 }
1108 
1109 int
1110 Composition::getTempoChangeCount() const
1111 {
1112     return int(m_tempoSegment.size());
1113 }
1114 
1115 int
1116 Composition::getTempoChangeNumberAt(timeT t) const
1117 {
1118     ReferenceSegment::iterator i = m_tempoSegment.findNearestTime(t);
1119     if (i == m_tempoSegment.end()) return -1;
1120     else return std::distance(m_tempoSegment.begin(), i);
1121 }
1122 
1123 std::pair<timeT, tempoT>
1124 Composition::getTempoChange(int n) const
1125 {
1126     return std::pair<timeT, tempoT>
1127         (m_tempoSegment[n]->getAbsoluteTime(),
1128          tempoT(m_tempoSegment[n]->get<Int>(TempoProperty)));
1129 }
1130 
1131 std::pair<bool, tempoT>
1132 Composition::getTempoRamping(int n, bool calculate) const
1133 {
1134     tempoT target = -1;
1135     if (m_tempoSegment[n]->has(TargetTempoProperty)) {
1136         target = m_tempoSegment[n]->get<Int>(TargetTempoProperty);
1137     }
1138     bool ramped = (target >= 0);
1139     if (target == 0) {
1140         if (calculate) {
1141             if (int(m_tempoSegment.size()) > n+1) {
1142                 target = m_tempoSegment[n+1]->get<Int>(TempoProperty);
1143             }
1144         }
1145     }
1146     if (target < 0 || (calculate && (target == 0))) {
1147         target = m_tempoSegment[n]->get<Int>(TempoProperty);
1148     }
1149     return std::pair<bool, tempoT>(ramped, target);
1150 }
1151 
1152 void
1153 Composition::removeTempoChange(int n)
1154 {
1155     tempoT oldTempo = m_tempoSegment[n]->get<Int>(TempoProperty);
1156     tempoT oldTarget = -1;
1157 
1158     if (m_tempoSegment[n]->has(TargetTempoProperty)) {
1159         oldTarget = m_tempoSegment[n]->get<Int>(TargetTempoProperty);
1160     }
1161 
1162     m_tempoSegment.eraseEvent(m_tempoSegment[n]);
1163     m_tempoTimestampsNeedCalculating = true;
1164 
1165     if (oldTempo == m_minTempo ||
1166         oldTempo == m_maxTempo ||
1167         (oldTarget > 0 && oldTarget == m_minTempo) ||
1168         (oldTarget > 0 && oldTarget == m_maxTempo)) {
1169         updateExtremeTempos();
1170     }
1171 
1172     updateRefreshStatuses();
1173     notifyTempoChanged();
1174 }
1175 
1176 void
1177 Composition::updateExtremeTempos()
1178 {
1179     m_minTempo = 0;
1180     m_maxTempo = 0;
1181     for (ReferenceSegment::iterator i = m_tempoSegment.begin();
1182          i != m_tempoSegment.end(); ++i) {
1183         tempoT tempo = (*i)->get<Int>(TempoProperty);
1184         tempoT target = -1;
1185         if ((*i)->has(TargetTempoProperty)) {
1186             target = (*i)->get<Int>(TargetTempoProperty);
1187         }
1188         if (tempo < m_minTempo || m_minTempo == 0) m_minTempo = tempo;
1189         if (target > 0 && target < m_minTempo) m_minTempo = target;
1190         if (tempo > m_maxTempo || m_maxTempo == 0) m_maxTempo = tempo;
1191         if (target > 0 && target > m_maxTempo) m_maxTempo = target;
1192     }
1193     if (m_minTempo == 0) {
1194         m_minTempo = m_defaultTempo;
1195         m_maxTempo = m_defaultTempo;
1196     }
1197 }
1198 
1199 RealTime
1200 Composition::getElapsedRealTime(timeT t) const
1201 {
1202     calculateTempoTimestamps();
1203 
1204     ReferenceSegment::iterator i = m_tempoSegment.findNearestTime(t);
1205     if (i == m_tempoSegment.end()) {
1206         i = m_tempoSegment.begin();
1207         if (t >= 0 ||
1208             (i == m_tempoSegment.end() || (*i)->getAbsoluteTime() > 0)) {
1209             return time2RealTime(t, m_defaultTempo);
1210         }
1211     }
1212 
1213     RealTime elapsed;
1214 
1215     tempoT target = -1;
1216     timeT nextTempoTime = t;
1217 
1218     if (!getTempoTarget(i, target, nextTempoTime)) target = -1;
1219 
1220     if (target > 0) {
1221         elapsed = getTempoTimestamp(*i) +
1222             time2RealTime(t - (*i)->getAbsoluteTime(),
1223                           tempoT((*i)->get<Int>(TempoProperty)),
1224                           nextTempoTime - (*i)->getAbsoluteTime(),
1225                           target);
1226     } else {
1227         elapsed = getTempoTimestamp(*i) +
1228             time2RealTime(t - (*i)->getAbsoluteTime(),
1229                           tempoT((*i)->get<Int>(TempoProperty)));
1230     }
1231 
1232 #ifdef DEBUG_TEMPO_STUFF
1233     RG_DEBUG << "getElapsedRealTime(): " << t << " -> " << elapsed << " (last tempo change at " << (*i)->getAbsoluteTime() << ")";
1234 #endif
1235 
1236     return elapsed;
1237 }
1238 
1239 timeT
1240 Composition::getElapsedTimeForRealTime(RealTime t) const
1241 {
1242     calculateTempoTimestamps();
1243 
1244     ReferenceSegment::iterator i = m_tempoSegment.findNearestRealTime(t);
1245     if (i == m_tempoSegment.end()) {
1246         i = m_tempoSegment.begin();
1247         if (t >= RealTime::zeroTime ||
1248             (i == m_tempoSegment.end() || (*i)->getAbsoluteTime() > 0)) {
1249             return realTime2Time(t, m_defaultTempo);
1250         }
1251     }
1252 
1253     timeT elapsed;
1254 
1255     tempoT target = -1;
1256     timeT nextTempoTime = 0;
1257     if (!getTempoTarget(i, target, nextTempoTime)) target = -1;
1258 
1259     if (target > 0) {
1260         elapsed = (*i)->getAbsoluteTime() +
1261             realTime2Time(t - getTempoTimestamp(*i),
1262                           (tempoT)((*i)->get<Int>(TempoProperty)),
1263                           nextTempoTime - (*i)->getAbsoluteTime(),
1264                           target);
1265     } else {
1266         elapsed = (*i)->getAbsoluteTime() +
1267             realTime2Time(t - getTempoTimestamp(*i),
1268                           (tempoT)((*i)->get<Int>(TempoProperty)));
1269     }
1270 
1271 #ifdef DEBUG_TEMPO_STUFF
1272     static int doError = true;
1273     if (doError) {
1274         doError = false;
1275         RealTime cfReal = getElapsedRealTime(elapsed);
1276         timeT cfTimeT = getElapsedTimeForRealTime(cfReal);
1277         doError = true;
1278         RG_DEBUG << "getElapsedTimeForRealTime(): " << t << " -> "
1279              << elapsed << " (error " << (cfReal - t)
1280              << " or " << (cfTimeT - elapsed) << ", tempo "
1281              << (*i)->getAbsoluteTime() << ":"
1282              << (tempoT)((*i)->get<Int>(TempoProperty)) << ")";
1283     }
1284 #endif
1285     return elapsed;
1286 }
1287 
1288 void
1289 Composition::calculateTempoTimestamps() const
1290 {
1291     if (!m_tempoTimestampsNeedCalculating) return;
1292 
1293     timeT lastTimeT = 0;
1294     RealTime lastRealTime;
1295 
1296     tempoT tempo = m_defaultTempo;
1297     tempoT target = -1;
1298 
1299 #ifdef DEBUG_TEMPO_STUFF
1300     RG_DEBUG << "calculateTempoTimestamps(): Tempo events are:";
1301 #endif
1302 
1303     for (ReferenceSegment::iterator i = m_tempoSegment.begin();
1304          i != m_tempoSegment.end(); ++i) {
1305 
1306         RealTime myTime;
1307 
1308         if (target > 0) {
1309             myTime = lastRealTime +
1310                 time2RealTime((*i)->getAbsoluteTime() - lastTimeT, tempo,
1311                               (*i)->getAbsoluteTime() - lastTimeT, target);
1312         } else {
1313             myTime = lastRealTime +
1314                 time2RealTime((*i)->getAbsoluteTime() - lastTimeT, tempo);
1315         }
1316 
1317         setTempoTimestamp(*i, myTime);
1318 
1319 #ifdef DEBUG_TEMPO_STUFF
1320         RG_DEBUG << (*i);
1321 #endif
1322 
1323         lastRealTime = myTime;
1324         lastTimeT = (*i)->getAbsoluteTime();
1325         tempo = tempoT((*i)->get<Int>(TempoProperty));
1326 
1327         target = -1;
1328         timeT nextTempoTime = 0;
1329         if (!getTempoTarget(i, target, nextTempoTime)) target = -1;
1330     }
1331 
1332     m_tempoTimestampsNeedCalculating = false;
1333 }
1334 
1335 #ifdef DEBUG_TEMPO_STUFF
1336 static int DEBUG_silence_recursive_tempo_printout = 0;
1337 #endif
1338 
1339 RealTime
1340 Composition::time2RealTime(timeT t, tempoT tempo) const
1341 {
1342     static timeT cdur = Note(Note::Crotchet).getDuration();
1343 
1344     double dt = (double(t) * 100000 * 60) / (double(tempo) * cdur);
1345 
1346     int sec = int(dt);
1347     int nsec = int((dt - sec) * 1000000000);
1348 
1349     RealTime rt(sec, nsec);
1350 
1351 #ifdef DEBUG_TEMPO_STUFF
1352     if (!DEBUG_silence_recursive_tempo_printout) {
1353         RG_DEBUG << "time2RealTime(): t " << t << ", sec " << sec << ", nsec "
1354              << nsec << ", tempo " << tempo
1355              << ", cdur " << cdur << ", dt " << dt << ", rt " << rt;
1356         DEBUG_silence_recursive_tempo_printout = 1;
1357         timeT ct = realTime2Time(rt, tempo);
1358         timeT et = t - ct;
1359         RealTime ert = time2RealTime(et, tempo);
1360         RG_DEBUG << "cf. realTime2Time(" << rt << ") -> " << ct << " [err " << et << " (" << ert << "?)]";
1361         DEBUG_silence_recursive_tempo_printout=0;
1362     }
1363 #endif
1364 
1365     return rt;
1366 }
1367 
1368 RealTime
1369 Composition::time2RealTime(timeT time, tempoT tempo,
1370                            timeT targetTime, tempoT targetTempo) const
1371 {
1372     static timeT cdur = Note(Note::Crotchet).getDuration();
1373 
1374     // The real time elapsed at musical time t, in seconds, during a
1375     // smooth tempo change from "tempo" at musical time zero to
1376     // "targetTempo" at musical time "targetTime", is
1377     //
1378     //           2
1379     //     at + t (b - a)
1380     //          ---------
1381     //             2n
1382     // where
1383     //
1384     // a is the initial tempo in seconds per tick
1385     // b is the target tempo in seconds per tick
1386     // n is targetTime in ticks
1387 
1388     if (targetTime == 0 || targetTempo == tempo) {
1389         return time2RealTime(time, targetTempo);
1390     }
1391 
1392     double a = (100000 * 60) / (double(tempo) * cdur);
1393     double b = (100000 * 60) / (double(targetTempo) * cdur);
1394     double t = time;
1395     double n = targetTime;
1396     double result = (a * t) + (t * t * (b - a)) / (2 * n);
1397 
1398     int sec = int(result);
1399     int nsec = int((result - sec) * 1000000000);
1400 
1401     RealTime rt(sec, nsec);
1402 
1403 #ifdef DEBUG_TEMPO_STUFF
1404     if (!DEBUG_silence_recursive_tempo_printout) {
1405         RG_DEBUG << "time2RealTime(): [2] time " << time << ", tempo "
1406              << tempo << ", targetTime " << targetTime << ", targetTempo "
1407              << targetTempo << ": rt " << rt;
1408         DEBUG_silence_recursive_tempo_printout = 1;
1409 //        RealTime nextRt = time2RealTime(targetTime, tempo, targetTime, targetTempo);
1410         timeT ct = realTime2Time(rt, tempo, targetTime, targetTempo);
1411         RG_DEBUG << "cf. realTime2Time: rt " << rt << " -> " << ct;
1412         DEBUG_silence_recursive_tempo_printout=0;
1413     }
1414 #endif
1415 
1416     return rt;
1417 }
1418 
1419 timeT
1420 Composition::realTime2Time(RealTime rt, tempoT tempo) const
1421 {
1422     static timeT cdur = Note(Note::Crotchet).getDuration();
1423 
1424     double tsec = (double(rt.sec) * cdur) * (tempo / (60.0 * 100000.0));
1425     double tnsec = (double(rt.nsec) * cdur) * (tempo / 100000.0);
1426 
1427     double dt = tsec + (tnsec / 60000000000.0);
1428     timeT t = (timeT)(dt + (dt < 0 ? -1e-6 : 1e-6));
1429 
1430 #ifdef DEBUG_TEMPO_STUFF
1431     if (!DEBUG_silence_recursive_tempo_printout) {
1432         RG_DEBUG << "realTime2Time(): rt.sec " << rt.sec << ", rt.nsec "
1433              << rt.nsec << ", tempo " << tempo
1434              << ", cdur " << cdur << ", tsec " << tsec << ", tnsec " << tnsec << ", dt " << dt << ", t " << t;
1435         DEBUG_silence_recursive_tempo_printout = 1;
1436         RealTime crt = time2RealTime(t, tempo);
1437         RealTime ert = rt - crt;
1438         timeT et = realTime2Time(ert, tempo);
1439         RG_DEBUG << "cf. time2RealTime(" << t << ") -> " << crt << " [err " << ert << " (" << et << "?)]";
1440         DEBUG_silence_recursive_tempo_printout = 0;
1441     }
1442 #endif
1443 
1444     return t;
1445 }
1446 
1447 timeT
1448 Composition::realTime2Time(RealTime rt, tempoT tempo,
1449                            timeT targetTime, tempoT targetTempo) const
1450 {
1451     static timeT cdur = Note(Note::Crotchet).getDuration();
1452 
1453     // Inverse of the expression in time2RealTime above.
1454     //
1455     // The musical time elapsed at real time t, in ticks, during a
1456     // smooth tempo change from "tempo" at real time zero to
1457     // "targetTempo" at real time "targetTime", is
1458     //
1459     //          2na (+/-) sqrt((2nb)^2 + 8(b-a)tn)
1460     //       -  ----------------------------------
1461     //                       2(b-a)
1462     // where
1463     //
1464     // a is the initial tempo in seconds per tick
1465     // b is the target tempo in seconds per tick
1466     // n is target real time in ticks
1467 
1468     if (targetTempo == tempo) return realTime2Time(rt, tempo);
1469 
1470     double a = (100000 * 60) / (double(tempo) * cdur);
1471     double b = (100000 * 60) / (double(targetTempo) * cdur);
1472     double t = double(rt.sec) + double(rt.nsec) / 1e9;
1473     double n = targetTime;
1474 
1475     double term1 = 2.0 * n * a;
1476     double term2 = (2.0 * n * a) * (2.0 * n * a) + 8 * (b - a) * t * n;
1477 
1478     if (term2 < 0) {
1479         // We're screwed, but at least let's not crash
1480         RG_WARNING << "realTime2Time(): ERROR: term2 < 0 (it's " << term2 << ")";
1481 #ifdef DEBUG_TEMPO_STUFF
1482         RG_DEBUG << "rt = " << rt << ", tempo = " << tempo << ", targetTime = " << targetTime << ", targetTempo = " << targetTempo;
1483         RG_DEBUG << "n = " << n << ", b = " << b << ", a = " << a << ", t = " << t;
1484         RG_DEBUG << "that's sqrt( (" << ((2.0*n*a*2.0*n*a)) << ") + "
1485                   << (8*(b-a)*t*n) << " )";
1486 
1487         RG_DEBUG << "so our original expression was " << rt << " = "
1488                   << a << "t + (t^2 * (" << b << " - " << a << ")) / " << 2*n;
1489 #endif
1490 
1491         return realTime2Time(rt, tempo);
1492     }
1493 
1494     double term3 = std::sqrt(term2);
1495 
1496     // We only want the positive root
1497     if (term3 > 0) term3 = -term3;
1498 
1499     double result = - (term1 + term3) / (2 * (b - a));
1500 
1501 #ifdef DEBUG_TEMPO_STUFF
1502     RG_DEBUG << "realTime2Time():";
1503     RG_DEBUG << "n = " << n << ", b = " << b << ", a = " << a << ", t = " << t;
1504     RG_DEBUG << "+/-sqrt(term2) = " << term3;
1505     RG_DEBUG << "result = " << result;
1506 #endif
1507 
1508     return long(result + 0.1);
1509 }
1510 
1511 // @param A RealTime
1512 // @param The same time in TimeT
1513 // @param A target tempo to ramp to.  For now, this parameter is
1514 // ignored and ramping is not supported.
1515 // @returns A tempo that effects this relationship.
1516 // @author Tom Breton (Tehom)
1517 tempoT
1518 Composition::timeRatioToTempo(RealTime &realTime,
1519                                   timeT beatTime, tempoT)
1520 {
1521     static const timeT cdur = Note(Note::Crotchet).getDuration();
1522     const double beatsPerMinute = 60 / realTime.toSeconds();
1523     const double qpm = beatsPerMinute * double(beatTime) / double(cdur);
1524     tempoT averageTempo = Composition::getTempoForQpm(qpm);
1525     return averageTempo;
1526 }
1527 
1528 bool
1529 Composition::getTempoTarget(ReferenceSegment::const_iterator i,
1530                             tempoT &target,
1531                             timeT &targetTime) const
1532 {
1533     target = -1;
1534     targetTime = 0;
1535     bool have = false;
1536 
1537     if ((*i)->has(TargetTempoProperty)) {
1538         target = (*i)->get<Int>(TargetTempoProperty);
1539         if (target >= 0) {
1540             ReferenceSegment::const_iterator j(i);
1541             if (++j != m_tempoSegment.end()) {
1542                 if (target == 0) target = (*j)->get<Int>(TempoProperty);
1543                 targetTime = (*j)->getAbsoluteTime();
1544             } else {
1545                 targetTime = getEndMarker();
1546                 if (targetTime < (*i)->getAbsoluteTime()) {
1547                     target = -1;
1548                 }
1549             }
1550             if (target > 0) have = true;
1551         }
1552     }
1553 
1554     return have;
1555 }
1556 
1557 RealTime
1558 Composition::getTempoTimestamp(const Event *e)
1559 {
1560     RealTime res;
1561     e->get<RealTimeT>(TempoTimestampProperty, res);
1562     return res;
1563 }
1564 
1565 void
1566 Composition::setTempoTimestamp(Event *e, RealTime t)
1567 {
1568     e->setMaybe<RealTimeT>(TempoTimestampProperty, t);
1569 }
1570 
1571 void
1572 Composition::getMusicalTimeForAbsoluteTime(timeT absTime,
1573                                            int &bar, int &beat,
1574                                            int &fraction, int &remainder)
1575 {
1576     bar = getBarNumber(absTime);
1577 
1578     TimeSignature timeSig = getTimeSignatureAt(absTime);
1579     timeT barStart = getBarStart(bar);
1580     timeT beatDuration = timeSig.getBeatDuration();
1581     beat = (absTime - barStart) / beatDuration + 1;
1582 
1583     remainder = (absTime - barStart) % beatDuration;
1584     timeT fractionDuration = Note(Note::Shortest).getDuration();
1585     fraction = remainder / fractionDuration;
1586     remainder = remainder % fractionDuration;
1587 }
1588 
1589 void
1590 Composition::getMusicalTimeForDuration(timeT absTime, timeT duration,
1591                                        int &bars, int &beats,
1592                                        int &fractions, int &remainder)
1593 {
1594     TimeSignature timeSig = getTimeSignatureAt(absTime);
1595     timeT barDuration = timeSig.getBarDuration();
1596     timeT beatDuration = timeSig.getBeatDuration();
1597 
1598     bars = duration / barDuration;
1599     beats = (duration % barDuration) / beatDuration;
1600     remainder = (duration % barDuration) % beatDuration;
1601     timeT fractionDuration = Note(Note::Shortest).getDuration();
1602     fractions = remainder / fractionDuration;
1603     remainder = remainder % fractionDuration;
1604 }
1605 
1606 timeT
1607 Composition::getAbsoluteTimeForMusicalTime(int bar, int beat,
1608                                            int fraction, int remainder)
1609 {
1610     timeT t = getBarStart(bar - 1);
1611     TimeSignature timesig = getTimeSignatureAt(t);
1612     t += (beat-1) * timesig.getBeatDuration();
1613     t += Note(Note::Shortest).getDuration() * fraction;
1614     t += remainder;
1615     return t;
1616 }
1617 
1618 timeT
1619 Composition::getDurationForMusicalTime(timeT absTime,
1620                                        int bars, int beats,
1621                                        int fractions, int remainder)
1622 {
1623     TimeSignature timeSig = getTimeSignatureAt(absTime);
1624     timeT barDuration = timeSig.getBarDuration();
1625     timeT beatDuration = timeSig.getBeatDuration();
1626     timeT t = bars * barDuration + beats * beatDuration + fractions *
1627         Note(Note::Shortest).getDuration() + remainder;
1628     return t;
1629 }
1630 
1631 void
1632 Composition::setPosition(timeT position)
1633 {
1634     m_position = position;
1635 }
1636 
1637 void Composition::setPlayMetronome(bool value)
1638 {
1639     m_playMetronome = value;
1640     notifyMetronomeChanged();
1641 }
1642 
1643 void Composition::setRecordMetronome(bool value)
1644 {
1645     m_recordMetronome = value;
1646     notifyMetronomeChanged();
1647 }
1648 
1649 
1650 
1651 #ifdef TRACK_DEBUG
1652 // track debug convenience function
1653 //
1654 static void dumpTracks(Composition::trackcontainer& tracks)
1655 {
1656     Composition::trackiterator it = tracks.begin();
1657     for (; it != tracks.end(); ++it) {
1658         RG_DEBUG << "tracks[" << (*it).first << "] = " << (*it).second;
1659     }
1660 }
1661 #endif
1662 
1663 Track* Composition::getTrackById(TrackId track) const
1664 {
1665     trackconstiterator i = m_tracks.find(track);
1666 
1667     if (i != m_tracks.end())
1668         return (*i).second;
1669 
1670     RG_WARNING << "getTrackById(" << track << "): WARNING: Track ID not found.";
1671     RG_WARNING << "  Available track ids are:";
1672     for (trackconstiterator i = m_tracks.begin(); i != m_tracks.end(); ++i) {
1673         RG_WARNING << "    " << (int)(*i).second->getId();
1674     }
1675 
1676     return nullptr;
1677 }
1678 
1679 bool
1680 Composition::haveTrack(TrackId track) const
1681 {
1682     trackconstiterator i = m_tracks.find(track);
1683     return (i != m_tracks.end());
1684 }
1685 
1686 #if 0
1687 // unused
1688 // Move a track object to a new id and position in the container -
1689 // used when deleting and undoing deletion of tracks.
1690 //
1691 //
1692 void Composition::resetTrackIdAndPosition(TrackId oldId, TrackId newId,
1693                                           int position)
1694 {
1695     trackiterator titerator = m_tracks.find(oldId);
1696 
1697     if (titerator != m_tracks.end())
1698     {
1699         // detach old track
1700         Track *track = (*titerator).second;
1701         m_tracks.erase(titerator);
1702 
1703         // set new position and
1704         track->setId(newId);
1705         track->setPosition(position);
1706         m_tracks[newId] = track;
1707 
1708         // modify segment mappings
1709         //
1710         for (SegmentMultiSet::const_iterator i = m_segments.begin();
1711              i != m_segments.end(); ++i)
1712         {
1713             if ((*i)->getTrack() == oldId) (*i)->setTrack(newId);
1714         }
1715 
1716         checkSelectedAndRecordTracks();
1717         updateRefreshStatuses();
1718         notifyTrackChanged(getTrackById(newId));
1719     }
1720     else
1721         RG_DEBUG << "resetTrackIdAndPosition() - "
1722                   << "can't move track " << oldId << " to " << newId;
1723 }
1724 #endif
1725 
1726 InstrumentId Composition::getSelectedInstrumentId() const
1727 {
1728     if (m_selectedTrackId == NoTrack)
1729         return NoInstrument;
1730 
1731     Track *track = getTrackById(m_selectedTrackId);
1732 
1733     if (!track)
1734         return NoInstrument;
1735 
1736     return track->getInstrument();
1737 }
1738 
1739 void Composition::setSelectedTrack(TrackId trackId)
1740 {
1741     m_selectedTrackId = trackId;
1742 
1743     // SequenceManager needs to update ControlBlock for auto thru routing
1744     // to work.
1745     notifySelectedTrackChanged();
1746 }
1747 
1748 // Insert a Track representation into the Composition
1749 //
1750 void Composition::addTrack(Track *track)
1751 {
1752     // make sure a track with the same id isn't already there
1753     //
1754     if (m_tracks.find(track->getId()) == m_tracks.end()) {
1755 
1756         m_tracks[track->getId()] = track;
1757         track->setOwningComposition(this);
1758         updateRefreshStatuses();
1759 
1760     } else {
1761         RG_DEBUG << "addTrack("
1762                   << track << "), id = " << track->getId()
1763                   << " - WARNING - track id already present "
1764                   << __FILE__ << ":" << __LINE__;
1765         // throw Exception("track id already present");
1766     }
1767 }
1768 
1769 #if 0
1770 // unused
1771 void Composition::deleteTrack(Rosegarden::TrackId track)
1772 {
1773     trackiterator titerator = m_tracks.find(track);
1774 
1775     if (titerator == m_tracks.end()) {
1776 
1777         RG_DEBUG << "deleteTrack() : no track of id " << track;
1778         throw Exception("track id not found");
1779 
1780     } else {
1781 
1782         delete ((*titerator).second);
1783         m_tracks.erase(titerator);
1784         checkSelectedAndRecordTracks();
1785         updateRefreshStatuses();
1786         notifyTrackDeleted(track);
1787     }
1788 
1789 }
1790 #endif
1791 
1792 bool Composition::detachTrack(Rosegarden::Track *track)
1793 {
1794     trackiterator it = m_tracks.begin();
1795 
1796     for (; it != m_tracks.end(); ++it)
1797     {
1798         if ((*it).second == track)
1799             break;
1800     }
1801 
1802     if (it == m_tracks.end()) {
1803         RG_DEBUG << "detachTrack() : no such track " << track;
1804         throw Exception("track id not found");
1805         return false;
1806     }
1807 
1808     ((*it).second)->setOwningComposition(nullptr);
1809 
1810     m_tracks.erase(it);
1811     updateRefreshStatuses();
1812     checkSelectedAndRecordTracks();
1813 
1814     return true;
1815 }
1816 
1817 void Composition::checkSelectedAndRecordTracks()
1818 {
1819     // reset m_selectedTrackId and m_recordTrack to the next valid track id
1820     // if the track they point to has been deleted
1821 
1822     if (m_tracks.find(m_selectedTrackId) == m_tracks.end()) {
1823 
1824         m_selectedTrackId = getClosestValidTrackId(m_selectedTrackId);
1825 
1826         // SequenceManager needs to update ControlBlock for auto thru routing
1827         // to work.
1828         notifySelectedTrackChanged();
1829 
1830     }
1831 
1832     // For each record track
1833     for (recordtrackcontainer::iterator i = m_recordTracks.begin();
1834          i != m_recordTracks.end(); ) {
1835         // Increment before use.  This way deleting the element does not
1836         // invalidate the iterator.
1837         recordtrackcontainer::iterator j = i++;
1838 
1839         // If the track is no longer in the composition
1840         if (m_tracks.find(*j) == m_tracks.end()) {
1841             // Remove it from the list of record tracks.
1842             m_recordTracks.erase(j);
1843         }
1844     }
1845 }
1846 
1847 TrackId
1848 Composition::getClosestValidTrackId(TrackId id) const
1849 {
1850     long diff = LONG_MAX;
1851     TrackId closestValidTrackId = 0;
1852 
1853     for (trackcontainer::const_iterator i = getTracks().begin();
1854          i != getTracks().end(); ++i) {
1855 
1856         long cdiff = labs(i->second->getId() - id);
1857 
1858         if (cdiff < diff) {
1859             diff = cdiff;
1860             closestValidTrackId = i->second->getId();
1861 
1862         } else break; // std::map is sorted, so if the diff increases, we're passed closest valid id
1863 
1864     }
1865 
1866     return closestValidTrackId;
1867 }
1868 
1869 TrackId
1870 Composition::getMinTrackId() const
1871 {
1872     if (getTracks().size() == 0) return 0;
1873 
1874     trackcontainer::const_iterator i = getTracks().begin();
1875     return i->first;
1876 }
1877 
1878 TrackId
1879 Composition::getMaxTrackId() const
1880 {
1881     if (getTracks().size() == 0) return 0;
1882 
1883     trackcontainer::const_iterator i = getTracks().end();
1884     --i;
1885 
1886     return i->first;
1887 }
1888 
1889 void
1890 Composition::setTrackRecording(TrackId trackId, bool recording)
1891 {
1892     if (recording) {
1893         m_recordTracks.insert(trackId);
1894     } else {
1895         m_recordTracks.erase(trackId);
1896     }
1897 
1898     Track *track = getTrackById(trackId);
1899 
1900     if (!track)
1901         return;
1902 
1903     track->setArmed(recording);
1904 }
1905 
1906 bool
1907 Composition::isTrackRecording(TrackId track) const
1908 {
1909     return m_recordTracks.find(track) != m_recordTracks.end();
1910 }
1911 
1912 bool
1913 Composition::isInstrumentRecording(InstrumentId instrumentID) const
1914 {
1915     // For each Track in the Composition
1916     // ??? Performance: LINEAR SEARCH
1917     //     I see no easy fix.  Each Instrument would need to keep a list
1918     //     of the Tracks it is on.  Or something equally complicated.
1919     for (Composition::trackcontainer::const_iterator ti =
1920              m_tracks.begin();
1921          ti != m_tracks.end();
1922          ++ti) {
1923         Track *track = ti->second;
1924 
1925         // If this Track has this Instrument
1926         if (track->getInstrument() == instrumentID) {
1927             if (isTrackRecording(track->getId())) {
1928                 // Only one Track can be armed per Instrument.  Regardless,
1929                 // we only need to know that a Track is in record mode.
1930                 return true;
1931             }
1932         }
1933     }
1934 
1935     return false;
1936 }
1937 
1938 // Export the Composition as XML, also iterates through
1939 // Tracks and any further sub-objects
1940 //
1941 //
1942 std::string Composition::toXmlString() const
1943 {
1944     std::stringstream composition;
1945 
1946     composition << "<composition recordtracks=\"";
1947     for (recordtrackiterator i = m_recordTracks.begin();
1948          i != m_recordTracks.end(); ) {
1949         composition << *i;
1950         if (++i != m_recordTracks.end()) {
1951             composition << ",";
1952         }
1953     }
1954     composition << "\" pointer=\"" << m_position;
1955     composition << "\" defaultTempo=\"";
1956     composition << std::setiosflags(std::ios::fixed)
1957                 << std::setprecision(4)
1958                 << getTempoQpm(m_defaultTempo);
1959     composition << "\" compositionDefaultTempo=\"";
1960     composition << m_defaultTempo;
1961 
1962     if (m_loopStart != m_loopEnd)
1963     {
1964         composition << "\" loopstart=\"" << m_loopStart;
1965         composition << "\" loopend=\"" << m_loopEnd;
1966     }
1967 
1968     composition << "\" startMarker=\"" << m_startMarker;
1969     composition << "\" endMarker=\"" << m_endMarker;
1970 
1971     if (m_autoExpand)
1972         composition << "\" autoExpand=\"" << m_autoExpand;
1973 
1974     composition << "\" selected=\"" << m_selectedTrackId;
1975     composition << "\" playmetronome=\"" << m_playMetronome;
1976     composition << "\" recordmetronome=\"" << m_recordMetronome;
1977     composition << "\" nexttriggerid=\"" << m_nextTriggerSegmentId;
1978 
1979     // Place the number of the current pan law in the composition tag.
1980     int panLaw = AudioLevel::getPanLaw();
1981     composition << "\" panlaw=\"" << panLaw;
1982 
1983     composition << "\" notationspacing=\"" << m_notationSpacing;
1984 
1985     composition << "\">" << std::endl << std::endl;
1986 
1987     composition << std::endl;
1988 
1989     for (trackconstiterator tit = getTracks().begin();
1990          tit != getTracks().end();
1991          ++tit)
1992         {
1993             if ((*tit).second)
1994                 composition << "  " << (*tit).second->toXmlString() << std::endl;
1995         }
1996 
1997     composition << std::endl;
1998 
1999     for (ReferenceSegment::iterator i = m_timeSigSegment.begin();
2000          i != m_timeSigSegment.end(); ++i) {
2001 
2002         // Might be nice just to stream the events, but that's
2003         // normally done by XmlStorableEvent in gui/ at the
2004         // moment.  Still, this isn't too much of a hardship
2005 
2006         composition << "  <timesignature time=\"" << (*i)->getAbsoluteTime()
2007                     << "\" numerator=\""
2008                     << (*i)->get<Int>(TimeSignature::NumeratorPropertyName)
2009                     << "\" denominator=\""
2010                     << (*i)->get<Int>(TimeSignature::DenominatorPropertyName)
2011                     << "\"";
2012 
2013         bool common = false;
2014         (*i)->get<Bool>(TimeSignature::ShowAsCommonTimePropertyName, common);
2015         if (common) composition << " common=\"true\"";
2016 
2017         bool hidden = false;
2018         (*i)->get<Bool>(TimeSignature::IsHiddenPropertyName, hidden);
2019         if (hidden) composition << " hidden=\"true\"";
2020 
2021         bool hiddenBars = false;
2022         (*i)->get<Bool>(TimeSignature::HasHiddenBarsPropertyName, hiddenBars);
2023         if (hiddenBars) composition << " hiddenbars=\"true\"";
2024 
2025         composition << "/>" << std::endl;
2026     }
2027 
2028     composition << std::endl;
2029 
2030     for (ReferenceSegment::iterator i = m_tempoSegment.begin();
2031          i != m_tempoSegment.end(); ++i) {
2032 
2033         tempoT tempo = tempoT((*i)->get<Int>(TempoProperty));
2034         tempoT target = -1;
2035         if ((*i)->has(TargetTempoProperty)) {
2036             target = tempoT((*i)->get<Int>(TargetTempoProperty));
2037         }
2038         composition << "  <tempo time=\"" << (*i)->getAbsoluteTime()
2039                     << "\" bph=\"" << ((tempo * 6) / 10000)
2040                     << "\" tempo=\"" << tempo;
2041         if (target >= 0) {
2042             composition << "\" target=\"" << target;
2043         }
2044         composition << "\"/>" << std::endl;
2045     }
2046 
2047     composition << std::endl;
2048 
2049     composition << "<metadata>" << std::endl
2050                 << m_metadata.toXmlString() << std::endl
2051                 << "</metadata>" << std::endl << std::endl;
2052 
2053     composition << "<markers>" << std::endl;
2054     for (markerconstiterator mIt = m_markers.begin();
2055          mIt != m_markers.end(); ++mIt)
2056     {
2057         composition << (*mIt)->toXmlString();
2058     }
2059     composition << "</markers>" << std::endl;
2060     composition << "</composition>";
2061 
2062     return composition.str();
2063 }
2064 
2065 void
2066 Composition::clearTracks()
2067 {
2068     trackiterator it = m_tracks.begin();
2069 
2070     for (; it != m_tracks.end(); ++it)
2071         delete ((*it).second);
2072 
2073     m_tracks.erase(m_tracks.begin(), m_tracks.end());
2074 }
2075 
2076 Track*
2077 Composition::getTrackByPosition(int position) const
2078 {
2079     trackconstiterator it = m_tracks.begin();
2080 
2081     for (; it != m_tracks.end(); ++it)
2082     {
2083         if ((*it).second->getPosition() == position)
2084             return (*it).second;
2085     }
2086 
2087     return nullptr;
2088 
2089 }
2090 
2091 int
2092 Composition::getTrackPositionById(TrackId id) const
2093 {
2094     Track *track = getTrackById(id);
2095     if (!track) return -1;
2096     return track->getPosition();
2097 }
2098 
2099 
2100 Rosegarden::TrackId
2101 Composition::getNewTrackId() const
2102 {
2103     // Re BR #1070325: another track deletion problem
2104     // Formerly this was returning the count of tracks currently in
2105     // existence -- returning a duplicate ID if some had been deleted
2106     // from the middle.  Let's find one that's really available instead.
2107 
2108     TrackId highWater = 0;
2109 
2110     trackconstiterator it = m_tracks.begin();
2111 
2112     for (; it != m_tracks.end(); ++it)
2113     {
2114         if ((*it).second->getId() >= highWater)
2115             highWater = (*it).second->getId() + 1;
2116     }
2117 
2118     return highWater;
2119 }
2120 
2121 bool
2122 Composition::hasTrack(InstrumentId instrumentId) const
2123 {
2124     // We don't return the TrackId since an Instrument can be on more than
2125     // one Track.  That would require a std::vector<TrackId>.
2126 
2127     // For each Track
2128     for (trackcontainer::const_iterator trackIter =
2129                  m_tracks.begin();
2130          trackIter != m_tracks.end();
2131          ++trackIter) {
2132 
2133         // If this Track is using the Instrument
2134         if (trackIter->second->getInstrument() == instrumentId)
2135             return true;
2136 
2137     }
2138 
2139     return false;
2140 }
2141 
2142 // Get all the segments that the same instrument plays that plays
2143 // segment s.
2144 // @return a SegmentMultiSet that includes s itself.
2145 SegmentMultiSet
2146 Composition::getInstrumentSegments(Segment *s, timeT t) const
2147 {
2148     SegmentMultiSet segments;
2149     InstrumentId instrumentId = getInstrumentId(s);
2150 
2151     // For each Segment in the Composition...
2152     const SegmentMultiSet& allSegments = getSegments();
2153     for (Composition::iterator i = allSegments.begin();
2154          i != allSegments.end();
2155          ++i)
2156     {
2157         if (((*i)->getStartTime() < t)  &&
2158             (getInstrumentId(*i) == instrumentId)) {
2159             segments.insert(*i);
2160         }
2161     }
2162 
2163     return segments;
2164 }
2165 
2166 void
2167 Composition::enforceArmRule(const Track *track)
2168 {
2169     // No more than one armed track per instrument.
2170 
2171     if (!track->isArmed())
2172         return;
2173 
2174     recordtrackcontainer recordTracks = getRecordTracks();
2175 
2176     // For each track that is armed for record
2177     for (recordtrackcontainer::const_iterator i =
2178             recordTracks.begin();
2179             i != recordTracks.end(); ++i) {
2180 
2181         const TrackId otherTrackId = *i;
2182         Track *otherTrack = getTrackById(otherTrackId);
2183 
2184         if (!otherTrack)
2185             continue;
2186         if (otherTrack == track)
2187             continue;
2188 
2189         // If this track is using the same instrument, unarm it.
2190         if (otherTrack->getInstrument() == track->getInstrument()) {
2191             setTrackRecording(otherTrackId, false);
2192             notifyTrackChanged(otherTrack);
2193         }
2194     }
2195 }
2196 
2197 void
2198 Composition::notifySegmentAdded(Segment *s) const
2199 {
2200     // If there is an earlier repeating segment on the same track, we
2201     // need to notify the change of its repeat end time
2202 
2203     for (const_iterator i = begin(); i != end(); ++i) {
2204 
2205         if (((*i)->getTrack() == s->getTrack())
2206             && ((*i)->isRepeating())
2207             && ((*i)->getStartTime() < s->getStartTime())) {
2208 
2209             notifySegmentRepeatEndChanged(*i, (*i)->getRepeatEndTime());
2210         }
2211     }
2212 
2213     for (ObserverSet::const_iterator i = m_observers.begin();
2214          i != m_observers.end(); ++i) {
2215         (*i)->segmentAdded(this, s);
2216     }
2217 }
2218 
2219 
2220 void
2221 Composition::notifySegmentRemoved(Segment *s) const
2222 {
2223     // If there is an earlier repeating segment on the same track, we
2224     // need to notify the change of its repeat end time
2225 
2226     for (const_iterator i = begin(); i != end(); ++i) {
2227 
2228         if (((*i)->getTrack() == s->getTrack())
2229             && ((*i)->isRepeating())
2230             && ((*i)->getStartTime() < s->getStartTime())) {
2231 
2232             notifySegmentRepeatEndChanged(*i, (*i)->getRepeatEndTime());
2233         }
2234     }
2235 
2236     for (ObserverSet::const_iterator i = m_observers.begin();
2237          i != m_observers.end(); ++i) {
2238         (*i)->segmentRemoved(this, s);
2239     }
2240 }
2241 
2242 void
2243 Composition::notifySegmentRepeatChanged(Segment *s, bool repeat) const
2244 {
2245     for (ObserverSet::const_iterator i = m_observers.begin();
2246          i != m_observers.end(); ++i) {
2247         (*i)->segmentRepeatChanged(this, s, repeat);
2248     }
2249 }
2250 
2251 void
2252 Composition::notifySegmentRepeatEndChanged(Segment *s, timeT t) const
2253 {
2254     for (ObserverSet::const_iterator i = m_observers.begin();
2255          i != m_observers.end(); ++i) {
2256         (*i)->segmentRepeatEndChanged(this, s, t);
2257     }
2258 }
2259 
2260 void
2261 Composition::notifySegmentEventsTimingChanged(Segment *s, timeT delay, RealTime rtDelay) const
2262 {
2263     for (ObserverSet::const_iterator i = m_observers.begin();
2264          i != m_observers.end(); ++i) {
2265         (*i)->segmentEventsTimingChanged(this, s, delay, rtDelay);
2266     }
2267 }
2268 
2269 void
2270 Composition::notifySegmentTransposeChanged(Segment *s, int transpose) const
2271 {
2272     for (ObserverSet::const_iterator i = m_observers.begin();
2273          i != m_observers.end(); ++i) {
2274         (*i)->segmentTransposeChanged(this, s, transpose);
2275     }
2276 }
2277 
2278 void
2279 Composition::notifySegmentTrackChanged(Segment *s, TrackId oldId, TrackId newId) const
2280 {
2281     // If there is an earlier repeating segment on either the
2282     // origin or destination track, we need to notify the change
2283     // of its repeat end time
2284 
2285     for (const_iterator i = begin(); i != end(); ++i) {
2286 
2287         if (((*i)->getTrack() == oldId || (*i)->getTrack() == newId)
2288             && ((*i)->isRepeating())
2289             && ((*i)->getStartTime() < s->getStartTime())) {
2290 
2291             notifySegmentRepeatEndChanged(*i, (*i)->getRepeatEndTime());
2292         }
2293     }
2294 
2295     for (ObserverSet::const_iterator i = m_observers.begin();
2296          i != m_observers.end(); ++i) {
2297         (*i)->segmentTrackChanged(this, s, newId);
2298     }
2299 }
2300 
2301 void
2302 Composition::notifySegmentStartChanged(Segment *s, timeT t)
2303 {
2304     // not ideal, but best way to ensure track heights are recomputed:
2305     clearVoiceCaches();
2306     updateRefreshStatuses();
2307 
2308     // If there is an earlier repeating segment on the same track, we
2309     // need to notify the change of its repeat end time
2310     // (Copied from notifySegmentTrackChanged())
2311     for (const_iterator i = begin(); i != end(); ++i) {
2312         if (((*i)->getTrack() == s->getTrack())
2313             && ((*i)->isRepeating())
2314             && ((*i)->getStartTime() < s->getStartTime())) {
2315 
2316             notifySegmentRepeatEndChanged(*i, (*i)->getRepeatEndTime());
2317         }
2318     }
2319 
2320     for (ObserverSet::const_iterator i = m_observers.begin();
2321          i != m_observers.end(); ++i) {
2322         (*i)->segmentStartChanged(this, s, t);
2323     }
2324 }
2325 
2326 void
2327 Composition::notifySegmentEndMarkerChange(Segment *s, bool shorten)
2328 {
2329     // not ideal, but best way to ensure track heights are recomputed:
2330     clearVoiceCaches();
2331     updateRefreshStatuses();
2332     for (ObserverSet::const_iterator i = m_observers.begin();
2333          i != m_observers.end(); ++i) {
2334         (*i)->segmentEndMarkerChanged(this, s, shorten);
2335     }
2336 }
2337 
2338 void
2339 Composition::notifyEndMarkerChange(bool shorten) const
2340 {
2341     for (ObserverSet::const_iterator i = m_observers.begin();
2342          i != m_observers.end(); ++i) {
2343         (*i)->endMarkerTimeChanged(this, shorten);
2344     }
2345 }
2346 
2347 void
2348 Composition::notifyTrackChanged(Track *t)
2349 {
2350     enforceArmRule(t);
2351 
2352     for (ObserverSet::const_iterator i = m_observers.begin();
2353             i != m_observers.end(); ++i) {
2354         (*i)->trackChanged(this, t);
2355     }
2356 }
2357 
2358 void
2359 Composition::notifyTracksDeleted(std::vector<TrackId> trackIds) const
2360 {
2361     //RG_DEBUG << "Composition::notifyTracksDeleted() notifying" << m_observers.size() << "observers";
2362 
2363     for (ObserverSet::const_iterator i = m_observers.begin();
2364          i != m_observers.end(); ++i) {
2365         (*i)->tracksDeleted(this, trackIds);
2366     }
2367 }
2368 
2369 void
2370 Composition::notifyTracksAdded(std::vector<TrackId> trackIds) const
2371 {
2372     //RG_DEBUG << "Composition::notifyTracksAdded() notifying" << m_observers.size() << "observers";
2373 
2374     for (ObserverSet::const_iterator i = m_observers.begin();
2375          i != m_observers.end(); ++i) {
2376         (*i)->tracksAdded(this, trackIds);
2377     }
2378 }
2379 
2380 void
2381 Composition::notifyTrackSelectionChanged(TrackId t) const
2382 {
2383     for (ObserverSet::const_iterator i = m_observers.begin();
2384          i != m_observers.end(); ++i) {
2385         (*i)->trackSelectionChanged(this, t);
2386     }
2387 }
2388 
2389 void
2390 Composition::notifyMetronomeChanged() const
2391 {
2392     for (ObserverSet::const_iterator i = m_observers.begin();
2393          i != m_observers.end(); ++i) {
2394         (*i)->metronomeChanged(this);
2395     }
2396 }
2397 
2398 void
2399 Composition::notifyTimeSignatureChanged() const
2400 {
2401     for (ObserverSet::const_iterator i = m_observers.begin();
2402          i != m_observers.end(); ++i) {
2403         (*i)->timeSignatureChanged(this);
2404     }
2405 }
2406 
2407 void
2408 Composition::notifyTempoChanged() const
2409 {
2410     for (ObserverSet::const_iterator i = m_observers.begin();
2411          i != m_observers.end(); ++i) {
2412         (*i)->tempoChanged(this);
2413     }
2414 }
2415 
2416 void
2417 Composition::notifySelectedTrackChanged() const
2418 {
2419     for (ObserverSet::const_iterator i = m_observers.begin();
2420          i != m_observers.end(); ++i) {
2421         (*i)->selectedTrackChanged(this);
2422     }
2423 }
2424 
2425 
2426 void
2427 Composition::notifySourceDeletion() const
2428 {
2429     for (ObserverSet::const_iterator i = m_observers.begin();
2430          i != m_observers.end(); ++i) {
2431         (*i)->compositionDeleted(this);
2432     }
2433 }
2434 
2435 
2436 void breakpoint()
2437 {
2438     //RG_DEBUG << "breakpoint()";
2439 }
2440 
2441 // Just empty out the markers
2442 void
2443 Composition::clearMarkers()
2444 {
2445     markerconstiterator it = m_markers.begin();
2446 
2447     for (; it != m_markers.end(); ++it)
2448     {
2449         delete *it;
2450     }
2451 
2452     m_markers.clear();
2453 }
2454 
2455 void
2456 Composition::addMarker(Rosegarden::Marker *marker)
2457 {
2458     m_markers.push_back(marker);
2459     updateRefreshStatuses();
2460 }
2461 
2462 bool
2463 Composition::detachMarker(Rosegarden::Marker *marker)
2464 {
2465     markeriterator it = m_markers.begin();
2466 
2467     for (; it != m_markers.end(); ++it)
2468     {
2469         if (*it == marker)
2470         {
2471             m_markers.erase(it);
2472             updateRefreshStatuses();
2473             return true;
2474         }
2475     }
2476 
2477     return false;
2478 }
2479 
2480 Segment*
2481 Composition::getSegmentByMarking(const QString& marking) const
2482 {
2483     for (SegmentMultiSet::const_iterator i = m_segments.begin();
2484          i != m_segments.end(); ++i) {
2485 
2486         Segment* s = *i;
2487         if (s->getMarking() == marking) {
2488             return s;
2489         }
2490     }
2491     return nullptr;
2492 }
2493 
2494 #if 0
2495 // unused
2496 bool
2497 Composition::isMarkerAtPosition(Rosegarden::timeT time) const
2498 {
2499     markerconstiterator it = m_markers.begin();
2500 
2501     for (; it != m_markers.end(); ++it)
2502         if ((*it)->getTime() == time) return true;
2503 
2504     return false;
2505 }
2506 #endif
2507 
2508 void
2509 Composition::setSegmentColourMap(Rosegarden::ColourMap &newmap)
2510 {
2511     m_segmentColourMap = newmap;
2512 
2513     updateRefreshStatuses();
2514 }
2515 
2516 void
2517 Composition::setGeneralColourMap(Rosegarden::ColourMap &newmap)
2518 {
2519     m_generalColourMap = newmap;
2520 
2521     updateRefreshStatuses();
2522 }
2523 
2524 void
2525 Composition::distributeVerses()
2526 {
2527     typedef std::map<int, SegmentMultiSet> SegmentMap;
2528     SegmentMap tracks;
2529     SegmentMap repeats;
2530 
2531     // Sort segments by track ID
2532     for (iterator i = begin(); i != end(); ++i) {
2533         Segment* s = *i;
2534         tracks[s->getTrack()].insert(s);
2535     }
2536 
2537     // Work track after track
2538     for (SegmentMap::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2539 
2540         // Reset all verse indexes and look for repeated segments
2541         repeats.clear();
2542         for (SegmentMultiSet::iterator j = i->second.begin(); j != i->second.end(); ++j) {
2543              Segment* s = *j;
2544              s->setVerse(0);
2545              if (s->isPlainlyLinked()) {
2546                  repeats[s->getLinker()->getSegmentLinkerId()].insert(s);
2547             }
2548         }
2549 
2550         // Set verse indexes where needed
2551         for (SegmentMap::iterator j = repeats.begin(); j != repeats.end(); ++j) {
2552             int verse = 0;
2553             for (SegmentMultiSet::iterator k = j->second.begin(); k != j->second.end(); ++k) {
2554                 Segment* s = *k;
2555                 s->setVerse(verse++);
2556             }
2557         }
2558     }
2559 }
2560 
2561 void
2562 Composition::dump() const
2563 {
2564     RG_DEBUG << "dump(): Composition segments";
2565 
2566     for (const_iterator i = begin(); i != end(); ++i) {
2567         Segment *s = *i;
2568 
2569         RG_DEBUG << "Segment start : " << s->getStartTime()
2570                 << " - end : " << s->getEndMarkerTime()
2571                 << " - repeating : " << s->isRepeating()
2572                 << " - track id : " << s->getTrack()
2573                 << " - label : " << s->getLabel();
2574                 //<< " - verse : " << s->getVerse()
2575     }
2576 }
2577 
2578 
2579 }
2580