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