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 cerr << offset.bars << " bars as quarters : " << b << " nv = " << (int) _note_value << endl;
145 b += (offset.beats * 4) / _note_value;
146 cerr << offset.beats << " beats as quarters : " << (offset.beats * 4) / _note_value << " nv = " << (int) _note_value << endl;
147 b += Evoral::Beats::ticks (offset.ticks);
153 TempoMetric::superclock_per_note_type_at_superclock (superclock_t sc) const
155 return superclocks_per_note_type () * expm1 (_c_per_superclock * sc);
159 TempoMetric::superclocks_per_grid (framecnt_t sr) const
161 return (superclock_ticks_per_second * Meter::note_value()) / (note_types_per_minute() / Tempo::note_type());
165 TempoMetric::superclocks_per_bar (framecnt_t sr) const
167 return superclocks_per_grid (sr) * _divisions_per_bar;
175 Tt----|-----------------*|
176 Ta----|--------------|* |
182 _______________|___|____
183 time a t (next tempo)
186 Duration in beats at time a is the integral of some Tempo function.
187 In our case, the Tempo function (Tempo at time t) is
190 >>1/S(t) = (1/S0)(e^ct) => (1/S)(t) = (e^(ct))/S0 => S(t) = S0/(e^(ct))
192 with function constant
195 >>c = log ((1/Sa)/(1/S0)) / a => c = log (S0/Sa) / a
200 >>a = log ((1/Ta)/(1/S0) / c => a = log (S0/Sa) / c
202 The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
203 b(t) = T0(e^(ct) - 1) / c
205 >>b(t) = 1/S0(e^(ct) - 1) / c => b(t) = (e^(ct) - 1) / (c * S0)
207 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:
208 t(b) = log((c.b / T0) + 1) / c
210 >>t(b) = log((c*b / (1/S0)) + 1) / c => t(b) = log ((c*b * S0) + 1) / c
212 The time t at which Tempo T occurs is a as above:
213 t(T) = log(T / T0) / c
215 >> t(1/S) = log ((1/S) / (1/S0) /c => t(1/S) = log (S0/S) / c
217 The beat at which a Tempo T occurs is:
220 >> b(1/S) = (1/S - 1/S0) / c
222 The Tempo at which beat b occurs is:
225 >> T(b) = b.c + (1/S0)
227 We define c for this tempo ramp by placing a new tempo section at some time t after this one.
228 Our problem is that we usually don't know t.
229 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.
230 Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
231 t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
233 By substituting our expanded t as a in the c function above, our problem is reduced to:
234 c = T0 (e^(log (Ta / T0)) - 1) / b
236 >> 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)
238 Of course the word 'beat' has been left loosely defined above.
239 In music, a beat is defined by the musical pulse (which comes from the tempo)
240 and the meter in use at a particular time (how many pulse divisions there are in one bar).
241 It would be more accurate to substitute the work 'pulse' for 'beat' above.
245 /* equation to compute c is:
247 * c = log (Ta / T0) / a
251 * a : time into section (from section start
252 * T0 : tempo at start of section
253 * Ta : tempo at time a into section
257 * log (Ta / T0) / (time-units) => C is in per-time-units (1/time-units)
259 * so the question is what are the units of a, and thus c?
261 * we could use ANY time units (because we can measure a in any time units)
262 * but whichever one we pick dictates how we can use c in the future since
263 * all subsequent computations will need to use the same time units.
267 * pulses ... whole notes, possibly useful, since we can use it for any other note_type
268 * quarter notes ... linearly related to pulses
269 * beats ... not a fixed unit of time
270 * minutes ... linearly related to superclocks
271 * samples ... needs sample rate
272 * superclocks ... frequently correct
274 * so one answer might be to compute c in two different units so that we have both available.
276 * hence, compute_c_superclocks() and compute_c_pulses()
280 TempoMetric::compute_c_superclock (framecnt_t sr, superclock_t end_scpqn, superclock_t superclock_duration)
282 if ((superclocks_per_quarter_note() == end_scpqn) || !ramped()) {
283 _c_per_superclock = 0.0;
287 _c_per_superclock = log ((double) superclocks_per_quarter_note () / end_scpqn) / superclock_duration;
290 TempoMetric::compute_c_quarters (framecnt_t sr, superclock_t end_scpqn, Evoral::Beats const & quarter_duration)
292 if ((superclocks_per_quarter_note () == end_scpqn) || !ramped()) {
293 _c_per_quarter = 0.0;
297 _c_per_quarter = log (superclocks_per_quarter_note () / (double) end_scpqn) / quarter_duration.to_double();
301 TempoMetric::superclock_at_qn (Evoral::Beats const & qn) const
303 if (_c_per_quarter == 0.0) {
304 /* not ramped, use linear */
305 return llrint (superclocks_per_quarter_note () * qn.to_double());
308 return llrint (superclocks_per_quarter_note() * (log1p (_c_per_quarter * qn.to_double()) / _c_per_quarter));
312 TempoMapPoint::quarters_at (superclock_t sc) const
314 /* This TempoMapPoint must already have a fully computed metric and position */
317 return _quarters + Evoral::Beats ((sc - _sclock) / (double) (metric().superclocks_per_quarter_note ()));
320 return _quarters + Evoral::Beats (expm1 (metric().c_per_superclock() * (sc - _sclock)) / (metric().c_per_superclock() * metric().superclocks_per_quarter_note ()));
324 TempoMapPoint::quarters_at (Timecode::BBT_Time const & bbt) const
326 /* This TempoMapPoint must already have a fully computed metric and position */
328 Timecode::BBT_Offset offset = metric().bbt_delta (bbt, _bbt);
329 cerr << "QA BBT DELTA between " << bbt << " and " << _bbt << " = " << offset << " as quarters for " << static_cast<Meter> (metric()) << " = " << metric().to_quarters (offset) << endl;
330 return _quarters + metric().to_quarters (offset);
334 TempoMapPoint::bbt_at (Evoral::Beats const & qn) const
336 /* This TempoMapPoint must already have a fully computed metric and position */
338 Evoral::Beats quarters_delta = qn - _quarters;
339 int32_t ticks_delta = quarters_delta.to_ticks (Evoral::Beats::PPQN);
340 return metric().bbt_add (_bbt, Timecode::BBT_Offset (0, 0, ticks_delta));
343 TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter, framecnt_t sr)
346 TempoMapPoint tmp (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo), initial_tempo, initial_meter, 0, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
347 _points.push_back (tmp);
351 TempoMap::meter_at (superclock_t sc) const
353 Glib::Threads::RWLock::ReaderLock lm (_lock);
354 return meter_at_locked (sc);
358 TempoMap::meter_at (Evoral::Beats const & b) const
360 Glib::Threads::RWLock::ReaderLock lm (_lock);
361 return meter_at_locked (b);
365 TempoMap::meter_at (Timecode::BBT_Time const & bbt) const
367 Glib::Threads::RWLock::ReaderLock lm (_lock);
368 return meter_at_locked (bbt);
372 TempoMap::tempo_at (superclock_t sc) const
374 Glib::Threads::RWLock::ReaderLock lm (_lock);
375 return tempo_at_locked (sc);
379 TempoMap::tempo_at (Evoral::Beats const &b) const
381 Glib::Threads::RWLock::ReaderLock lm (_lock);
382 return tempo_at_locked (b);
386 TempoMap::tempo_at (Timecode::BBT_Time const & bbt) const
388 Glib::Threads::RWLock::ReaderLock lm (_lock);
389 return tempo_at_locked (bbt);
393 TempoMap::rebuild (superclock_t limit)
395 Glib::Threads::RWLock::WriterLock lm (_lock);
396 rebuild_locked (limit);
400 TempoMap::rebuild_locked (superclock_t limit)
402 /* step one: remove all implicit points after a dirty explicit point */
405 TempoMapPoints::iterator tmp = _points.begin();
406 TempoMapPoints::iterator first_explicit_dirty = _points.end();
408 while ((tmp != _points.end()) && (tmp->is_implicit() || (tmp->is_explicit() && !tmp->dirty ()))) {
412 first_explicit_dirty = tmp;
414 /* remove all implicit points, because we're going to recalculate them all */
416 while (tmp != _points.end()) {
417 TempoMapPoints::iterator next = tmp;
420 if (tmp->is_implicit()) {
427 /* compute C for all ramped sections */
429 for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
430 TempoMapPoints::iterator nxt = tmp;
433 if (tmp->ramped() && (nxt != _points.end())) {
434 tmp->compute_c_quarters (_sample_rate, nxt->metric().superclocks_per_quarter_note (), nxt->quarters() - tmp->quarters());
440 TempoMapPoints::iterator prev = _points.end();
442 /* Compute correct quarter-note and superclock times for all music-time locked explicit points */
444 for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
446 TempoMapPoints::iterator next = tmp;
449 if (prev != _points.end()) {
450 if ((tmp->lock_style() == MusicTime)) {
451 /* determine superclock and quarter note time for this (music-time) locked point */
453 cerr << "MT-lock, prev = " << *prev << endl;
455 Evoral::Beats qn = prev->quarters_at (tmp->bbt());
456 cerr << "MT-lock @ " << tmp->bbt() << " => " << qn << endl;
457 superclock_t sc = prev->sclock() + prev->metric().superclock_at_qn (qn - prev->quarters());
458 cerr << "MT-lock sc is " << prev->metric().superclock_at_qn (qn - prev->quarters()) << " after " << prev->sclock() << " = " << sc
459 << " secs = " << prev->metric().superclock_at_qn (qn - prev->quarters()) / (double) superclock_ticks_per_second
462 if (qn != tmp->quarters() || tmp->sclock() != sc) {
463 cerr << "Ned to move " << *tmp << endl;
464 tmp->set_quarters (qn);
465 tmp->set_sclock (sc);
466 cerr << "using " << *prev << " moved music-time-locked @ " << tmp->bbt() << " to " << sc << " aka " << qn << endl;
467 _points.sort (TempoMapPoint::SuperClockComparator());
478 /* _points is guaranteed sorted in superclock and quarter note order. It may not be sorted BBT order because of re-ordering
479 * of music-time locked points.
482 cerr << "POST-SORT\n";
485 prev = _points.end();
487 /* step two: add new implicit points between each pair of explicit
488 * points, after the dirty explicit point
491 for (tmp = _points.begin(); tmp != _points.end(); ) {
498 TempoMapPoints::iterator next = tmp;
501 if (prev != _points.end()) {
502 if ((tmp->lock_style() == AudioTime)) {
503 cerr << "AT: check " << *tmp << endl
504 << "\t\tusing " << *prev << endl;
505 /* audio-locked explicit point: recompute it's BBT and quarter-note position since this may have changed */
506 tmp->set_quarters (prev->quarters_at (tmp->sclock()));
507 cerr << "AT - recompute quarters at " << tmp->quarters () << endl;
508 if (static_cast<Meter>(tmp->metric()) != static_cast<Meter>(prev->metric())) {
509 /* new meter, must be on bar/measure start */
510 tmp->set_bbt (prev->metric().round_up_to_bar (prev->bbt_at (tmp->quarters())));
512 /* no meter change, tempo change required to be on beat */
513 tmp->set_bbt (prev->bbt_at (tmp->quarters()).round_up_to_beat());
515 cerr << "AT - recompute bbt at " << tmp->bbt () << endl;
519 superclock_t sc = tmp->sclock();
520 Evoral::Beats qn (tmp->quarters ());
521 Timecode::BBT_Time bbt (tmp->bbt());
522 const bool ramped = tmp->ramped () && next != _points.end();
524 /* Evoral::Beats are really quarter notes. This counts how many quarter notes
525 there are between grid points in this section of the tempo map.
527 const Evoral::Beats qn_step = (Evoral::Beats (1) * 4) / tmp->metric().note_value();
529 /* compute implicit points as far as the next explicit point, or limit,
530 whichever comes first.
533 const superclock_t sc_limit = (next == _points.end() ? limit : (*next).sclock());
537 /* define next beat in superclocks, beats and bbt */
540 bbt = tmp->metric().bbt_add (bbt, Timecode::BBT_Offset (0, 1, 0));
543 sc += tmp->metric().superclocks_per_note_type();
545 sc = tmp->sclock() + tmp->metric().superclock_at_qn (qn - tmp->quarters());
548 if (sc >= sc_limit) {
552 _points.insert (next, TempoMapPoint (*tmp, sc, qn, bbt));
555 (*tmp).set_dirty (false);
562 TempoMap::set_tempo_and_meter (Tempo const & tempo, Meter const & meter, superclock_t sc, bool ramp, bool flexible)
564 /* CALLER MUST HOLD LOCK */
566 assert (!_points.empty());
568 /* special case: first map entry is later than the new point */
570 if (_points.front().sclock() > sc) {
571 /* first point is later than sc. There's no iterator to reference a point at or before sc */
573 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
574 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
578 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
579 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
581 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, b, bbt, AudioTime, ramp));
585 /* special case #3: only one map entry, at the same time as the new point.
586 This is the common case when editing tempo/meter in a session with a single tempo/meter
589 if (_points.size() == 1 && _points.front().sclock() == sc) {
591 *((Tempo*) &_points.front().metric()) = tempo;
592 *((Meter*) &_points.front().metric()) = meter;
593 _points.front().make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
597 /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
599 TempoMapPoints::iterator i = iterator_at (sc);
600 TempoMapPoints::iterator nxt = i;
603 if (i->sclock() == sc) {
605 *((Tempo*) &i->metric()) = tempo;
606 *((Meter*) &i->metric()) = meter;
607 i->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
612 if (!flexible && (sc - i->sclock() < i->metric().superclocks_per_note_type())) {
613 cerr << "new tempo too close to previous ...\n";
617 TempoMapPoints::iterator e (i);
618 while (!e->is_explicit() && e != _points.begin()) {
622 if (e->metric().ramped()) {
623 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
624 and thus defines the new ramp distance.
626 e->compute_c_superclock (_sample_rate, tempo.superclocks_per_quarter_note (), sc);
629 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
630 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
634 Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
636 /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
639 Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
641 /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
644 if (i != _points.end()) {
648 cerr << "Insert at " << i->sclock() / superclock_ticks_per_second << endl;
649 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, qn, bbt, AudioTime, ramp));
654 TempoMap::set_tempo (Tempo const & t, superclock_t sc, bool ramp)
656 Glib::Threads::RWLock::WriterLock lm (_lock);
658 assert (!_points.empty());
660 /* special case: first map entry is later than the new point */
662 if (_points.front().sclock() > sc) {
663 /* first point is later than sc. There's no iterator to reference a point at or before sc */
665 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
666 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
670 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
671 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
673 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, t, _points.front().metric(), sc, b, bbt, AudioTime, ramp));
677 /* special case #3: only one map entry, at the same time as the new point.
678 This is the common case when editing tempo/meter in a session with a single tempo/meter
681 if (_points.size() == 1 && _points.front().sclock() == sc) {
683 *((Tempo*) &_points.front().metric()) = t;
684 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
688 /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
690 TempoMapPoints::iterator i = iterator_at (sc);
691 TempoMapPoints::iterator nxt = i;
694 if (i->sclock() == sc) {
696 *((Tempo*) &i->metric()) = t;
697 i->make_explicit (TempoMapPoint::ExplicitTempo);
702 if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
703 cerr << "new tempo too close to previous ...\n";
707 Meter const & meter (i->metric());
709 TempoMapPoints::iterator e (i);
710 while (!e->is_explicit() && e != _points.begin()) {
714 if (e->metric().ramped()) {
715 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
716 and thus defines the new ramp distance.
718 e->compute_c_superclock (_sample_rate, t.superclocks_per_quarter_note (), sc);
721 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
722 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
726 Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
728 /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
731 Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
733 /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
736 if (i != _points.end()) {
739 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, sc, qn, bbt, AudioTime, ramp));
744 TempoMap::set_tempo (Tempo const & t, Timecode::BBT_Time const & bbt, bool ramp)
746 Glib::Threads::RWLock::WriterLock lm (_lock);
748 /* tempo changes are required to be on-beat */
750 Timecode::BBT_Time on_beat = bbt.round_up_to_beat();
752 cerr << "Try to set tempo @ " << on_beat << " to " << t << endl;
754 assert (!_points.empty());
756 if (_points.front().bbt() > on_beat) {
757 cerr << "Cannot insert tempo at " << bbt << " before first point at " << _points.front().bbt() << endl;
761 if (_points.size() == 1 && _points.front().bbt() == on_beat) {
763 *((Tempo*) &_points.front().metric()) = t;
764 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
768 TempoMapPoints::iterator i = iterator_at (on_beat);
770 if (i->bbt() == on_beat) {
771 *((Tempo*) &i->metric()) = t;
772 i->make_explicit (TempoMapPoint::ExplicitTempo);
776 Meter const & meter (i->metric());
779 /* stick a prototype music-locked point up front and let ::rebuild figure out the superclock and quarter time */
780 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, 0, Evoral::Beats(), on_beat, MusicTime, ramp));
785 TempoMap::set_meter (Meter const & m, Timecode::BBT_Time const & bbt)
787 Glib::Threads::RWLock::WriterLock lm (_lock);
788 Timecode::BBT_Time measure_start (m.round_up_to_bar (bbt));
790 cerr << "Try to set meter @ " << measure_start << " to " << m << endl;
792 assert (!_points.empty());
794 if (_points.front().bbt() > measure_start) {
795 cerr << "Cannot insert meter at " << bbt << " before first point at " << _points.front().bbt() << endl;
799 if (_points.size() == 1 && _points.front().bbt() == measure_start) {
801 cerr << "Found the single point\n";
802 *((Meter*) &_points.front().metric()) = m;
803 cerr << "Updated meter to " << m << endl;
804 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
808 TempoMapPoints::iterator i = iterator_at (measure_start);
810 if (i->bbt() == measure_start) {
811 *((Meter*) &i->metric()) = m;
812 cerr << "Updated meter to " << m << endl;
813 i->make_explicit (TempoMapPoint::ExplicitMeter);
817 Evoral::Beats qn = i->quarters_at (measure_start);
818 superclock_t sc = i->sclock() + i->metric().superclock_at_qn (qn);
820 Tempo const & tempo (i->metric());
823 cerr << "NEW METER, provisionally @ "
824 << TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime)
827 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime));
832 TempoMap::set_meter (Meter const & m, superclock_t sc)
834 Glib::Threads::RWLock::WriterLock lm (_lock);
835 assert (!_points.empty());
837 /* special case #2: first map entry is later than the new point */
839 if (_points.front().sclock() > sc) {
840 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
841 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
845 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
846 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
848 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitMeter, _points.front().metric(), m, sc, b, bbt, AudioTime));
852 /* special case #3: only one map entry, at the same time as the new point.
854 This is the common case when editing tempo/meter in a session with a single tempo/meter
857 if (_points.size() == 1 && _points.front().sclock() == sc) {
859 *((Meter*) &_points.front().metric()) = m;
860 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
864 TempoMapPoints::iterator i = iterator_at (sc);
866 if (i->sclock() == sc) {
868 *((Meter*) &i->metric()) = m;
870 /* enforce rule described below regarding meter change positions */
872 if (i->bbt().beats != 1) {
873 i->set_bbt (Timecode::BBT_Time (i->bbt().bars + 1, 1, 0));
876 i->make_explicit (TempoMapPoint::ExplicitMeter);
881 if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
882 cerr << "new tempo too close to previous ...\n";
886 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
887 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
891 Evoral::Beats b = i->quarters_at (sc).round_to_beat();
893 /* rule: all Meter changes must start a new measure. So determine the nearest, lower beat to "sc". If this is not
894 the first division of the measure, move to the next measure.
897 Timecode::BBT_Time bbt = i->bbt_at (b).round_down_to_beat ();
899 if (bbt.beats != 1) {
905 Tempo const & tempo (i->metric());
908 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, b, bbt, AudioTime));
912 TempoMapPoints::iterator
913 TempoMap::iterator_at (superclock_t sc)
915 /* CALLER MUST HOLD LOCK */
917 if (_points.empty()) {
918 throw EmptyTempoMapException();
921 if (_points.size() == 1) {
922 return _points.begin();
925 /* Construct an arbitrary TempoMapPoint. The only property we care about is it's superclock time,
926 so other values used in the constructor are arbitrary and irrelevant.
929 TempoMetric const & metric (_points.front().metric());
930 const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, sc, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
931 TempoMapPoint::SuperClockComparator scmp;
933 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, scmp);
935 if (tmp != _points.begin()) {
942 TempoMapPoints::iterator
943 TempoMap::iterator_at (Evoral::Beats const & qn)
945 /* CALLER MUST HOLD LOCK */
947 if (_points.empty()) {
948 throw EmptyTempoMapException();
951 if (_points.size() == 1) {
952 return _points.begin();
955 /* Construct an arbitrary TempoMapPoint. The only property we care about is its quarters time,
956 so other values used in the constructor are arbitrary and irrelevant.
959 TempoMetric const & metric (_points.front().metric());
960 const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, 0, qn, Timecode::BBT_Time(), AudioTime);
961 TempoMapPoint::QuarterComparator bcmp;
963 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
965 if (tmp != _points.begin()) {
972 TempoMapPoints::iterator
973 TempoMap::iterator_at (Timecode::BBT_Time const & bbt)
975 /* CALLER MUST HOLD LOCK */
977 if (_points.empty()) {
978 throw EmptyTempoMapException();
981 if (_points.size() == 1) {
982 return _points.begin();
985 /* Construct an arbitrary TempoMapPoint. The only property we care about is its bbt time,
986 so other values used in the constructor are arbitrary and irrelevant.
989 TempoMetric const & metric (_points.front().metric());
990 const TempoMapPoint tp (TempoMapPoint::Flag(0), metric, metric, 0, Evoral::Beats(), bbt, MusicTime);
991 TempoMapPoint::BBTComparator bcmp;
993 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
995 if (tmp != _points.begin()) {
1003 TempoMap::bbt_at (superclock_t sc) const
1005 Glib::Threads::RWLock::ReaderLock lm (_lock);
1006 return bbt_at_locked (sc);
1010 TempoMap::bbt_at_locked (superclock_t sc) const
1012 TempoMapPoint point (const_point_at (sc));
1013 Evoral::Beats b ((sc - point.sclock()) / (double) point.metric().superclocks_per_quarter_note());
1014 return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, b.get_beats(), b.get_ticks()));
1018 TempoMap::bbt_at (Evoral::Beats const & qn) const
1020 Glib::Threads::RWLock::ReaderLock lm (_lock);
1021 return bbt_at_locked (qn);
1025 TempoMap::bbt_at_locked (Evoral::Beats const & qn) const
1027 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1028 TempoMapPoint const & point (const_point_at (qn));
1029 Evoral::Beats delta (qn - point.quarters());
1030 return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, delta.get_beats(), delta.get_ticks()));
1034 TempoMap::quarter_note_at (superclock_t sc) const
1036 Glib::Threads::RWLock::ReaderLock lm (_lock);
1037 return quarter_note_at_locked (sc);
1041 TempoMap::quarter_note_at_locked (superclock_t sc) const
1043 return const_point_at (sc).quarters_at (sc);
1047 TempoMap::quarter_note_at (Timecode::BBT_Time const & bbt) const
1049 Glib::Threads::RWLock::ReaderLock lm (_lock);
1050 return quarter_note_at_locked (bbt);
1054 TempoMap::quarter_note_at_locked (Timecode::BBT_Time const & bbt) const
1056 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1057 TempoMapPoint const & point (const_point_at (bbt));
1059 Timecode::BBT_Time bbt_delta (point.metric().bbt_subtract (bbt, point.bbt()));
1060 /* XXX need to convert the metric division to quarters to match Evoral::Beats == Evoral::Quarters */
1061 return point.quarters() + Evoral::Beats ((point.metric().divisions_per_bar() * bbt_delta.bars) + bbt_delta.beats, bbt_delta.ticks);
1065 TempoMap::superclock_at (Evoral::Beats const & qn) const
1067 Glib::Threads::RWLock::ReaderLock lm (_lock);
1068 return superclock_at_locked (qn);
1072 TempoMap::superclock_at_locked (Evoral::Beats const & qn) const
1074 assert (!_points.empty());
1076 /* only the quarters property matters, since we're just using it to compare */
1077 const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, qn, Timecode::BBT_Time(), MusicTime);
1078 TempoMapPoint::QuarterComparator bcmp;
1080 TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1082 if (i == _points.end()) {
1086 /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1088 const Evoral::Beats q_delta = qn - i->quarters();
1089 superclock_t sclock_delta = i->metric().superclocks_per_quarter_note () * q_delta;
1090 return i->sclock() + sclock_delta;
1094 TempoMap::superclock_at (Timecode::BBT_Time const & bbt) const
1096 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1097 return superclock_at_locked (bbt);
1101 TempoMap::superclock_at_locked (Timecode::BBT_Time const & bbt) const
1103 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1104 assert (!_points.empty());
1106 /* only the bbt property matters, since we're just using it to compare */
1107 const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, Evoral::Beats(), bbt, MusicTime);
1108 TempoMapPoint::BBTComparator bcmp;
1110 TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1112 if (i == _points.end()) {
1116 /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1118 //const Evoral::Beats delta = b - i->beats();
1119 //return i->sclock() + samples_to_superclock ((delta / i->metric().quarter_notes_per_minute ()).to_double() * _sample_rate, _sample_rate);
1124 TempoMap::set_sample_rate (framecnt_t new_sr)
1126 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1127 double ratio = new_sr / (double) _sample_rate;
1129 for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1130 i->map_reset_set_sclock_for_sr_change (llrint (ratio * i->sclock()));
1135 TempoMap::dump (std::ostream& ostr)
1137 Glib::Threads::RWLock::ReaderLock lm (_lock);
1142 TempoMap::dump_locked (std::ostream& ostr)
1144 ostr << "\n\n------------\n";
1145 for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1146 ostr << *i << std::endl;
1151 TempoMap::remove_explicit_point (superclock_t sc)
1153 Glib::Threads::RWLock::WriterLock lm (_lock);
1154 TempoMapPoints::iterator p = iterator_at (sc);
1156 if (p->sclock() == sc) {
1162 TempoMap::move_to (superclock_t current, superclock_t destination, bool push)
1164 Glib::Threads::RWLock::WriterLock lm (_lock);
1165 TempoMapPoints::iterator p = iterator_at (current);
1167 if (p->sclock() != current) {
1168 cerr << "No point @ " << current << endl;
1172 const Meter meter (p->metric());
1173 const Tempo tempo (p->metric());
1174 const bool ramp = p->ramped();
1178 return set_tempo_and_meter (tempo, meter, destination, ramp, true);
1182 TempoMap::get_grid (TempoMapPoints& ret, superclock_t start, superclock_t end)
1184 Glib::Threads::RWLock::ReaderLock lm (_lock);
1185 TempoMapPoints::iterator p = iterator_at (start);
1187 while (p != _points.end() && p->sclock() < start) {
1191 while (p != _points.end() && p->sclock() < end) {
1198 operator<<(std::ostream& str, Meter const & m)
1200 return str << m.divisions_per_bar() << '/' << m.note_value();
1204 operator<<(std::ostream& str, Tempo const & t)
1206 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() << ')';
1210 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1212 str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
1213 << (tmp.is_explicit() ? " EXP" : " imp")
1214 << " qn " << tmp.quarters ()
1215 << " bbt " << tmp.bbt()
1216 << " lock to " << tmp.lock_style()
1219 if (tmp.is_explicit()) {
1220 str << " tempo " << *((Tempo*) &tmp.metric())
1221 << " meter " << *((Meter*) &tmp.metric())
1225 if (tmp.is_explicit() && tmp.ramped()) {
1226 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();
1233 #define SAMPLERATE 48000
1234 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1243 using namespace Timecode;
1246 BBT_Time b1 (1,1,1919);
1247 BBT_Time n1 (-1,1,1919);
1248 std::vector<Meter> meters;
1250 meters.push_back (Meter (4, 4));
1251 meters.push_back (Meter (5, 8));
1252 meters.push_back (Meter (11, 7));
1253 meters.push_back (Meter (3, 4));
1255 #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;
1257 for (std::vector<Meter>::iterator m = meters.begin(); m != meters.end(); ++m) {
1258 for (int B = 1; B < 4; ++B) {
1259 for (int b = 1; b < 13; ++b) {
1260 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 0);
1261 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 1);
1262 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN/2);
1263 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN);
1264 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 1);
1265 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 2);
1267 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 0);
1268 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 1);
1269 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN/2);
1270 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN);
1271 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 1);
1272 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 2);
1274 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 0);
1275 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 1);
1276 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN/2);
1277 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN);
1278 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 1);
1279 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 2);
1283 for (int B = 1; B < 4; ++B) {
1284 for (int b = 1; b < 13; ++b) {
1285 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 0);
1286 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 1);
1287 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN/2);
1288 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN);
1289 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 1);
1290 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 2);
1299 TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1304 tmap.set_tempo (Tempo (7), SECONDS_TO_SUPERCLOCK(7));
1305 tmap.set_tempo (Tempo (23), SECONDS_TO_SUPERCLOCK(23));
1306 tmap.set_tempo (Tempo (24), SECONDS_TO_SUPERCLOCK(24), true);
1307 tmap.set_tempo (Tempo (40), SECONDS_TO_SUPERCLOCK(28), true);
1308 tmap.set_tempo (Tempo (100), SECONDS_TO_SUPERCLOCK(100));
1309 tmap.set_tempo (Tempo (123), SECONDS_TO_SUPERCLOCK(23));
1311 tmap.set_meter (Meter (3, 4), SECONDS_TO_SUPERCLOCK(23));
1312 tmap.set_meter (Meter (5, 8), SECONDS_TO_SUPERCLOCK(100));
1313 tmap.set_meter (Meter (5, 7), SECONDS_TO_SUPERCLOCK(7));
1314 tmap.set_meter (Meter (4, 4), SECONDS_TO_SUPERCLOCK(24));
1315 tmap.set_meter (Meter (11, 7), SECONDS_TO_SUPERCLOCK(23));
1317 tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1319 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1320 tmap.dump (std::cout);
1322 if (tmap.move_to (SECONDS_TO_SUPERCLOCK(23), SECONDS_TO_SUPERCLOCK (72))) {
1323 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1324 tmap.dump (std::cout);
1327 TempoMapPoints grid;
1328 tmap.get_grid (grid, SECONDS_TO_SUPERCLOCK (12), SECONDS_TO_SUPERCLOCK (44));
1329 cout << "grid contains " << grid.size() << endl;
1330 for (TempoMapPoints::iterator p = grid.begin(); p != grid.end(); ++p) {