add _locked() variants to new tempo experiment
[ardour.git] / nutemp / t.cc
1 #include "t.h"
2
3 using namespace ARDOUR;
4 using std::cerr;
5 using std::cout;
6 using std::endl;
7
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; }
10
11 Timecode::BBT_Time
12 Meter::bbt_add (Timecode::BBT_Time const & bbt, Timecode::BBT_Offset const & add) const
13 {
14         int32_t bars = bbt.bars;
15         int32_t beats = bbt.beats;
16         int32_t ticks = bbt.ticks;
17
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
23                         */
24                         if (bars < 0) {
25                                 bars++;
26                         } else {
27                                 bars--;
28                         }
29                 }
30         }
31
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 */
36                         if (beats < 0) {
37                                 beats++;
38                         } else {
39                                 beats--;
40                         }
41                 }
42         }
43
44         Timecode::BBT_Offset r (bars + add.bars, beats + add.beats, ticks + add.ticks);
45
46         if (r.ticks >= Evoral::Beats::PPQN) {
47                 r.beats += r.ticks / Evoral::Beats::PPQN;
48                 r.ticks %= Evoral::Beats::PPQN;
49         }
50
51         if (r.beats > _divisions_per_bar) {
52                 r.bars += r.beats / _divisions_per_bar;
53                 r.beats %= _divisions_per_bar;
54         }
55
56         if (r.beats == 0) {
57                 r.beats = 1;
58         }
59
60         if (r.bars == 0) {
61                 r.bars = 1;
62         }
63
64         return Timecode::BBT_Time (r.bars, r.beats, r.ticks);
65 }
66
67 Timecode::BBT_Time
68 Meter::bbt_subtract (Timecode::BBT_Time const & bbt, Timecode::BBT_Offset const & sub) const
69 {
70         int32_t bars = bbt.bars;
71         int32_t beats = bbt.beats;
72         int32_t ticks = bbt.ticks;
73
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 */
78                         if (bars < 0) {
79                                 bars++;
80                         } else {
81                                 bars--;
82                         }
83                 }
84         }
85
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 */
90                         if (beats < 0) {
91                                 beats++;
92                         } else {
93                                 beats--;
94                         }
95                 }
96         }
97
98         Timecode::BBT_Offset r (bars - sub.bars, beats - sub.beats, ticks - sub.ticks);
99
100         if (r.ticks < 0) {
101                 r.beats -= 1 - (r.ticks / Evoral::Beats::PPQN);
102                 r.ticks = Evoral::Beats::PPQN + (r.ticks % Evoral::Beats::PPQN);
103         }
104
105         if (r.beats <= 0) {
106                 r.bars -= 1 - (r.beats / _divisions_per_bar);
107                 r.beats = _divisions_per_bar + (r.beats % _divisions_per_bar);
108         }
109
110         if (r.beats == 0) {
111                 r.beats = 1;
112         }
113
114         if (r.bars <= 0) {
115                 r.bars -= 1;
116         }
117
118         return Timecode::BBT_Time (r.bars, r.beats, r.ticks);
119 }
120
121 Timecode::BBT_Offset
122 Meter::bbt_delta (Timecode::BBT_Time const & a, Timecode::BBT_Time const & b) const
123 {
124         return Timecode::BBT_Offset (a.bars - b.bars, a.beats - b.beats, a.ticks - b.ticks);
125 }
126
127 Timecode::BBT_Time
128 Meter::round_up_to_bar (Timecode::BBT_Time const & bbt) const
129 {
130         Timecode::BBT_Time b = bbt.round_up_to_beat ();
131         if (b.beats > 1) {
132                 b.bars++;
133                 b.beats = 1;
134         }
135         return b;
136 }
137
138 Evoral::Beats
139 Meter::to_quarters (Timecode::BBT_Offset const & offset) const
140 {
141         Evoral::Beats b;
142
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);
148
149         return b;
150 }
151
152 superclock_t
153 TempoMetric::superclock_per_note_type_at_superclock (superclock_t sc) const
154 {
155         return superclocks_per_note_type () * expm1 (_c_per_superclock * sc);
156 }
157
158 superclock_t
159 TempoMetric::superclocks_per_grid (framecnt_t sr) const
160 {
161         return (superclock_ticks_per_second * Meter::note_value()) / (note_types_per_minute() / Tempo::note_type());
162 }
163
164 superclock_t
165 TempoMetric::superclocks_per_bar (framecnt_t sr) const
166 {
167         return superclocks_per_grid (sr) * _divisions_per_bar;
168 }
169
170 /*
171 Ramp Overview
172
173       |                     *
174 Tempo |                   *
175 Tt----|-----------------*|
176 Ta----|--------------|*  |
177       |            * |   |
178       |         *    |   |
179       |     *        |   |
180 T0----|*             |   |
181   *   |              |   |
182       _______________|___|____
183       time           a   t (next tempo)
184       [        c         ] defines c
185
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
188 T(t) = T0(e^(ct))
189
190 >>1/S(t) = (1/S0)(e^ct) => (1/S)(t) = (e^(ct))/S0 => S(t) = S0/(e^(ct))
191
192 with function constant
193 c = log(Ta/T0)/a
194
195 >>c = log ((1/Sa)/(1/S0)) / a => c = log (S0/Sa) / a
196
197 so
198 a = log(Ta/T0)/c
199
200 >>a = log ((1/Ta)/(1/S0) / c => a = log (S0/Sa) / c
201
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
204
205 >>b(t) = 1/S0(e^(ct) - 1) / c  => b(t) = (e^(ct) - 1) / (c * S0)
206
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
209
210 >>t(b) = log((c*b / (1/S0)) + 1) / c => t(b) = log ((c*b * S0) + 1) / c
211
212 The time t at which Tempo T occurs is a as above:
213 t(T) = log(T / T0) / c
214
215 >> t(1/S) = log ((1/S) / (1/S0) /c => t(1/S) = log (S0/S) / c
216
217 The beat at which a Tempo T occurs is:
218 b(T) = (T - T0) / c
219
220 >> b(1/S) = (1/S - 1/S0) / c
221
222 The Tempo at which beat b occurs is:
223 T(b) = b.c + T0
224
225 >> T(b) = b.c + (1/S0)
226
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))
232
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
235
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)
237
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.
242
243  */
244
245 /* equation to compute c is:
246  *
247  *    c = log (Ta / T0) / a
248  *
249  * where
250  *
251  *   a : time into section (from section start
252  *  T0 : tempo at start of section
253  *  Ta : tempo at time a into section
254  *
255  * THE UNITS QUESTION
256  *
257  * log (Ta / T0) / (time-units) => C is in per-time-units (1/time-units)
258  *
259  * so the question is what are the units of a, and thus c?
260  *
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.
264  *
265  * options:
266  *
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
273  *
274  * so one answer might be to compute c in two different units so that we have both available.
275  *
276  * hence, compute_c_superclocks() and compute_c_pulses()
277  */
278
279 void
280 TempoMetric::compute_c_superclock (framecnt_t sr, superclock_t end_scpqn, superclock_t superclock_duration)
281 {
282         if ((superclocks_per_quarter_note() == end_scpqn) || !ramped()) {
283                 _c_per_superclock = 0.0;
284                 return;
285         }
286
287         _c_per_superclock = log ((double) superclocks_per_quarter_note () / end_scpqn) / superclock_duration;
288 }
289 void
290 TempoMetric::compute_c_quarters (framecnt_t sr, superclock_t end_scpqn, Evoral::Beats const & quarter_duration)
291 {
292         if ((superclocks_per_quarter_note () == end_scpqn) || !ramped()) {
293                 _c_per_quarter = 0.0;
294                 return;
295         }
296
297         _c_per_quarter = log (superclocks_per_quarter_note () / (double) end_scpqn) /  quarter_duration.to_double();
298 }
299
300 superclock_t
301 TempoMetric::superclock_at_qn (Evoral::Beats const & qn) const
302 {
303         if (_c_per_quarter == 0.0) {
304                 /* not ramped, use linear */
305                 return llrint (superclocks_per_quarter_note () * qn.to_double());
306         }
307
308         return llrint (superclocks_per_quarter_note() * (log1p (_c_per_quarter * qn.to_double()) / _c_per_quarter));
309 }
310
311 Evoral::Beats
312 TempoMapPoint::quarters_at (superclock_t sc) const
313 {
314         /* This TempoMapPoint must already have a fully computed metric and position */
315
316         if (!ramped()) {
317                 return _quarters + Evoral::Beats ((sc - _sclock) / (double) (metric().superclocks_per_quarter_note ()));
318         }
319
320         return _quarters + Evoral::Beats (expm1 (metric().c_per_superclock() * (sc - _sclock)) / (metric().c_per_superclock() * metric().superclocks_per_quarter_note ()));
321 }
322
323 Evoral::Beats
324 TempoMapPoint::quarters_at (Timecode::BBT_Time const & bbt) const
325 {
326         /* This TempoMapPoint must already have a fully computed metric and position */
327
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);
331 }
332
333 Timecode::BBT_Time
334 TempoMapPoint::bbt_at (Evoral::Beats const & qn) const
335 {
336         /* This TempoMapPoint must already have a fully computed metric and position */
337
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));
341 }
342
343 TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter, framecnt_t sr)
344         : _sample_rate (sr)
345 {
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);
348 }
349
350 Meter const &
351 TempoMap::meter_at (superclock_t sc) const
352 {
353         Glib::Threads::RWLock::ReaderLock lm (_lock);
354         return meter_at_locked (sc);
355 }
356
357 Meter const &
358 TempoMap::meter_at (Evoral::Beats const & b) const
359 {
360         Glib::Threads::RWLock::ReaderLock lm (_lock);
361         return meter_at_locked (b);
362 }
363
364 Meter const &
365 TempoMap::meter_at (Timecode::BBT_Time const & bbt) const
366 {
367         Glib::Threads::RWLock::ReaderLock lm (_lock);
368         return meter_at_locked (bbt);
369 }
370
371 Tempo const &
372 TempoMap::tempo_at (superclock_t sc) const
373 {
374         Glib::Threads::RWLock::ReaderLock lm (_lock);
375         return tempo_at_locked (sc);
376 }
377
378 Tempo const &
379 TempoMap::tempo_at (Evoral::Beats const &b) const
380 {
381         Glib::Threads::RWLock::ReaderLock lm (_lock);
382         return tempo_at_locked (b);
383 }
384
385 Tempo const &
386 TempoMap::tempo_at (Timecode::BBT_Time const & bbt) const
387 {
388         Glib::Threads::RWLock::ReaderLock lm (_lock);
389         return tempo_at_locked (bbt);
390 }
391
392 void
393 TempoMap::rebuild (superclock_t limit)
394 {
395         Glib::Threads::RWLock::WriterLock lm (_lock);
396         rebuild_locked (limit);
397 }
398
399 void
400 TempoMap::rebuild_locked (superclock_t limit)
401 {
402         /* step one: remove all implicit points after a dirty explicit point */
403
404   restart:
405         TempoMapPoints::iterator tmp = _points.begin();
406         TempoMapPoints::iterator first_explicit_dirty = _points.end();
407
408         while ((tmp != _points.end()) && (tmp->is_implicit() || (tmp->is_explicit() && !tmp->dirty ()))) {
409                 ++tmp;
410         }
411
412         first_explicit_dirty = tmp;
413
414         /* remove all implicit points, because we're going to recalculate them all */
415
416         while (tmp != _points.end()) {
417                 TempoMapPoints::iterator next = tmp;
418                 ++next;
419
420                 if (tmp->is_implicit()) {
421                         _points.erase (tmp);
422                 }
423
424                 tmp = next;
425         }
426
427         /* compute C for all ramped sections */
428
429         for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
430                 TempoMapPoints::iterator nxt = tmp;
431                 ++nxt;
432
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());
435                 }
436
437                 tmp = nxt;
438         }
439
440         TempoMapPoints::iterator prev = _points.end();
441
442         /* Compute correct quarter-note and superclock times for all music-time locked explicit points */
443
444         for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
445
446                 TempoMapPoints::iterator next = tmp;
447                 ++next;
448
449                 if (prev != _points.end()) {
450                         if ((tmp->lock_style() == MusicTime)) {
451                                 /* determine superclock and quarter note time for this (music-time) locked point */
452
453                                 cerr << "MT-lock, prev = " << *prev << endl;
454
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
460                                      << endl;
461
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());
468                                         cerr << "Restart\n";
469                                         goto restart;
470                                 }
471                         }
472                 }
473
474                 prev = tmp;
475                 tmp = next;
476         }
477
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.
480          */
481
482         cerr << "POST-SORT\n";
483         dump (cerr);
484
485         prev = _points.end();
486
487         /* step two: add new implicit points between each pair of explicit
488          * points, after the dirty explicit point
489          */
490
491         for (tmp = _points.begin(); tmp != _points.end(); ) {
492
493                 if (!tmp->dirty()) {
494                         ++tmp;
495                         continue;
496                 }
497
498                 TempoMapPoints::iterator next = tmp;
499                 ++next;
500
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())));
511                                 } else {
512                                         /* no meter change, tempo change required to be on beat */
513                                         tmp->set_bbt (prev->bbt_at (tmp->quarters()).round_up_to_beat());
514                                 }
515                                 cerr << "AT - recompute bbt at " << tmp->bbt () << endl;
516                         }
517                 }
518
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();
523
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.
526                  */
527                 const Evoral::Beats qn_step = (Evoral::Beats (1) * 4) / tmp->metric().note_value();
528
529                 /* compute implicit points as far as the next explicit point, or limit,
530                    whichever comes first.
531                 */
532
533                 const superclock_t sc_limit = (next == _points.end() ? limit : (*next).sclock());
534
535                 while (1) {
536
537                         /* define next beat in superclocks, beats and bbt */
538
539                         qn += qn_step;
540                         bbt = tmp->metric().bbt_add (bbt, Timecode::BBT_Offset (0, 1, 0));
541
542                         if (!ramped) {
543                                 sc += tmp->metric().superclocks_per_note_type();
544                         } else {
545                                 sc = tmp->sclock() + tmp->metric().superclock_at_qn (qn - tmp->quarters());
546                         }
547
548                         if (sc >= sc_limit) {
549                                 break;
550                         }
551
552                         _points.insert (next, TempoMapPoint (*tmp, sc, qn, bbt));
553                 }
554
555                 (*tmp).set_dirty (false);
556                 prev = tmp;
557                 tmp = next;
558         }
559 }
560
561 bool
562 TempoMap::set_tempo (Tempo const & t, superclock_t sc, bool ramp)
563 {
564         Glib::Threads::RWLock::WriterLock lm (_lock);
565
566         assert (!_points.empty());
567
568         /* special case: first map entry is later than the new point */
569
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 */
572
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
575                    fractional.
576                 */
577
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 ();
580
581                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, t, _points.front().metric(), sc, b, bbt, AudioTime, ramp));
582                 return true;
583         }
584
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
587         */
588
589         if (_points.size() == 1 && _points.front().sclock() == sc) {
590                 /* change tempo */
591                 *((Tempo*) &_points.front().metric()) = t;
592                 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
593                 return true;
594         }
595
596         /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
597
598         TempoMapPoints::iterator i = iterator_at (sc);
599         TempoMapPoints::iterator nxt = i;
600         ++nxt;
601
602         if (i->sclock() == sc) {
603                 /* change tempo */
604                 *((Tempo*) &i->metric()) = t;
605                 i->make_explicit (TempoMapPoint::ExplicitTempo);
606                 /* done */
607                 return true;
608         }
609
610         if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
611                 cerr << "new tempo too close to previous ...\n";
612                 return false;
613         }
614
615         Meter const & meter (i->metric());
616
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.
620                 */
621                 i->metric().compute_c_superclock (_sample_rate, t.superclocks_per_quarter_note (), sc);
622         }
623
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
626            fractional.
627          */
628
629         Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
630
631         /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
632          */
633
634         Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
635
636         /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
637          */
638
639         if (i != _points.end()) {
640                 ++i;
641         }
642         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, sc, qn, bbt, AudioTime, ramp));
643         return true;
644 }
645
646 bool
647 TempoMap::set_tempo (Tempo const & t, Timecode::BBT_Time const & bbt, bool ramp)
648 {
649         Glib::Threads::RWLock::WriterLock lm (_lock);
650
651         /* tempo changes are required to be on-beat */
652
653         Timecode::BBT_Time on_beat = bbt.round_up_to_beat();
654
655         cerr << "Try to set tempo @ " << on_beat << " to " << t << endl;
656
657         assert (!_points.empty());
658
659         if (_points.front().bbt() > on_beat) {
660                 cerr << "Cannot insert tempo at " << bbt << " before first point at " << _points.front().bbt() << endl;
661                 return false;
662         }
663
664         if (_points.size() == 1 && _points.front().bbt() == on_beat) {
665                 /* change Meter */
666                 *((Tempo*) &_points.front().metric()) = t;
667                 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
668                 return true;
669         }
670
671         TempoMapPoints::iterator i = iterator_at (on_beat);
672
673         if (i->bbt() == on_beat) {
674                 *((Tempo*) &i->metric()) = t;
675                 i->make_explicit (TempoMapPoint::ExplicitTempo);
676                 return true;
677         }
678
679         Meter const & meter (i->metric());
680         ++i;
681
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));
684         return true;
685 }
686
687 bool
688 TempoMap::set_meter (Meter const & m, Timecode::BBT_Time const & bbt)
689 {
690         Glib::Threads::RWLock::WriterLock lm (_lock);
691         Timecode::BBT_Time measure_start (m.round_up_to_bar (bbt));
692
693         cerr << "Try to set meter @ " << measure_start << " to " << m << endl;
694
695         assert (!_points.empty());
696
697         if (_points.front().bbt() > measure_start) {
698                 cerr << "Cannot insert meter at " << bbt << " before first point at " << _points.front().bbt() << endl;
699                 return false;
700         }
701
702         if (_points.size() == 1 && _points.front().bbt() == measure_start) {
703                 /* change Meter */
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);
708                 return true;
709         }
710
711         TempoMapPoints::iterator i = iterator_at (measure_start);
712
713         if (i->bbt() == measure_start) {
714                 *((Meter*) &i->metric()) = m;
715                 cerr << "Updated meter to " << m << endl;
716                 i->make_explicit (TempoMapPoint::ExplicitMeter);
717                 return true;
718         }
719
720         Evoral::Beats qn = i->quarters_at (measure_start);
721         superclock_t sc = i->sclock() + i->metric().superclock_at_qn (qn);
722
723         Tempo const & tempo (i->metric());
724         ++i;
725
726         cerr << "NEW METER, provisionally @ "
727              << TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime)
728              << endl;
729
730         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime));
731         return true;
732 }
733
734 bool
735 TempoMap::set_meter (Meter const & m, superclock_t sc)
736 {
737         Glib::Threads::RWLock::WriterLock lm (_lock);
738         assert (!_points.empty());
739
740         /* special case #2: first map entry is later than the new point */
741
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
745                    fractional.
746                 */
747
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 ();
750
751                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitMeter, _points.front().metric(), m, sc, b, bbt, AudioTime));
752                 return true;
753         }
754
755         /* special case #3: only one map entry, at the same time as the new point.
756
757            This is the common case when editing tempo/meter in a session with a single tempo/meter
758         */
759
760         if (_points.size() == 1 && _points.front().sclock() == sc) {
761                 /* change meter */
762                 *((Meter*) &_points.front().metric()) = m;
763                 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
764                 return true;
765         }
766
767         TempoMapPoints::iterator i = iterator_at (sc);
768
769         if (i->sclock() == sc) {
770                 /* change meter */
771                 *((Meter*) &i->metric()) = m;
772
773                 /* enforce rule described below regarding meter change positions */
774
775                 if (i->bbt().beats != 1) {
776                         i->set_bbt (Timecode::BBT_Time (i->bbt().bars + 1, 1, 0));
777                 }
778
779                 i->make_explicit (TempoMapPoint::ExplicitMeter);
780
781                 return true;
782         }
783
784         if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
785                 cerr << "new tempo too close to previous ...\n";
786                 return false;
787         }
788
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
791            fractional.
792         */
793
794         Evoral::Beats b = i->quarters_at (sc).round_to_beat();
795
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.
798          */
799
800         Timecode::BBT_Time bbt = i->bbt_at (b).round_down_to_beat ();
801
802         if (bbt.beats != 1) {
803                 bbt.bars += 1;
804                 bbt.beats = 1;
805                 bbt.ticks = 0;
806         }
807
808         Tempo const & tempo (i->metric());
809         ++i;
810
811         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, b, bbt, AudioTime));
812         return true;
813 }
814
815 TempoMapPoints::iterator
816 TempoMap::iterator_at (superclock_t sc)
817 {
818         /* CALLER MUST HOLD LOCK */
819
820         if (_points.empty()) {
821                 throw EmptyTempoMapException();
822         }
823
824         if (_points.size() == 1) {
825                 return _points.begin();
826         }
827
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.
830         */
831
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;
835
836         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, scmp);
837
838         if (tmp != _points.begin()) {
839                 return --tmp;
840         }
841
842         return tmp;
843 }
844
845 TempoMapPoints::iterator
846 TempoMap::iterator_at (Evoral::Beats const & qn)
847 {
848         /* CALLER MUST HOLD LOCK */
849
850         if (_points.empty()) {
851                 throw EmptyTempoMapException();
852         }
853
854         if (_points.size() == 1) {
855                 return _points.begin();
856         }
857
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.
860         */
861
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;
865
866         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
867
868         if (tmp != _points.begin()) {
869                 return --tmp;
870         }
871
872         return tmp;
873 }
874
875 TempoMapPoints::iterator
876 TempoMap::iterator_at (Timecode::BBT_Time const & bbt)
877 {
878         /* CALLER MUST HOLD LOCK */
879
880         if (_points.empty()) {
881                 throw EmptyTempoMapException();
882         }
883
884         if (_points.size() == 1) {
885                 return _points.begin();
886         }
887
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.
890         */
891
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;
895
896         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
897
898         if (tmp != _points.begin()) {
899                 return --tmp;
900         }
901
902         return tmp;
903 }
904
905 Timecode::BBT_Time
906 TempoMap::bbt_at (superclock_t sc) const
907 {
908         Glib::Threads::RWLock::ReaderLock lm (_lock);
909         return bbt_at_locked (sc);
910 }
911
912 Timecode::BBT_Time
913 TempoMap::bbt_at_locked (superclock_t sc) const
914 {
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()));
918 }
919
920 Timecode::BBT_Time
921 TempoMap::bbt_at (Evoral::Beats const & qn) const
922 {
923         Glib::Threads::RWLock::ReaderLock lm (_lock);
924         return bbt_at_locked (qn);
925 }
926
927 Timecode::BBT_Time
928 TempoMap::bbt_at_locked (Evoral::Beats const & qn) const
929 {
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()));
934 }
935
936 Evoral::Beats
937 TempoMap::quarter_note_at (superclock_t sc) const
938 {
939         Glib::Threads::RWLock::ReaderLock lm (_lock);
940         return quarter_note_at_locked (sc);
941 }
942
943 Evoral::Beats
944 TempoMap::quarter_note_at_locked (superclock_t sc) const
945 {
946         return const_point_at (sc).quarters_at (sc);
947 }
948
949 Evoral::Beats
950 TempoMap::quarter_note_at (Timecode::BBT_Time const & bbt) const
951 {
952         Glib::Threads::RWLock::ReaderLock lm (_lock);
953         return quarter_note_at_locked (bbt);
954 }
955
956 Evoral::Beats
957 TempoMap::quarter_note_at_locked (Timecode::BBT_Time const & bbt) const
958 {
959         //Glib::Threads::RWLock::ReaderLock lm (_lock);
960         TempoMapPoint const & point (const_point_at (bbt));
961
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);
965 }
966
967 superclock_t
968 TempoMap::superclock_at (Evoral::Beats const & qn) const
969 {
970         Glib::Threads::RWLock::ReaderLock lm (_lock);
971         return superclock_at_locked (qn);
972 }
973
974 superclock_t
975 TempoMap::superclock_at_locked (Evoral::Beats const & qn) const
976 {
977         assert (!_points.empty());
978
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;
982
983         TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
984
985         if (i == _points.end()) {
986                 --i;
987         }
988
989         /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
990
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;
994 }
995
996 superclock_t
997 TempoMap::superclock_at (Timecode::BBT_Time const & bbt) const
998 {
999         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1000         return superclock_at_locked (bbt);
1001 }
1002
1003 superclock_t
1004 TempoMap::superclock_at_locked (Timecode::BBT_Time const & bbt) const
1005 {
1006         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1007         assert (!_points.empty());
1008
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;
1012
1013         TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1014
1015         if (i == _points.end()) {
1016                 --i;
1017         }
1018
1019         /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1020
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);
1023         return 0;
1024 }
1025
1026 void
1027 TempoMap::set_sample_rate (framecnt_t new_sr)
1028 {
1029         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1030         double ratio = new_sr / (double) _sample_rate;
1031
1032         for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1033                 i->map_reset_set_sclock_for_sr_change (llrint (ratio * i->sclock()));
1034         }
1035 }
1036                                                                                                                                                                                                                                                                       void
1037 TempoMap::dump (std::ostream& ostr)
1038 {
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;
1043         }
1044 }
1045
1046 void
1047 TempoMap::remove_explicit_point (superclock_t sc)
1048 {
1049         //Glib::Threads::RWLock::WriterLock lm (_lock);
1050         TempoMapPoints::iterator p = iterator_at (sc);
1051
1052         if (p->sclock() == sc) {
1053                 _points.erase (p);
1054         }
1055 }
1056
1057 void
1058 TempoMap::move_explicit (superclock_t current, superclock_t destination)
1059 {
1060         //Glib::Threads::RWLock::WriterLock lm (_lock);
1061         TempoMapPoints::iterator p = iterator_at (current);
1062
1063         if (p->sclock() != current) {
1064                 return;
1065         }
1066
1067         move_explicit_to (p, destination);
1068 }
1069
1070 void
1071 TempoMap::move_explicit_to (TempoMapPoints::iterator p, superclock_t destination)
1072 {
1073         /* CALLER MUST HOLD LOCK */
1074
1075         TempoMapPoint point (*p);
1076         point.set_sclock (destination);
1077
1078         TempoMapPoints::iterator prev;
1079
1080         prev = p;
1081         if (p != _points.begin()) {
1082                 --prev;
1083         }
1084
1085         /* remove existing */
1086
1087         _points.erase (p);
1088         prev->set_dirty (true);
1089
1090         /* find insertion point */
1091
1092         p = iterator_at (destination);
1093
1094         /* STL insert semantics are always "insert-before", whereas ::iterator_at() returns iterator-at-or-before */
1095         ++p;
1096
1097         _points.insert (p, point);
1098 }
1099
1100 void
1101 TempoMap::move_implicit (superclock_t current, superclock_t destination)
1102 {
1103         //Glib::Threads::RWLock::WriterLock lm (_lock);
1104         TempoMapPoints::iterator p = iterator_at (current);
1105
1106         if (p->sclock() != current) {
1107                 return;
1108         }
1109
1110         if (p->is_implicit()) {
1111                 p->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo));
1112         }
1113
1114         move_explicit_to (p, destination);
1115 }
1116
1117 /*******/
1118
1119 #define SAMPLERATE 48000
1120 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1121
1122 using std::cerr;
1123 using std::cout;
1124 using std::endl;
1125
1126 void
1127 test_bbt_math ()
1128 {
1129         using namespace Timecode;
1130
1131         BBT_Time a;
1132         BBT_Time b1 (1,1,1919);
1133         BBT_Time n1 (-1,1,1919);
1134         std::vector<Meter> meters;
1135
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));
1140
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;
1142
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);
1152
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);
1159
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);
1166                         }
1167                 }
1168
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);
1177                         }
1178                 }
1179         }
1180 }
1181
1182 int
1183 main ()
1184 {
1185         TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1186
1187         //test_bbt_math ();
1188         //return 0;
1189
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));
1196
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));
1202
1203         tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1204
1205         tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1206         tmap.dump (std::cout);
1207
1208         return 0;
1209 }
1210
1211 std::ostream&
1212 operator<<(std::ostream& str, Meter const & m)
1213 {
1214         return str << m.divisions_per_bar() << '/' << m.note_value();
1215 }
1216
1217 std::ostream&
1218 operator<<(std::ostream& str, Tempo const & t)
1219 {
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() << ')';
1221 }
1222
1223 std::ostream&
1224 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1225 {
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()
1231                 ;
1232
1233         if (tmp.is_explicit()) {
1234                 str << " tempo " << *((Tempo*) &tmp.metric())
1235                     << " meter " << *((Meter*) &tmp.metric())
1236                         ;
1237         }
1238
1239         if (tmp.is_explicit() && tmp.ramped()) {
1240                 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();
1241         }
1242         return str;
1243 }