add a _locked variant for TempoMap::dump()
[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_locked (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
1037 void
1038 TempoMap::dump (std::ostream& ostr)
1039 {
1040         Glib::Threads::RWLock::ReaderLock lm (_lock);
1041         dump_locked (ostr);
1042 }
1043
1044 void
1045 TempoMap::dump (std::ostream& ostr)
1046 {
1047         ostr << "\n\n------------\n";
1048         for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1049                 ostr << *i << std::endl;
1050         }
1051 }
1052
1053 void
1054 TempoMap::remove_explicit_point (superclock_t sc)
1055 {
1056         //Glib::Threads::RWLock::WriterLock lm (_lock);
1057         TempoMapPoints::iterator p = iterator_at (sc);
1058
1059         if (p->sclock() == sc) {
1060                 _points.erase (p);
1061         }
1062 }
1063
1064 void
1065 TempoMap::move_explicit (superclock_t current, superclock_t destination)
1066 {
1067         //Glib::Threads::RWLock::WriterLock lm (_lock);
1068         TempoMapPoints::iterator p = iterator_at (current);
1069
1070         if (p->sclock() != current) {
1071                 return;
1072         }
1073
1074         move_explicit_to (p, destination);
1075 }
1076
1077 void
1078 TempoMap::move_explicit_to (TempoMapPoints::iterator p, superclock_t destination)
1079 {
1080         /* CALLER MUST HOLD LOCK */
1081
1082         TempoMapPoint point (*p);
1083         point.set_sclock (destination);
1084
1085         TempoMapPoints::iterator prev;
1086
1087         prev = p;
1088         if (p != _points.begin()) {
1089                 --prev;
1090         }
1091
1092         /* remove existing */
1093
1094         _points.erase (p);
1095         prev->set_dirty (true);
1096
1097         /* find insertion point */
1098
1099         p = iterator_at (destination);
1100
1101         /* STL insert semantics are always "insert-before", whereas ::iterator_at() returns iterator-at-or-before */
1102         ++p;
1103
1104         _points.insert (p, point);
1105 }
1106
1107 void
1108 TempoMap::move_implicit (superclock_t current, superclock_t destination)
1109 {
1110         //Glib::Threads::RWLock::WriterLock lm (_lock);
1111         TempoMapPoints::iterator p = iterator_at (current);
1112
1113         if (p->sclock() != current) {
1114                 return;
1115         }
1116
1117         if (p->is_implicit()) {
1118                 p->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo));
1119         }
1120
1121         move_explicit_to (p, destination);
1122 }
1123
1124 /*******/
1125
1126 #define SAMPLERATE 48000
1127 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1128
1129 using std::cerr;
1130 using std::cout;
1131 using std::endl;
1132
1133 void
1134 test_bbt_math ()
1135 {
1136         using namespace Timecode;
1137
1138         BBT_Time a;
1139         BBT_Time b1 (1,1,1919);
1140         BBT_Time n1 (-1,1,1919);
1141         std::vector<Meter> meters;
1142
1143         meters.push_back (Meter (4, 4));
1144         meters.push_back (Meter (5, 8));
1145         meters.push_back (Meter (11, 7));
1146         meters.push_back (Meter (3, 4));
1147
1148 #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;
1149
1150         for (std::vector<Meter>::iterator m = meters.begin(); m != meters.end(); ++m) {
1151                 for (int B = 1; B < 4; ++B) {
1152                         for (int b = 1; b < 13; ++b) {
1153                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 0);
1154                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 1);
1155                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN/2);
1156                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN);
1157                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 1);
1158                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 2);
1159
1160                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 0);
1161                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 1);
1162                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN/2);
1163                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN);
1164                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 1);
1165                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 2);
1166
1167                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 0);
1168                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 1);
1169                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN/2);
1170                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN);
1171                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 1);
1172                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 2);
1173                         }
1174                 }
1175
1176                 for (int B = 1; B < 4; ++B) {
1177                         for (int b = 1; b < 13; ++b) {
1178                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 0);
1179                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 1);
1180                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN/2);
1181                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN);
1182                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 1);
1183                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 2);
1184                         }
1185                 }
1186         }
1187 }
1188
1189 int
1190 main ()
1191 {
1192         TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1193
1194         //test_bbt_math ();
1195         //return 0;
1196
1197         tmap.set_tempo (Tempo (7), SECONDS_TO_SUPERCLOCK(7));
1198         tmap.set_tempo (Tempo (23), SECONDS_TO_SUPERCLOCK(23));
1199         tmap.set_tempo (Tempo (24), SECONDS_TO_SUPERCLOCK(24), true);
1200         tmap.set_tempo (Tempo (40), SECONDS_TO_SUPERCLOCK(28), true);
1201         tmap.set_tempo (Tempo (100), SECONDS_TO_SUPERCLOCK(100));
1202         tmap.set_tempo (Tempo (123), SECONDS_TO_SUPERCLOCK(23));
1203
1204         tmap.set_meter (Meter (3, 4), SECONDS_TO_SUPERCLOCK(23));
1205         tmap.set_meter (Meter (5, 8), SECONDS_TO_SUPERCLOCK(100));
1206         tmap.set_meter (Meter (5, 7), SECONDS_TO_SUPERCLOCK(7));
1207         tmap.set_meter (Meter (4, 4), SECONDS_TO_SUPERCLOCK(24));
1208         tmap.set_meter (Meter (11, 7), SECONDS_TO_SUPERCLOCK(23));
1209
1210         tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1211
1212         tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1213         tmap.dump (std::cout);
1214
1215         return 0;
1216 }
1217
1218 std::ostream&
1219 operator<<(std::ostream& str, Meter const & m)
1220 {
1221         return str << m.divisions_per_bar() << '/' << m.note_value();
1222 }
1223
1224 std::ostream&
1225 operator<<(std::ostream& str, Tempo const & t)
1226 {
1227         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() << ')';
1228 }
1229
1230 std::ostream&
1231 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1232 {
1233         str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
1234             << (tmp.is_explicit() ? " EXP" : " imp")
1235             << " qn " << tmp.quarters ()
1236             << " bbt " << tmp.bbt()
1237             << " lock to " << tmp.lock_style()
1238                 ;
1239
1240         if (tmp.is_explicit()) {
1241                 str << " tempo " << *((Tempo*) &tmp.metric())
1242                     << " meter " << *((Meter*) &tmp.metric())
1243                         ;
1244         }
1245
1246         if (tmp.is_explicit() && tmp.ramped()) {
1247                 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();
1248         }
1249         return str;
1250 }