3 using namespace ARDOUR;
8 /* overloaded operator* that avoids floating point math when multiplying a superclock position by a number of quarter notes */
9 superclock_t operator*(superclock_t sc, Evoral::Beats const & b) { return (sc * ((b.get_beats() * Evoral::Beats::PPQN) + b.get_ticks())) / Evoral::Beats::PPQN; }
12 Meter::bbt_add (Timecode::BBT_Time const & bbt, Timecode::BBT_Offset const & add) const
14 int32_t bars = bbt.bars;
15 int32_t beats = bbt.beats;
16 int32_t ticks = bbt.ticks;
18 if ((bars ^ add.bars) < 0) {
19 /* signed-ness varies */
20 if (abs(add.bars) >= abs(bars)) {
21 /* addition will change which side of "zero" the answer is on;
22 adjust bbt.bars towards zero to deal with "unusual" BBT math
32 if ((beats ^ add.beats) < 0) {
33 /* signed-ness varies */
34 if (abs (add.beats) >= abs (beats)) {
35 /* adjust bbt.beats towards zero to deal with "unusual" BBT math */
44 Timecode::BBT_Offset r (bars + add.bars, beats + add.beats, ticks + add.ticks);
46 if (r.ticks >= Evoral::Beats::PPQN) {
47 r.beats += r.ticks / Evoral::Beats::PPQN;
48 r.ticks %= Evoral::Beats::PPQN;
51 if (r.beats > _divisions_per_bar) {
52 r.bars += r.beats / _divisions_per_bar;
53 r.beats %= _divisions_per_bar;
64 return Timecode::BBT_Time (r.bars, r.beats, r.ticks);
68 Meter::bbt_subtract (Timecode::BBT_Time const & bbt, Timecode::BBT_Offset const & sub) const
70 int32_t bars = bbt.bars;
71 int32_t beats = bbt.beats;
72 int32_t ticks = bbt.ticks;
74 if ((bars ^ sub.bars) < 0) {
75 /* signed-ness varies */
76 if (abs (sub.bars) >= abs (bars)) {
77 /* adjust bbt.bars towards zero to deal with "unusual" BBT math */
86 if ((beats ^ sub.beats) < 0) {
87 /* signed-ness varies */
88 if (abs (sub.beats) >= abs (beats)) {
89 /* adjust bbt.beats towards zero to deal with "unusual" BBT math */
98 Timecode::BBT_Offset r (bars - sub.bars, beats - sub.beats, ticks - sub.ticks);
101 r.beats -= 1 - (r.ticks / Evoral::Beats::PPQN);
102 r.ticks = Evoral::Beats::PPQN + (r.ticks % Evoral::Beats::PPQN);
106 r.bars -= 1 - (r.beats / _divisions_per_bar);
107 r.beats = _divisions_per_bar + (r.beats % _divisions_per_bar);
118 return Timecode::BBT_Time (r.bars, r.beats, r.ticks);
122 Meter::bbt_delta (Timecode::BBT_Time const & a, Timecode::BBT_Time const & b) const
124 return Timecode::BBT_Offset (a.bars - b.bars, a.beats - b.beats, a.ticks - b.ticks);
128 Meter::round_up_to_bar (Timecode::BBT_Time const & bbt) const
130 Timecode::BBT_Time b = bbt.round_up_to_beat ();
139 Meter::to_quarters (Timecode::BBT_Offset const & offset) const
143 b += (offset.bars * _divisions_per_bar * 4) / _note_value;
144 b += (offset.beats * 4) / _note_value;
145 b += Evoral::Beats::ticks (offset.ticks);
151 TempoMetric::superclock_per_note_type_at_superclock (superclock_t sc) const
153 return superclocks_per_note_type () * expm1 (_c_per_superclock * sc);
157 TempoMetric::superclocks_per_grid (framecnt_t sr) const
159 return (superclock_ticks_per_second * Meter::note_value()) / (note_types_per_minute() / Tempo::note_type());
163 TempoMetric::superclocks_per_bar (framecnt_t sr) const
165 return superclocks_per_grid (sr) * _divisions_per_bar;
173 Tt----|-----------------*|
174 Ta----|--------------|* |
180 _______________|___|____
181 time a t (next tempo)
184 Duration in beats at time a is the integral of some Tempo function.
185 In our case, the Tempo function (Tempo at time t) is
188 >>1/S(t) = (1/S0)(e^ct) => (1/S)(t) = (e^(ct))/S0 => S(t) = S0/(e^(ct))
190 with function constant
193 >>c = log ((1/Sa)/(1/S0)) / a => c = log (S0/Sa) / a
198 >>a = log ((1/Ta)/(1/S0) / c => a = log (S0/Sa) / c
200 The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
201 b(t) = T0(e^(ct) - 1) / c
203 >>b(t) = 1/S0(e^(ct) - 1) / c => b(t) = (e^(ct) - 1) / (c * S0)
205 To find the time t at beat duration b, we use the inverse function of the beat function (the time function) which can be shown to be:
206 t(b) = log((c.b / T0) + 1) / c
208 >>t(b) = log((c*b / (1/S0)) + 1) / c => t(b) = log ((c*b * S0) + 1) / c
210 The time t at which Tempo T occurs is a as above:
211 t(T) = log(T / T0) / c
213 >> t(1/S) = log ((1/S) / (1/S0) /c => t(1/S) = log (S0/S) / c
215 The beat at which a Tempo T occurs is:
218 >> b(1/S) = (1/S - 1/S0) / c
220 The Tempo at which beat b occurs is:
223 >> T(b) = b.c + (1/S0)
225 We define c for this tempo ramp by placing a new tempo section at some time t after this one.
226 Our problem is that we usually don't know t.
227 We almost always know the duration in beats between this and the new section, so we need to find c in terms of the beat function.
228 Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
229 t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
231 By substituting our expanded t as a in the c function above, our problem is reduced to:
232 c = T0 (e^(log (Ta / T0)) - 1) / b
234 >> c = (1/S0) (e^(log ((1/Sa) / (1/S0))) - 1) / b => c = (1/S0) (e^(log (S0/Sa)) - 1) / b => c (e^(log (S0/Sa)) - 1) / (b * S0)
236 Of course the word 'beat' has been left loosely defined above.
237 In music, a beat is defined by the musical pulse (which comes from the tempo)
238 and the meter in use at a particular time (how many pulse divisions there are in one bar).
239 It would be more accurate to substitute the work 'pulse' for 'beat' above.
243 /* equation to compute c is:
245 * c = log (Ta / T0) / a
249 * a : time into section (from section start
250 * T0 : tempo at start of section
251 * Ta : tempo at time a into section
255 * log (Ta / T0) / (time-units) => C is in per-time-units (1/time-units)
257 * so the question is what are the units of a, and thus c?
259 * we could use ANY time units (because we can measure a in any time units)
260 * but whichever one we pick dictates how we can use c in the future since
261 * all subsequent computations will need to use the same time units.
265 * pulses ... whole notes, possibly useful, since we can use it for any other note_type
266 * quarter notes ... linearly related to pulses
267 * beats ... not a fixed unit of time
268 * minutes ... linearly related to superclocks
269 * samples ... needs sample rate
270 * superclocks ... frequently correct
272 * so one answer might be to compute c in two different units so that we have both available.
274 * hence, compute_c_superclocks() and compute_c_pulses()
278 TempoMetric::compute_c_superclock (framecnt_t sr, superclock_t end_scpqn, superclock_t superclock_duration)
280 if ((superclocks_per_quarter_note() == end_scpqn) || !ramped()) {
281 _c_per_superclock = 0.0;
285 _c_per_superclock = log ((double) superclocks_per_quarter_note () / end_scpqn) / superclock_duration;
288 TempoMetric::compute_c_quarters (framecnt_t sr, superclock_t end_scpqn, Evoral::Beats const & quarter_duration)
290 if ((superclocks_per_quarter_note () == end_scpqn) || !ramped()) {
291 _c_per_quarter = 0.0;
295 _c_per_quarter = log (superclocks_per_quarter_note () / (double) end_scpqn) / quarter_duration.to_double();
299 TempoMetric::superclock_at_qn (Evoral::Beats const & qn) const
301 if (_c_per_quarter == 0.0) {
302 /* not ramped, use linear */
303 return llrint (superclocks_per_quarter_note () * qn.to_double());
306 return llrint (superclocks_per_quarter_note() * (log1p (_c_per_quarter * qn.to_double()) / _c_per_quarter));
310 TempoMapPoint::set_map (TempoMap* m)
316 TempoMapPoint::set_dirty (bool yn)
321 _map->set_dirty (true);
327 TempoMapPoint::quarters_at (superclock_t sc) const
329 /* This TempoMapPoint must already have a fully computed metric and position */
332 return _quarters + Evoral::Beats ((sc - _sclock) / (double) (metric().superclocks_per_quarter_note ()));
335 return _quarters + Evoral::Beats (expm1 (metric().c_per_superclock() * (sc - _sclock)) / (metric().c_per_superclock() * metric().superclocks_per_quarter_note ()));
339 TempoMapPoint::quarters_at (Timecode::BBT_Time const & bbt) const
341 /* This TempoMapPoint must already have a fully computed metric and position */
343 Timecode::BBT_Offset offset = metric().bbt_delta (bbt, _bbt);
344 return _quarters + metric().to_quarters (offset);
348 TempoMapPoint::bbt_at (Evoral::Beats const & qn) const
350 /* This TempoMapPoint must already have a fully computed metric and position */
352 Evoral::Beats quarters_delta = qn - _quarters;
353 int32_t ticks_delta = quarters_delta.to_ticks (Evoral::Beats::PPQN);
354 return metric().bbt_add (_bbt, Timecode::BBT_Offset (0, 0, ticks_delta));
357 TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter, framecnt_t sr)
361 TempoMapPoint tmp (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo), initial_tempo, initial_meter, 0, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
362 _points.push_back (tmp);
366 TempoMap::set_dirty (bool yn)
372 TempoMap::meter_at (superclock_t sc) const
374 Glib::Threads::RWLock::ReaderLock lm (_lock);
375 return meter_at_locked (sc);
379 TempoMap::meter_at (Evoral::Beats const & b) const
381 Glib::Threads::RWLock::ReaderLock lm (_lock);
382 return meter_at_locked (b);
386 TempoMap::meter_at (Timecode::BBT_Time const & bbt) const
388 Glib::Threads::RWLock::ReaderLock lm (_lock);
389 return meter_at_locked (bbt);
393 TempoMap::tempo_at (superclock_t sc) const
395 Glib::Threads::RWLock::ReaderLock lm (_lock);
396 return tempo_at_locked (sc);
400 TempoMap::tempo_at (Evoral::Beats const &b) const
402 Glib::Threads::RWLock::ReaderLock lm (_lock);
403 return tempo_at_locked (b);
407 TempoMap::tempo_at (Timecode::BBT_Time const & bbt) const
409 Glib::Threads::RWLock::ReaderLock lm (_lock);
410 return tempo_at_locked (bbt);
414 TempoMap::rebuild (superclock_t limit)
416 Glib::Threads::RWLock::WriterLock lm (_lock);
418 /* step one: remove all implicit points after a dirty explicit point */
421 TempoMapPoints::iterator tmp = _points.begin();
422 TempoMapPoints::iterator first_explicit_dirty = _points.end();
424 while ((tmp != _points.end()) && (tmp->is_implicit() || (tmp->is_explicit() && !tmp->dirty ()))) {
428 first_explicit_dirty = tmp;
430 if (first_explicit_dirty == _points.end()) {
431 /* nothing is dirty */
435 /* remove all implicit points, because we're going to recalculate them all */
437 while (tmp != _points.end()) {
438 TempoMapPoints::iterator next = tmp;
441 if (tmp->is_implicit()) {
448 /* compute C-by-quarters for all ramped sections, because we need it shortly */
450 for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
451 TempoMapPoints::iterator nxt = tmp;
454 if (tmp->ramped() && (nxt != _points.end())) {
455 tmp->compute_c_quarters (_sample_rate, nxt->metric().superclocks_per_quarter_note (), nxt->quarters() - tmp->quarters());
461 TempoMapPoints::iterator prev = _points.end();
463 /* Compute correct quarter-note and superclock times for all music-time locked explicit points */
465 for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
467 TempoMapPoints::iterator next = tmp;
470 if (prev != _points.end()) {
471 if ((tmp->lock_style() == MusicTime)) {
472 /* determine superclock and quarter note time for this (music-time) locked point */
474 Evoral::Beats qn = prev->quarters_at (tmp->bbt());
475 superclock_t sc = prev->sclock() + prev->metric().superclock_at_qn (qn - prev->quarters());
477 if (qn != tmp->quarters() || tmp->sclock() != sc) {
478 tmp->set_quarters (qn);
479 tmp->set_sclock (sc);
480 _points.sort (TempoMapPoint::SuperClockComparator());
490 /* _points is guaranteed sorted in superclock and quarter note order. It may not be sorted BBT order because of re-ordering
491 * of music-time locked points.
494 prev = _points.end();
496 /* step two: add new implicit points between each pair of explicit
497 * points, after the dirty explicit point
500 bool hit_dirty = false;
501 superclock_t first_dirty = 0;
503 for (tmp = _points.begin(); tmp != _points.end(); ) {
511 first_dirty = tmp->sclock();
514 TempoMapPoints::iterator next = tmp;
518 if (prev != _points.end()) {
519 if ((tmp->lock_style() == AudioTime)) {
520 /* audio-locked explicit point: recompute it's BBT and quarter-note position since this may have changed */
521 tmp->set_quarters (prev->quarters_at (tmp->sclock()));
522 if (static_cast<Meter>(tmp->metric()) != static_cast<Meter>(prev->metric())) {
523 /* new meter, must be on bar/measure start */
524 tmp->set_bbt (prev->metric().round_up_to_bar (prev->bbt_at (tmp->quarters())));
526 /* no meter change, tempo change required to be on beat */
527 tmp->set_bbt (prev->bbt_at (tmp->quarters()).round_up_to_beat());
532 superclock_t sc = tmp->sclock();
533 Evoral::Beats qn (tmp->quarters ());
534 Timecode::BBT_Time bbt (tmp->bbt());
535 const bool ramped = tmp->ramped () && next != _points.end();
537 /* Evoral::Beats are really quarter notes. This counts how many quarter notes
538 there are between grid points in this section of the tempo map.
540 const Evoral::Beats qn_step = (Evoral::Beats (1) * 4) / tmp->metric().note_value();
542 /* compute implicit points as far as the next explicit point, or limit,
543 whichever comes first.
546 const superclock_t sc_limit = (next == _points.end() ? limit : (*next).sclock());
550 /* define next beat in superclocks, beats and bbt */
553 bbt = tmp->metric().bbt_add (bbt, Timecode::BBT_Offset (0, 1, 0));
556 sc += tmp->metric().superclocks_per_note_type();
558 sc = tmp->sclock() + tmp->metric().superclock_at_qn (qn - tmp->quarters());
561 if (sc >= sc_limit) {
565 _points.insert (next, TempoMapPoint (*tmp, sc, qn, bbt));
568 (*tmp).set_dirty (false);
573 Changed (first_dirty, _points.back().sclock()); /* EMIT SIGNAL */
574 cerr << "Rebuilt " << first_dirty << " .. " << _points.back().sclock() << endl;
578 TempoMap::set_tempo_and_meter (Tempo const & tempo, Meter const & meter, superclock_t sc, bool ramp, bool flexible)
580 /* CALLER MUST HOLD LOCK */
582 assert (!_points.empty());
584 /* special case: first map entry is later than the new point */
586 if (_points.front().sclock() > sc) {
587 /* first point is later than sc. There's no iterator to reference a point at or before sc */
589 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
590 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
594 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
595 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
597 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, b, bbt, AudioTime, ramp));
601 /* special case #3: only one map entry, at the same time as the new point.
602 This is the common case when editing tempo/meter in a session with a single tempo/meter
605 if (_points.size() == 1 && _points.front().sclock() == sc) {
607 *((Tempo*) &_points.front().metric()) = tempo;
608 *((Meter*) &_points.front().metric()) = meter;
609 _points.front().make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
613 /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
615 TempoMapPoints::iterator i = iterator_at (sc);
616 TempoMapPoints::iterator nxt = i;
619 if (i->sclock() == sc) {
621 *((Tempo*) &i->metric()) = tempo;
622 *((Meter*) &i->metric()) = meter;
623 i->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
628 if (!flexible && (sc - i->sclock() < i->metric().superclocks_per_note_type())) {
629 cerr << "new tempo too close to previous ...\n";
633 TempoMapPoints::iterator e (i);
634 while (!e->is_explicit() && e != _points.begin()) {
638 if (e->metric().ramped()) {
639 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
640 and thus defines the new ramp distance.
642 e->compute_c_superclock (_sample_rate, tempo.superclocks_per_quarter_note (), sc);
645 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
646 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
650 Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
652 /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
655 Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
657 /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
660 if (i != _points.end()) {
664 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, qn, bbt, AudioTime, ramp));
669 TempoMap::set_tempo (Tempo const & t, superclock_t sc, bool ramp)
671 Glib::Threads::RWLock::WriterLock lm (_lock);
673 assert (!_points.empty());
675 /* special case: first map entry is later than the new point */
677 if (_points.front().sclock() > sc) {
678 /* first point is later than sc. There's no iterator to reference a point at or before sc */
680 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
681 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
685 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
686 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
688 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, t, _points.front().metric(), sc, b, bbt, AudioTime, ramp));
692 /* special case #3: only one map entry, at the same time as the new point.
693 This is the common case when editing tempo/meter in a session with a single tempo/meter
696 if (_points.size() == 1 && _points.front().sclock() == sc) {
698 *((Tempo*) &_points.front().metric()) = t;
699 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
703 /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
705 TempoMapPoints::iterator i = iterator_at (sc);
706 TempoMapPoints::iterator nxt = i;
709 if (i->sclock() == sc) {
711 *((Tempo*) &i->metric()) = t;
712 i->make_explicit (TempoMapPoint::ExplicitTempo);
717 if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
718 cerr << "new tempo too close to previous ...\n";
722 Meter const & meter (i->metric());
724 TempoMapPoints::iterator e (i);
725 while (!e->is_explicit() && e != _points.begin()) {
729 if (e->metric().ramped()) {
730 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
731 and thus defines the new ramp distance.
733 e->compute_c_superclock (_sample_rate, t.superclocks_per_quarter_note (), sc);
736 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
737 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
741 Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
743 /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
746 Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
748 /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
751 if (i != _points.end()) {
754 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, sc, qn, bbt, AudioTime, ramp));
759 TempoMap::set_tempo (Tempo const & t, Timecode::BBT_Time const & bbt, bool ramp)
761 Glib::Threads::RWLock::WriterLock lm (_lock);
763 /* tempo changes are required to be on-beat */
765 Timecode::BBT_Time on_beat = bbt.round_up_to_beat();
767 assert (!_points.empty());
769 if (_points.front().bbt() > on_beat) {
770 cerr << "Cannot insert tempo at " << bbt << " before first point at " << _points.front().bbt() << endl;
774 if (_points.size() == 1 && _points.front().bbt() == on_beat) {
776 *((Tempo*) &_points.front().metric()) = t;
777 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
781 TempoMapPoints::iterator i = iterator_at (on_beat);
783 if (i->bbt() == on_beat) {
784 *((Tempo*) &i->metric()) = t;
785 i->make_explicit (TempoMapPoint::ExplicitTempo);
789 Meter const & meter (i->metric());
792 /* stick a prototype music-locked point up front and let ::rebuild figure out the superclock and quarter time */
793 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, 0, Evoral::Beats(), on_beat, MusicTime, ramp));
798 TempoMap::set_meter (Meter const & m, Timecode::BBT_Time const & bbt)
800 Glib::Threads::RWLock::WriterLock lm (_lock);
801 Timecode::BBT_Time measure_start (m.round_up_to_bar (bbt));
803 assert (!_points.empty());
805 if (_points.front().bbt() > measure_start) {
806 cerr << "Cannot insert meter at " << bbt << " before first point at " << _points.front().bbt() << endl;
810 if (_points.size() == 1 && _points.front().bbt() == measure_start) {
812 *((Meter*) &_points.front().metric()) = m;
813 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
817 TempoMapPoints::iterator i = iterator_at (measure_start);
819 if (i->bbt() == measure_start) {
820 *((Meter*) &i->metric()) = m;
821 i->make_explicit (TempoMapPoint::ExplicitMeter);
825 Evoral::Beats qn = i->quarters_at (measure_start);
826 superclock_t sc = i->sclock() + i->metric().superclock_at_qn (qn);
828 Tempo const & tempo (i->metric());
831 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime));
836 TempoMap::set_meter (Meter const & m, superclock_t sc)
838 Glib::Threads::RWLock::WriterLock lm (_lock);
839 assert (!_points.empty());
841 /* special case #2: first map entry is later than the new point */
843 if (_points.front().sclock() > sc) {
844 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
845 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
849 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
850 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
852 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitMeter, _points.front().metric(), m, sc, b, bbt, AudioTime));
856 /* special case #3: only one map entry, at the same time as the new point.
858 This is the common case when editing tempo/meter in a session with a single tempo/meter
861 if (_points.size() == 1 && _points.front().sclock() == sc) {
863 *((Meter*) &_points.front().metric()) = m;
864 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
868 TempoMapPoints::iterator i = iterator_at (sc);
870 if (i->sclock() == sc) {
872 *((Meter*) &i->metric()) = m;
874 /* enforce rule described below regarding meter change positions */
876 if (i->bbt().beats != 1) {
877 i->set_bbt (Timecode::BBT_Time (i->bbt().bars + 1, 1, 0));
880 i->make_explicit (TempoMapPoint::ExplicitMeter);
885 if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
886 cerr << "new tempo too close to previous ...\n";
890 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
891 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
895 Evoral::Beats b = i->quarters_at (sc).round_to_beat();
897 /* rule: all Meter changes must start a new measure. So determine the nearest, lower beat to "sc". If this is not
898 the first division of the measure, move to the next measure.
901 Timecode::BBT_Time bbt = i->bbt_at (b).round_down_to_beat ();
903 if (bbt.beats != 1) {
909 Tempo const & tempo (i->metric());
912 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, b, bbt, AudioTime));
916 TempoMapPoints::iterator
917 TempoMap::iterator_at (superclock_t sc)
919 /* CALLER MUST HOLD LOCK */
921 if (_points.empty()) {
922 throw EmptyTempoMapException();
925 if (_points.size() == 1) {
926 return _points.begin();
929 /* Construct an arbitrary TempoMapPoint. The only property we care about is it's superclock time,
930 so other values used in the constructor are arbitrary and irrelevant.
933 TempoMetric const & metric (_points.front().metric());
934 const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, sc, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
935 TempoMapPoint::SuperClockComparator scmp;
937 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, scmp);
939 if (tmp != _points.begin()) {
946 TempoMapPoints::iterator
947 TempoMap::iterator_at (Evoral::Beats const & qn)
949 /* CALLER MUST HOLD LOCK */
951 if (_points.empty()) {
952 throw EmptyTempoMapException();
955 if (_points.size() == 1) {
956 return _points.begin();
959 /* Construct an arbitrary TempoMapPoint. The only property we care about is its quarters time,
960 so other values used in the constructor are arbitrary and irrelevant.
963 TempoMetric const & metric (_points.front().metric());
964 const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, 0, qn, Timecode::BBT_Time(), AudioTime);
965 TempoMapPoint::QuarterComparator bcmp;
967 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
969 if (tmp != _points.begin()) {
976 TempoMapPoints::iterator
977 TempoMap::iterator_at (Timecode::BBT_Time const & bbt)
979 /* CALLER MUST HOLD LOCK */
981 if (_points.empty()) {
982 throw EmptyTempoMapException();
985 if (_points.size() == 1) {
986 return _points.begin();
989 /* Construct an arbitrary TempoMapPoint. The only property we care about is its bbt time,
990 so other values used in the constructor are arbitrary and irrelevant.
993 TempoMetric const & metric (_points.front().metric());
994 const TempoMapPoint tp (TempoMapPoint::Flag(0), metric, metric, 0, Evoral::Beats(), bbt, MusicTime);
995 TempoMapPoint::BBTComparator bcmp;
997 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
999 if (tmp != _points.begin()) {
1007 TempoMap::bbt_at (superclock_t sc) const
1009 Glib::Threads::RWLock::ReaderLock lm (_lock);
1010 return bbt_at_locked (sc);
1014 TempoMap::bbt_at_locked (superclock_t sc) const
1016 TempoMapPoint point (const_point_at (sc));
1017 Evoral::Beats b ((sc - point.sclock()) / (double) point.metric().superclocks_per_quarter_note());
1018 return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, b.get_beats(), b.get_ticks()));
1022 TempoMap::bbt_at (Evoral::Beats const & qn) const
1024 Glib::Threads::RWLock::ReaderLock lm (_lock);
1025 return bbt_at_locked (qn);
1029 TempoMap::bbt_at_locked (Evoral::Beats const & qn) const
1031 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1032 TempoMapPoint const & point (const_point_at (qn));
1033 Evoral::Beats delta (qn - point.quarters());
1034 return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, delta.get_beats(), delta.get_ticks()));
1038 TempoMap::superclock_at (Evoral::Beats const & qn) const
1040 Glib::Threads::RWLock::ReaderLock lm (_lock);
1041 return superclock_at_locked (qn);
1045 TempoMap::superclock_at_locked (Evoral::Beats const & qn) const
1047 assert (!_points.empty());
1049 /* only the quarters property matters, since we're just using it to compare */
1050 const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, qn, Timecode::BBT_Time(), MusicTime);
1051 TempoMapPoint::QuarterComparator bcmp;
1053 TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1055 if (i == _points.end()) {
1059 /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1061 const Evoral::Beats q_delta = qn - i->quarters();
1062 superclock_t sclock_delta = i->metric().superclock_at_qn (q_delta);
1063 return i->sclock() + sclock_delta;
1067 TempoMap::superclock_at (Timecode::BBT_Time const & bbt) const
1069 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1070 return superclock_at_locked (bbt);
1074 TempoMap::superclock_at_locked (Timecode::BBT_Time const & bbt) const
1076 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1077 assert (!_points.empty());
1079 /* only the bbt property matters, since we're just using it to compare */
1080 const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, Evoral::Beats(), bbt, MusicTime);
1081 TempoMapPoint::BBTComparator bcmp;
1083 TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1085 if (i == _points.end()) {
1089 /* this computes the distance from the point, in beats whose size is
1090 determined by the meter.
1093 const Timecode::BBT_Offset delta = i->metric().bbt_delta (bbt, i->bbt());
1095 /* convert to quarter notes */
1096 const int32_t ticks = delta.ticks + (Evoral::Beats::PPQN * delta.beats * 4) / i->metric().note_value();
1098 /* get distance in superclocks */
1099 return i->sclock() + i->metric().superclock_at_qn (Evoral::Beats::ticks (ticks));
1103 TempoMap::set_sample_rate (framecnt_t new_sr)
1105 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1106 double ratio = new_sr / (double) _sample_rate;
1108 for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1109 i->map_reset_set_sclock_for_sr_change (llrint (ratio * i->sclock()));
1114 TempoMap::dump (std::ostream& ostr)
1116 Glib::Threads::RWLock::ReaderLock lm (_lock);
1121 TempoMap::dump_locked (std::ostream& ostr)
1123 ostr << "\n\n------------\n";
1124 for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1125 ostr << *i << std::endl;
1130 TempoMap::remove_explicit_point (superclock_t sc)
1132 Glib::Threads::RWLock::WriterLock lm (_lock);
1133 TempoMapPoints::iterator p = iterator_at (sc);
1135 if (p->sclock() == sc) {
1141 TempoMap::move_to (superclock_t current, superclock_t destination, bool push)
1143 Glib::Threads::RWLock::WriterLock lm (_lock);
1144 TempoMapPoints::iterator p = iterator_at (current);
1146 if (p->sclock() != current) {
1147 cerr << "No point @ " << current << endl;
1151 /* put a "dirty" flag in at the nearest explicit point to the removal point
1154 if (p != _points.begin()) {
1155 TempoMapPoints::iterator prev (p);
1157 while (prev != _points.begin() && !prev->is_explicit()) {
1160 prev->set_dirty (true);
1162 TempoMapPoints::iterator nxt (p);
1164 while (nxt != _points.end() && !nxt->is_explicit()) {
1167 if (nxt != _points.end()) {
1168 nxt->set_dirty (true);
1172 if (!set_tempo_and_meter (p->metric(), p->metric(), destination, p->ramped(), true)) {
1178 p = iterator_at (destination);
1181 const superclock_t delta = destination - current;
1183 while (p != _points.end()) {
1184 p->set_sclock (p->sclock() + delta);
1195 TempoMap::get_grid (TempoMapPoints& ret, superclock_t start, superclock_t end, Evoral::Beats const & resolution)
1197 Glib::Threads::RWLock::ReaderLock lm (_lock);
1198 TempoMapPoints::iterator p = iterator_at (start);
1200 while (p != _points.end() && p->sclock() < start) {
1204 if (resolution == Evoral::Beats()) {
1205 /* just hand over the points as-is */
1206 while (p != _points.end() && p->sclock() < end) {
1213 superclock_t pos = p->sclock();
1215 TempoMapPoints::iterator nxt = p;
1218 while ((p != _points.end()) && (pos < end)) {
1219 /* recompute grid down to @param resolution level
1222 superclock_t sclock_delta = p->metric().superclock_at_qn (qpos);
1224 ret.push_back (TempoMapPoint (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo),
1225 p->metric(), p->metric(),
1226 p->sclock() + sclock_delta,
1227 p->quarters() + qpos,
1228 p->metric().bbt_add (p->bbt(), Timecode::BBT_Offset (0, qpos.get_beats(), qpos.get_ticks())),
1233 pos += sclock_delta;
1235 if (pos >= nxt->sclock()) {
1244 TempoMap::get_bar_grid (TempoMapPoints& ret, superclock_t start, superclock_t end, int32_t bar_gap)
1246 Glib::Threads::RWLock::ReaderLock lm (_lock);
1248 for (TempoMapPoints::iterator p = iterator_at (start); (p != _points.end()) && (p->sclock() < end); ++p) {
1250 if ((p->sclock() >= start) && (p->bbt().beats == 1) && ((p->bbt().bars == 1) || (p->bbt().bars % bar_gap == 0))) {
1251 ret.push_back (TempoMapPoint (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo),
1252 p->metric(), p->metric(),
1263 operator<<(std::ostream& str, Meter const & m)
1265 return str << m.divisions_per_bar() << '/' << m.note_value();
1269 operator<<(std::ostream& str, Tempo const & t)
1271 return str << t.note_types_per_minute() << " 1/" << t.note_type() << " notes per minute (" << t.superclocks_per_note_type() << " sc-per-1/" << t.note_type() << ')';
1275 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1277 str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
1278 << (tmp.is_explicit() ? " EXP" : " imp")
1279 << " qn " << tmp.quarters ()
1280 << " bbt " << tmp.bbt()
1281 << " lock to " << tmp.lock_style()
1284 if (tmp.is_explicit()) {
1285 str << " tempo " << *((Tempo*) &tmp.metric())
1286 << " meter " << *((Meter*) &tmp.metric())
1290 if (tmp.is_explicit() && tmp.ramped()) {
1291 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();
1298 #define SAMPLERATE 48000
1299 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1308 using namespace Timecode;
1311 BBT_Time b1 (1,1,1919);
1312 BBT_Time n1 (-1,1,1919);
1313 std::vector<Meter> meters;
1315 meters.push_back (Meter (4, 4));
1316 meters.push_back (Meter (5, 8));
1317 meters.push_back (Meter (11, 7));
1318 meters.push_back (Meter (3, 4));
1320 #define PRINT_RESULT(m,str,op,op1,Bars,Beats,Ticks) cout << m << ' ' << (op1) << ' ' << str << ' ' << BBT_Offset ((Bars),(Beats),(Ticks)) << " = " << m.op ((op1), BBT_Offset ((Bars), (Beats), (Ticks))) << endl;
1322 for (std::vector<Meter>::iterator m = meters.begin(); m != meters.end(); ++m) {
1323 for (int B = 1; B < 4; ++B) {
1324 for (int b = 1; b < 13; ++b) {
1325 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 0);
1326 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 1);
1327 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN/2);
1328 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN);
1329 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 1);
1330 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 2);
1332 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 0);
1333 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 1);
1334 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN/2);
1335 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN);
1336 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 1);
1337 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 2);
1339 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 0);
1340 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 1);
1341 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN/2);
1342 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN);
1343 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 1);
1344 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 2);
1348 for (int B = 1; B < 4; ++B) {
1349 for (int b = 1; b < 13; ++b) {
1350 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 0);
1351 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 1);
1352 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN/2);
1353 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN);
1354 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 1);
1355 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 2);
1364 TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1369 tmap.set_tempo (Tempo (7), SECONDS_TO_SUPERCLOCK(7));
1370 tmap.set_tempo (Tempo (23), SECONDS_TO_SUPERCLOCK(23));
1371 tmap.set_tempo (Tempo (24), SECONDS_TO_SUPERCLOCK(24), true);
1372 tmap.set_tempo (Tempo (40), SECONDS_TO_SUPERCLOCK(28), true);
1373 tmap.set_tempo (Tempo (100), SECONDS_TO_SUPERCLOCK(100));
1374 tmap.set_tempo (Tempo (123), SECONDS_TO_SUPERCLOCK(23));
1376 tmap.set_meter (Meter (3, 4), SECONDS_TO_SUPERCLOCK(23));
1377 tmap.set_meter (Meter (5, 8), SECONDS_TO_SUPERCLOCK(100));
1378 tmap.set_meter (Meter (5, 7), SECONDS_TO_SUPERCLOCK(7));
1379 tmap.set_meter (Meter (4, 4), SECONDS_TO_SUPERCLOCK(24));
1380 tmap.set_meter (Meter (11, 7), SECONDS_TO_SUPERCLOCK(23));
1382 tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1384 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1385 tmap.dump (std::cout);
1387 if (tmap.move_to (SECONDS_TO_SUPERCLOCK(23), SECONDS_TO_SUPERCLOCK (72))) {
1388 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1389 tmap.dump (std::cout);
1392 TempoMapPoints grid;
1393 tmap.get_grid (grid, SECONDS_TO_SUPERCLOCK (12.3), SECONDS_TO_SUPERCLOCK (44), Evoral::Beats::ticks ((Evoral::Beats::PPQN * 4) / 12));
1394 cout << "grid contains " << grid.size() << endl;
1395 for (TempoMapPoints::iterator p = grid.begin(); p != grid.end(); ++p) {
1399 TempoMapPoints bbt_grid;
1400 tmap.get_bar_grid (bbt_grid, SECONDS_TO_SUPERCLOCK (0), SECONDS_TO_SUPERCLOCK (100), 4);
1401 cout << "bbt_grid contains " << bbt_grid.size() << endl;
1402 for (TempoMapPoints::iterator p = bbt_grid.begin(); p != bbt_grid.end(); ++p) {