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->metric().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 (Tempo const & t, superclock_t sc, bool ramp)
564 Glib::Threads::RWLock::WriterLock lm (_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, t, _points.front().metric(), 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()) = t;
592 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
596 /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
598 TempoMapPoints::iterator i = iterator_at (sc);
599 TempoMapPoints::iterator nxt = i;
602 if (i->sclock() == sc) {
604 *((Tempo*) &i->metric()) = t;
605 i->make_explicit (TempoMapPoint::ExplicitTempo);
610 if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
611 cerr << "new tempo too close to previous ...\n";
615 Meter const & meter (i->metric());
617 if (i->metric().ramped()) {
618 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
619 and thus defines the new ramp distance.
621 i->metric().compute_c_superclock (_sample_rate, t.superclocks_per_quarter_note (), sc);
624 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
625 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
629 Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
631 /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
634 Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
636 /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
639 if (i != _points.end()) {
642 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, sc, qn, bbt, AudioTime, ramp));
647 TempoMap::set_tempo (Tempo const & t, Timecode::BBT_Time const & bbt, bool ramp)
649 Glib::Threads::RWLock::WriterLock lm (_lock);
651 /* tempo changes are required to be on-beat */
653 Timecode::BBT_Time on_beat = bbt.round_up_to_beat();
655 cerr << "Try to set tempo @ " << on_beat << " to " << t << endl;
657 assert (!_points.empty());
659 if (_points.front().bbt() > on_beat) {
660 cerr << "Cannot insert tempo at " << bbt << " before first point at " << _points.front().bbt() << endl;
664 if (_points.size() == 1 && _points.front().bbt() == on_beat) {
666 *((Tempo*) &_points.front().metric()) = t;
667 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
671 TempoMapPoints::iterator i = iterator_at (on_beat);
673 if (i->bbt() == on_beat) {
674 *((Tempo*) &i->metric()) = t;
675 i->make_explicit (TempoMapPoint::ExplicitTempo);
679 Meter const & meter (i->metric());
682 /* stick a prototype music-locked point up front and let ::rebuild figure out the superclock and quarter time */
683 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, 0, Evoral::Beats(), on_beat, MusicTime, ramp));
688 TempoMap::set_meter (Meter const & m, Timecode::BBT_Time const & bbt)
690 Glib::Threads::RWLock::WriterLock lm (_lock);
691 Timecode::BBT_Time measure_start (m.round_up_to_bar (bbt));
693 cerr << "Try to set meter @ " << measure_start << " to " << m << endl;
695 assert (!_points.empty());
697 if (_points.front().bbt() > measure_start) {
698 cerr << "Cannot insert meter at " << bbt << " before first point at " << _points.front().bbt() << endl;
702 if (_points.size() == 1 && _points.front().bbt() == measure_start) {
704 cerr << "Found the single point\n";
705 *((Meter*) &_points.front().metric()) = m;
706 cerr << "Updated meter to " << m << endl;
707 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
711 TempoMapPoints::iterator i = iterator_at (measure_start);
713 if (i->bbt() == measure_start) {
714 *((Meter*) &i->metric()) = m;
715 cerr << "Updated meter to " << m << endl;
716 i->make_explicit (TempoMapPoint::ExplicitMeter);
720 Evoral::Beats qn = i->quarters_at (measure_start);
721 superclock_t sc = i->sclock() + i->metric().superclock_at_qn (qn);
723 Tempo const & tempo (i->metric());
726 cerr << "NEW METER, provisionally @ "
727 << TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime)
730 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime));
735 TempoMap::set_meter (Meter const & m, superclock_t sc)
737 Glib::Threads::RWLock::WriterLock lm (_lock);
738 assert (!_points.empty());
740 /* special case #2: first map entry is later than the new point */
742 if (_points.front().sclock() > sc) {
743 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
744 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
748 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
749 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
751 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitMeter, _points.front().metric(), m, sc, b, bbt, AudioTime));
755 /* special case #3: only one map entry, at the same time as the new point.
757 This is the common case when editing tempo/meter in a session with a single tempo/meter
760 if (_points.size() == 1 && _points.front().sclock() == sc) {
762 *((Meter*) &_points.front().metric()) = m;
763 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
767 TempoMapPoints::iterator i = iterator_at (sc);
769 if (i->sclock() == sc) {
771 *((Meter*) &i->metric()) = m;
773 /* enforce rule described below regarding meter change positions */
775 if (i->bbt().beats != 1) {
776 i->set_bbt (Timecode::BBT_Time (i->bbt().bars + 1, 1, 0));
779 i->make_explicit (TempoMapPoint::ExplicitMeter);
784 if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
785 cerr << "new tempo too close to previous ...\n";
789 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
790 even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
794 Evoral::Beats b = i->quarters_at (sc).round_to_beat();
796 /* rule: all Meter changes must start a new measure. So determine the nearest, lower beat to "sc". If this is not
797 the first division of the measure, move to the next measure.
800 Timecode::BBT_Time bbt = i->bbt_at (b).round_down_to_beat ();
802 if (bbt.beats != 1) {
808 Tempo const & tempo (i->metric());
811 _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, b, bbt, AudioTime));
815 TempoMapPoints::iterator
816 TempoMap::iterator_at (superclock_t sc)
818 /* CALLER MUST HOLD LOCK */
820 if (_points.empty()) {
821 throw EmptyTempoMapException();
824 if (_points.size() == 1) {
825 return _points.begin();
828 /* Construct an arbitrary TempoMapPoint. The only property we care about is it's superclock time,
829 so other values used in the constructor are arbitrary and irrelevant.
832 TempoMetric const & metric (_points.front().metric());
833 const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, sc, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
834 TempoMapPoint::SuperClockComparator scmp;
836 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, scmp);
838 if (tmp != _points.begin()) {
845 TempoMapPoints::iterator
846 TempoMap::iterator_at (Evoral::Beats const & qn)
848 /* CALLER MUST HOLD LOCK */
850 if (_points.empty()) {
851 throw EmptyTempoMapException();
854 if (_points.size() == 1) {
855 return _points.begin();
858 /* Construct an arbitrary TempoMapPoint. The only property we care about is its quarters time,
859 so other values used in the constructor are arbitrary and irrelevant.
862 TempoMetric const & metric (_points.front().metric());
863 const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, 0, qn, Timecode::BBT_Time(), AudioTime);
864 TempoMapPoint::QuarterComparator bcmp;
866 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
868 if (tmp != _points.begin()) {
875 TempoMapPoints::iterator
876 TempoMap::iterator_at (Timecode::BBT_Time const & bbt)
878 /* CALLER MUST HOLD LOCK */
880 if (_points.empty()) {
881 throw EmptyTempoMapException();
884 if (_points.size() == 1) {
885 return _points.begin();
888 /* Construct an arbitrary TempoMapPoint. The only property we care about is its bbt time,
889 so other values used in the constructor are arbitrary and irrelevant.
892 TempoMetric const & metric (_points.front().metric());
893 const TempoMapPoint tp (TempoMapPoint::Flag(0), metric, metric, 0, Evoral::Beats(), bbt, MusicTime);
894 TempoMapPoint::BBTComparator bcmp;
896 TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
898 if (tmp != _points.begin()) {
906 TempoMap::bbt_at (superclock_t sc) const
908 Glib::Threads::RWLock::ReaderLock lm (_lock);
909 return bbt_at_locked (sc);
913 TempoMap::bbt_at_locked (superclock_t sc) const
915 TempoMapPoint point (const_point_at (sc));
916 Evoral::Beats b ((sc - point.sclock()) / (double) point.metric().superclocks_per_quarter_note());
917 return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, b.get_beats(), b.get_ticks()));
921 TempoMap::bbt_at (Evoral::Beats const & qn) const
923 Glib::Threads::RWLock::ReaderLock lm (_lock);
924 return bbt_at_locked (qn);
928 TempoMap::bbt_at_locked (Evoral::Beats const & qn) const
930 //Glib::Threads::RWLock::ReaderLock lm (_lock);
931 TempoMapPoint const & point (const_point_at (qn));
932 Evoral::Beats delta (qn - point.quarters());
933 return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, delta.get_beats(), delta.get_ticks()));
937 TempoMap::quarter_note_at (superclock_t sc) const
939 Glib::Threads::RWLock::ReaderLock lm (_lock);
940 return quarter_note_at_locked (sc);
944 TempoMap::quarter_note_at_locked (superclock_t sc) const
946 return const_point_at (sc).quarters_at (sc);
950 TempoMap::quarter_note_at (Timecode::BBT_Time const & bbt) const
952 Glib::Threads::RWLock::ReaderLock lm (_lock);
953 return quarter_note_at_locked (bbt);
957 TempoMap::quarter_note_at_locked (Timecode::BBT_Time const & bbt) const
959 //Glib::Threads::RWLock::ReaderLock lm (_lock);
960 TempoMapPoint const & point (const_point_at (bbt));
962 Timecode::BBT_Time bbt_delta (point.metric().bbt_subtract (bbt, point.bbt()));
963 /* XXX need to convert the metric division to quarters to match Evoral::Beats == Evoral::Quarters */
964 return point.quarters() + Evoral::Beats ((point.metric().divisions_per_bar() * bbt_delta.bars) + bbt_delta.beats, bbt_delta.ticks);
968 TempoMap::superclock_at (Evoral::Beats const & qn) const
970 Glib::Threads::RWLock::ReaderLock lm (_lock);
971 return superclock_at_locked (qn);
975 TempoMap::superclock_at_locked (Evoral::Beats const & qn) const
977 assert (!_points.empty());
979 /* only the quarters property matters, since we're just using it to compare */
980 const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, qn, Timecode::BBT_Time(), MusicTime);
981 TempoMapPoint::QuarterComparator bcmp;
983 TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
985 if (i == _points.end()) {
989 /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
991 const Evoral::Beats q_delta = qn - i->quarters();
992 superclock_t sclock_delta = i->metric().superclocks_per_quarter_note () * q_delta;
993 return i->sclock() + sclock_delta;
997 TempoMap::superclock_at (Timecode::BBT_Time const & bbt) const
999 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1000 return superclock_at_locked (bbt);
1004 TempoMap::superclock_at_locked (Timecode::BBT_Time const & bbt) const
1006 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1007 assert (!_points.empty());
1009 /* only the bbt property matters, since we're just using it to compare */
1010 const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, Evoral::Beats(), bbt, MusicTime);
1011 TempoMapPoint::BBTComparator bcmp;
1013 TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1015 if (i == _points.end()) {
1019 /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1021 //const Evoral::Beats delta = b - i->beats();
1022 //return i->sclock() + samples_to_superclock ((delta / i->metric().quarter_notes_per_minute ()).to_double() * _sample_rate, _sample_rate);
1027 TempoMap::set_sample_rate (framecnt_t new_sr)
1029 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1030 double ratio = new_sr / (double) _sample_rate;
1032 for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1033 i->map_reset_set_sclock_for_sr_change (llrint (ratio * i->sclock()));
1037 TempoMap::dump (std::ostream& ostr)
1039 //Glib::Threads::RWLock::ReaderLock lm (_lock);
1040 ostr << "\n\n------------\n";
1041 for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1042 ostr << *i << std::endl;
1047 TempoMap::remove_explicit_point (superclock_t sc)
1049 //Glib::Threads::RWLock::WriterLock lm (_lock);
1050 TempoMapPoints::iterator p = iterator_at (sc);
1052 if (p->sclock() == sc) {
1058 TempoMap::move_explicit (superclock_t current, superclock_t destination)
1060 //Glib::Threads::RWLock::WriterLock lm (_lock);
1061 TempoMapPoints::iterator p = iterator_at (current);
1063 if (p->sclock() != current) {
1067 move_explicit_to (p, destination);
1071 TempoMap::move_explicit_to (TempoMapPoints::iterator p, superclock_t destination)
1073 /* CALLER MUST HOLD LOCK */
1075 TempoMapPoint point (*p);
1076 point.set_sclock (destination);
1078 TempoMapPoints::iterator prev;
1081 if (p != _points.begin()) {
1085 /* remove existing */
1088 prev->set_dirty (true);
1090 /* find insertion point */
1092 p = iterator_at (destination);
1094 /* STL insert semantics are always "insert-before", whereas ::iterator_at() returns iterator-at-or-before */
1097 _points.insert (p, point);
1101 TempoMap::move_implicit (superclock_t current, superclock_t destination)
1103 //Glib::Threads::RWLock::WriterLock lm (_lock);
1104 TempoMapPoints::iterator p = iterator_at (current);
1106 if (p->sclock() != current) {
1110 if (p->is_implicit()) {
1111 p->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo));
1114 move_explicit_to (p, destination);
1119 #define SAMPLERATE 48000
1120 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1129 using namespace Timecode;
1132 BBT_Time b1 (1,1,1919);
1133 BBT_Time n1 (-1,1,1919);
1134 std::vector<Meter> meters;
1136 meters.push_back (Meter (4, 4));
1137 meters.push_back (Meter (5, 8));
1138 meters.push_back (Meter (11, 7));
1139 meters.push_back (Meter (3, 4));
1141 #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;
1143 for (std::vector<Meter>::iterator m = meters.begin(); m != meters.end(); ++m) {
1144 for (int B = 1; B < 4; ++B) {
1145 for (int b = 1; b < 13; ++b) {
1146 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 0);
1147 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 1);
1148 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN/2);
1149 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN);
1150 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 1);
1151 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 2);
1153 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 0);
1154 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 1);
1155 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN/2);
1156 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN);
1157 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 1);
1158 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 2);
1160 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 0);
1161 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 1);
1162 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN/2);
1163 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN);
1164 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 1);
1165 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 2);
1169 for (int B = 1; B < 4; ++B) {
1170 for (int b = 1; b < 13; ++b) {
1171 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 0);
1172 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 1);
1173 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN/2);
1174 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN);
1175 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 1);
1176 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 2);
1185 TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1190 tmap.set_tempo (Tempo (7), SECONDS_TO_SUPERCLOCK(7));
1191 tmap.set_tempo (Tempo (23), SECONDS_TO_SUPERCLOCK(23));
1192 tmap.set_tempo (Tempo (24), SECONDS_TO_SUPERCLOCK(24), true);
1193 tmap.set_tempo (Tempo (40), SECONDS_TO_SUPERCLOCK(28), true);
1194 tmap.set_tempo (Tempo (100), SECONDS_TO_SUPERCLOCK(100));
1195 tmap.set_tempo (Tempo (123), SECONDS_TO_SUPERCLOCK(23));
1197 tmap.set_meter (Meter (3, 4), SECONDS_TO_SUPERCLOCK(23));
1198 tmap.set_meter (Meter (5, 8), SECONDS_TO_SUPERCLOCK(100));
1199 tmap.set_meter (Meter (5, 7), SECONDS_TO_SUPERCLOCK(7));
1200 tmap.set_meter (Meter (4, 4), SECONDS_TO_SUPERCLOCK(24));
1201 tmap.set_meter (Meter (11, 7), SECONDS_TO_SUPERCLOCK(23));
1203 tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1205 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1206 tmap.dump (std::cout);
1212 operator<<(std::ostream& str, Meter const & m)
1214 return str << m.divisions_per_bar() << '/' << m.note_value();
1218 operator<<(std::ostream& str, Tempo const & t)
1220 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() << ')';
1224 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1226 str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
1227 << (tmp.is_explicit() ? " EXP" : " imp")
1228 << " qn " << tmp.quarters ()
1229 << " bbt " << tmp.bbt()
1230 << " lock to " << tmp.lock_style()
1233 if (tmp.is_explicit()) {
1234 str << " tempo " << *((Tempo*) &tmp.metric())
1235 << " meter " << *((Meter*) &tmp.metric())
1239 if (tmp.is_explicit() && tmp.ramped()) {
1240 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();