bb82340244bc19069061bb3388dcc785ad1424a2
[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->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_and_meter (Tempo const & tempo, Meter const & meter, superclock_t sc, bool ramp, bool flexible)
563 {
564         /* CALLER MUST HOLD 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, tempo, meter, 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 metrics */
591                 *((Tempo*) &_points.front().metric()) = tempo;
592                 *((Meter*) &_points.front().metric()) = meter;
593                 _points.front().make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
594                 return true;
595         }
596
597         /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
598
599         TempoMapPoints::iterator i = iterator_at (sc);
600         TempoMapPoints::iterator nxt = i;
601         ++nxt;
602
603         if (i->sclock() == sc) {
604                 /* change  metrics */
605                 *((Tempo*) &i->metric()) = tempo;
606                 *((Meter*) &i->metric()) = meter;
607                 i->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
608                 /* done */
609                 return true;
610         }
611
612         if (!flexible && (sc - i->sclock() < i->metric().superclocks_per_note_type())) {
613                 cerr << "new tempo too close to previous ...\n";
614                 return false;
615         }
616
617         TempoMapPoints::iterator e (i);
618         while (!e->is_explicit() && e != _points.begin()) {
619                 --e;
620         }
621
622         if (e->metric().ramped()) {
623                 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
624                    and thus defines the new ramp distance.
625                 */
626                 e->compute_c_superclock (_sample_rate, tempo.superclocks_per_quarter_note (), sc);
627         }
628
629         /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
630            even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
631            fractional.
632          */
633
634         Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
635
636         /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
637          */
638
639         Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
640
641         /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
642          */
643
644         if (i != _points.end()) {
645                 ++i;
646         }
647
648         cerr << "Insert at " << i->sclock() / superclock_ticks_per_second << endl;
649         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, qn, bbt, AudioTime, ramp));
650         return true;
651 }
652
653 bool
654 TempoMap::set_tempo (Tempo const & t, superclock_t sc, bool ramp)
655 {
656         Glib::Threads::RWLock::WriterLock lm (_lock);
657
658         assert (!_points.empty());
659
660         /* special case: first map entry is later than the new point */
661
662         if (_points.front().sclock() > sc) {
663                 /* first point is later than sc. There's no iterator to reference a point at or before sc */
664
665                 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
666                    even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
667                    fractional.
668                 */
669
670                 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
671                 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
672
673                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, t, _points.front().metric(), sc, b, bbt, AudioTime, ramp));
674                 return true;
675         }
676
677         /* special case #3: only one map entry, at the same time as the new point.
678            This is the common case when editing tempo/meter in a session with a single tempo/meter
679         */
680
681         if (_points.size() == 1 && _points.front().sclock() == sc) {
682                 /* change tempo */
683                 *((Tempo*) &_points.front().metric()) = t;
684                 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
685                 return true;
686         }
687
688         /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
689
690         TempoMapPoints::iterator i = iterator_at (sc);
691         TempoMapPoints::iterator nxt = i;
692         ++nxt;
693
694         if (i->sclock() == sc) {
695                 /* change tempo */
696                 *((Tempo*) &i->metric()) = t;
697                 i->make_explicit (TempoMapPoint::ExplicitTempo);
698                 /* done */
699                 return true;
700         }
701
702         if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
703                 cerr << "new tempo too close to previous ...\n";
704                 return false;
705         }
706
707         Meter const & meter (i->metric());
708
709         TempoMapPoints::iterator e (i);
710         while (!e->is_explicit() && e != _points.begin()) {
711                 --e;
712         }
713
714         if (e->metric().ramped()) {
715                 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
716                    and thus defines the new ramp distance.
717                 */
718                 e->compute_c_superclock (_sample_rate, t.superclocks_per_quarter_note (), sc);
719         }
720
721         /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
722            even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
723            fractional.
724          */
725
726         Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
727
728         /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
729          */
730
731         Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
732
733         /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
734          */
735
736         if (i != _points.end()) {
737                 ++i;
738         }
739         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, sc, qn, bbt, AudioTime, ramp));
740         return true;
741 }
742
743 bool
744 TempoMap::set_tempo (Tempo const & t, Timecode::BBT_Time const & bbt, bool ramp)
745 {
746         Glib::Threads::RWLock::WriterLock lm (_lock);
747
748         /* tempo changes are required to be on-beat */
749
750         Timecode::BBT_Time on_beat = bbt.round_up_to_beat();
751
752         cerr << "Try to set tempo @ " << on_beat << " to " << t << endl;
753
754         assert (!_points.empty());
755
756         if (_points.front().bbt() > on_beat) {
757                 cerr << "Cannot insert tempo at " << bbt << " before first point at " << _points.front().bbt() << endl;
758                 return false;
759         }
760
761         if (_points.size() == 1 && _points.front().bbt() == on_beat) {
762                 /* change Meter */
763                 *((Tempo*) &_points.front().metric()) = t;
764                 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
765                 return true;
766         }
767
768         TempoMapPoints::iterator i = iterator_at (on_beat);
769
770         if (i->bbt() == on_beat) {
771                 *((Tempo*) &i->metric()) = t;
772                 i->make_explicit (TempoMapPoint::ExplicitTempo);
773                 return true;
774         }
775
776         Meter const & meter (i->metric());
777         ++i;
778
779         /* stick a prototype music-locked point up front and let ::rebuild figure out the superclock and quarter time */
780         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, 0, Evoral::Beats(), on_beat, MusicTime, ramp));
781         return true;
782 }
783
784 bool
785 TempoMap::set_meter (Meter const & m, Timecode::BBT_Time const & bbt)
786 {
787         Glib::Threads::RWLock::WriterLock lm (_lock);
788         Timecode::BBT_Time measure_start (m.round_up_to_bar (bbt));
789
790         cerr << "Try to set meter @ " << measure_start << " to " << m << endl;
791
792         assert (!_points.empty());
793
794         if (_points.front().bbt() > measure_start) {
795                 cerr << "Cannot insert meter at " << bbt << " before first point at " << _points.front().bbt() << endl;
796                 return false;
797         }
798
799         if (_points.size() == 1 && _points.front().bbt() == measure_start) {
800                 /* change Meter */
801                 cerr << "Found the single point\n";
802                 *((Meter*) &_points.front().metric()) = m;
803                 cerr << "Updated meter to " << m << endl;
804                 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
805                 return true;
806         }
807
808         TempoMapPoints::iterator i = iterator_at (measure_start);
809
810         if (i->bbt() == measure_start) {
811                 *((Meter*) &i->metric()) = m;
812                 cerr << "Updated meter to " << m << endl;
813                 i->make_explicit (TempoMapPoint::ExplicitMeter);
814                 return true;
815         }
816
817         Evoral::Beats qn = i->quarters_at (measure_start);
818         superclock_t sc = i->sclock() + i->metric().superclock_at_qn (qn);
819
820         Tempo const & tempo (i->metric());
821         ++i;
822
823         cerr << "NEW METER, provisionally @ "
824              << TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime)
825              << endl;
826
827         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime));
828         return true;
829 }
830
831 bool
832 TempoMap::set_meter (Meter const & m, superclock_t sc)
833 {
834         Glib::Threads::RWLock::WriterLock lm (_lock);
835         assert (!_points.empty());
836
837         /* special case #2: first map entry is later than the new point */
838
839         if (_points.front().sclock() > sc) {
840                 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
841                    even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
842                    fractional.
843                 */
844
845                 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
846                 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
847
848                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitMeter, _points.front().metric(), m, sc, b, bbt, AudioTime));
849                 return true;
850         }
851
852         /* special case #3: only one map entry, at the same time as the new point.
853
854            This is the common case when editing tempo/meter in a session with a single tempo/meter
855         */
856
857         if (_points.size() == 1 && _points.front().sclock() == sc) {
858                 /* change meter */
859                 *((Meter*) &_points.front().metric()) = m;
860                 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
861                 return true;
862         }
863
864         TempoMapPoints::iterator i = iterator_at (sc);
865
866         if (i->sclock() == sc) {
867                 /* change meter */
868                 *((Meter*) &i->metric()) = m;
869
870                 /* enforce rule described below regarding meter change positions */
871
872                 if (i->bbt().beats != 1) {
873                         i->set_bbt (Timecode::BBT_Time (i->bbt().bars + 1, 1, 0));
874                 }
875
876                 i->make_explicit (TempoMapPoint::ExplicitMeter);
877
878                 return true;
879         }
880
881         if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
882                 cerr << "new tempo too close to previous ...\n";
883                 return false;
884         }
885
886         /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
887            even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
888            fractional.
889         */
890
891         Evoral::Beats b = i->quarters_at (sc).round_to_beat();
892
893         /* rule: all Meter changes must start a new measure. So determine the nearest, lower beat to "sc". If this is not
894            the first division of the measure, move to the next measure.
895          */
896
897         Timecode::BBT_Time bbt = i->bbt_at (b).round_down_to_beat ();
898
899         if (bbt.beats != 1) {
900                 bbt.bars += 1;
901                 bbt.beats = 1;
902                 bbt.ticks = 0;
903         }
904
905         Tempo const & tempo (i->metric());
906         ++i;
907
908         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, b, bbt, AudioTime));
909         return true;
910 }
911
912 TempoMapPoints::iterator
913 TempoMap::iterator_at (superclock_t sc)
914 {
915         /* CALLER MUST HOLD LOCK */
916
917         if (_points.empty()) {
918                 throw EmptyTempoMapException();
919         }
920
921         if (_points.size() == 1) {
922                 return _points.begin();
923         }
924
925         /* Construct an arbitrary TempoMapPoint. The only property we care about is it's superclock time,
926            so other values used in the constructor are arbitrary and irrelevant.
927         */
928
929         TempoMetric const & metric (_points.front().metric());
930         const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, sc, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
931         TempoMapPoint::SuperClockComparator scmp;
932
933         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, scmp);
934
935         if (tmp != _points.begin()) {
936                 return --tmp;
937         }
938
939         return tmp;
940 }
941
942 TempoMapPoints::iterator
943 TempoMap::iterator_at (Evoral::Beats const & qn)
944 {
945         /* CALLER MUST HOLD LOCK */
946
947         if (_points.empty()) {
948                 throw EmptyTempoMapException();
949         }
950
951         if (_points.size() == 1) {
952                 return _points.begin();
953         }
954
955         /* Construct an arbitrary TempoMapPoint. The only property we care about is its quarters time,
956            so other values used in the constructor are arbitrary and irrelevant.
957         */
958
959         TempoMetric const & metric (_points.front().metric());
960         const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, 0, qn, Timecode::BBT_Time(), AudioTime);
961         TempoMapPoint::QuarterComparator bcmp;
962
963         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
964
965         if (tmp != _points.begin()) {
966                 return --tmp;
967         }
968
969         return tmp;
970 }
971
972 TempoMapPoints::iterator
973 TempoMap::iterator_at (Timecode::BBT_Time const & bbt)
974 {
975         /* CALLER MUST HOLD LOCK */
976
977         if (_points.empty()) {
978                 throw EmptyTempoMapException();
979         }
980
981         if (_points.size() == 1) {
982                 return _points.begin();
983         }
984
985         /* Construct an arbitrary TempoMapPoint. The only property we care about is its bbt time,
986            so other values used in the constructor are arbitrary and irrelevant.
987         */
988
989         TempoMetric const & metric (_points.front().metric());
990         const TempoMapPoint tp (TempoMapPoint::Flag(0), metric, metric, 0, Evoral::Beats(), bbt, MusicTime);
991         TempoMapPoint::BBTComparator bcmp;
992
993         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
994
995         if (tmp != _points.begin()) {
996                 return --tmp;
997         }
998
999         return tmp;
1000 }
1001
1002 Timecode::BBT_Time
1003 TempoMap::bbt_at (superclock_t sc) const
1004 {
1005         Glib::Threads::RWLock::ReaderLock lm (_lock);
1006         return bbt_at_locked (sc);
1007 }
1008
1009 Timecode::BBT_Time
1010 TempoMap::bbt_at_locked (superclock_t sc) const
1011 {
1012         TempoMapPoint point (const_point_at (sc));
1013         Evoral::Beats b ((sc - point.sclock()) / (double) point.metric().superclocks_per_quarter_note());
1014         return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, b.get_beats(), b.get_ticks()));
1015 }
1016
1017 Timecode::BBT_Time
1018 TempoMap::bbt_at (Evoral::Beats const & qn) const
1019 {
1020         Glib::Threads::RWLock::ReaderLock lm (_lock);
1021         return bbt_at_locked (qn);
1022 }
1023
1024 Timecode::BBT_Time
1025 TempoMap::bbt_at_locked (Evoral::Beats const & qn) const
1026 {
1027         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1028         TempoMapPoint const & point (const_point_at (qn));
1029         Evoral::Beats delta (qn - point.quarters());
1030         return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, delta.get_beats(), delta.get_ticks()));
1031 }
1032
1033 Evoral::Beats
1034 TempoMap::quarter_note_at (superclock_t sc) const
1035 {
1036         Glib::Threads::RWLock::ReaderLock lm (_lock);
1037         return quarter_note_at_locked (sc);
1038 }
1039
1040 Evoral::Beats
1041 TempoMap::quarter_note_at_locked (superclock_t sc) const
1042 {
1043         return const_point_at (sc).quarters_at (sc);
1044 }
1045
1046 Evoral::Beats
1047 TempoMap::quarter_note_at (Timecode::BBT_Time const & bbt) const
1048 {
1049         Glib::Threads::RWLock::ReaderLock lm (_lock);
1050         return quarter_note_at_locked (bbt);
1051 }
1052
1053 Evoral::Beats
1054 TempoMap::quarter_note_at_locked (Timecode::BBT_Time const & bbt) const
1055 {
1056         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1057         TempoMapPoint const & point (const_point_at (bbt));
1058
1059         Timecode::BBT_Time bbt_delta (point.metric().bbt_subtract (bbt, point.bbt()));
1060         /* XXX need to convert the metric division to quarters to match Evoral::Beats == Evoral::Quarters */
1061         return point.quarters() + Evoral::Beats ((point.metric().divisions_per_bar() * bbt_delta.bars) + bbt_delta.beats, bbt_delta.ticks);
1062 }
1063
1064 superclock_t
1065 TempoMap::superclock_at (Evoral::Beats const & qn) const
1066 {
1067         Glib::Threads::RWLock::ReaderLock lm (_lock);
1068         return superclock_at_locked (qn);
1069 }
1070
1071 superclock_t
1072 TempoMap::superclock_at_locked (Evoral::Beats const & qn) const
1073 {
1074         assert (!_points.empty());
1075
1076         /* only the quarters property matters, since we're just using it to compare */
1077         const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, qn, Timecode::BBT_Time(), MusicTime);
1078         TempoMapPoint::QuarterComparator bcmp;
1079
1080         TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1081
1082         if (i == _points.end()) {
1083                 --i;
1084         }
1085
1086         /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1087
1088         const Evoral::Beats q_delta = qn - i->quarters();
1089         superclock_t sclock_delta = i->metric().superclocks_per_quarter_note () * q_delta;
1090         return i->sclock() + sclock_delta;
1091 }
1092
1093 superclock_t
1094 TempoMap::superclock_at (Timecode::BBT_Time const & bbt) const
1095 {
1096         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1097         return superclock_at_locked (bbt);
1098 }
1099
1100 superclock_t
1101 TempoMap::superclock_at_locked (Timecode::BBT_Time const & bbt) const
1102 {
1103         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1104         assert (!_points.empty());
1105
1106         /* only the bbt property matters, since we're just using it to compare */
1107         const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, Evoral::Beats(), bbt, MusicTime);
1108         TempoMapPoint::BBTComparator bcmp;
1109
1110         TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1111
1112         if (i == _points.end()) {
1113                 --i;
1114         }
1115
1116         /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1117
1118         //const Evoral::Beats delta = b - i->beats();
1119         //return i->sclock() + samples_to_superclock ((delta / i->metric().quarter_notes_per_minute ()).to_double() * _sample_rate, _sample_rate);
1120         return 0;
1121 }
1122
1123 void
1124 TempoMap::set_sample_rate (framecnt_t new_sr)
1125 {
1126         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1127         double ratio = new_sr / (double) _sample_rate;
1128
1129         for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1130                 i->map_reset_set_sclock_for_sr_change (llrint (ratio * i->sclock()));
1131         }
1132 }
1133
1134 void
1135 TempoMap::dump (std::ostream& ostr)
1136 {
1137         Glib::Threads::RWLock::ReaderLock lm (_lock);
1138         dump_locked (ostr);
1139 }
1140
1141 void
1142 TempoMap::dump_locked (std::ostream& ostr)
1143 {
1144         ostr << "\n\n------------\n";
1145         for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1146                 ostr << *i << std::endl;
1147         }
1148 }
1149
1150 void
1151 TempoMap::remove_explicit_point (superclock_t sc)
1152 {
1153         Glib::Threads::RWLock::WriterLock lm (_lock);
1154         TempoMapPoints::iterator p = iterator_at (sc);
1155
1156         if (p->sclock() == sc) {
1157                 _points.erase (p);
1158         }
1159 }
1160
1161 bool
1162 TempoMap::move_to (superclock_t current, superclock_t destination, bool push)
1163 {
1164         Glib::Threads::RWLock::WriterLock lm (_lock);
1165         TempoMapPoints::iterator p = iterator_at (current);
1166
1167         if (p->sclock() != current) {
1168                 cerr << "No point @ " << current << endl;
1169                 return false;
1170         }
1171
1172         const Meter meter (p->metric());
1173         const Tempo tempo (p->metric());
1174         const bool ramp = p->ramped();
1175
1176         _points.erase (p);
1177
1178         return set_tempo_and_meter (tempo, meter, destination, ramp, true);
1179 }
1180
1181 void
1182 TempoMap::get_grid (TempoMapPoints& ret, superclock_t start, superclock_t end)
1183 {
1184         Glib::Threads::RWLock::ReaderLock lm (_lock);
1185         TempoMapPoints::iterator p = iterator_at (start);
1186
1187         while (p != _points.end() && p->sclock() < start) {
1188                 ++p;
1189         }
1190
1191         while (p != _points.end() && p->sclock() < end) {
1192                 ret.push_back (*p);
1193                 ++p;
1194         }
1195 }
1196
1197 std::ostream&
1198 operator<<(std::ostream& str, Meter const & m)
1199 {
1200         return str << m.divisions_per_bar() << '/' << m.note_value();
1201 }
1202
1203 std::ostream&
1204 operator<<(std::ostream& str, Tempo const & t)
1205 {
1206         return str << t.note_types_per_minute() << " 1/" << t.note_type() << " notes per minute (" << t.superclocks_per_note_type() << " sc-per-1/" << t.note_type() << ')';
1207 }
1208
1209 std::ostream&
1210 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1211 {
1212         str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
1213             << (tmp.is_explicit() ? " EXP" : " imp")
1214             << " qn " << tmp.quarters ()
1215             << " bbt " << tmp.bbt()
1216             << " lock to " << tmp.lock_style()
1217                 ;
1218
1219         if (tmp.is_explicit()) {
1220                 str << " tempo " << *((Tempo*) &tmp.metric())
1221                     << " meter " << *((Meter*) &tmp.metric())
1222                         ;
1223         }
1224
1225         if (tmp.is_explicit() && tmp.ramped()) {
1226                 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();
1227         }
1228         return str;
1229 }
1230
1231 /*******/
1232
1233 #define SAMPLERATE 48000
1234 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1235
1236 using std::cerr;
1237 using std::cout;
1238 using std::endl;
1239
1240 void
1241 test_bbt_math ()
1242 {
1243         using namespace Timecode;
1244
1245         BBT_Time a;
1246         BBT_Time b1 (1,1,1919);
1247         BBT_Time n1 (-1,1,1919);
1248         std::vector<Meter> meters;
1249
1250         meters.push_back (Meter (4, 4));
1251         meters.push_back (Meter (5, 8));
1252         meters.push_back (Meter (11, 7));
1253         meters.push_back (Meter (3, 4));
1254
1255 #define PRINT_RESULT(m,str,op,op1,Bars,Beats,Ticks) cout << m << ' ' << (op1) << ' ' << str << ' ' << BBT_Offset ((Bars),(Beats),(Ticks)) << " = " << m.op ((op1), BBT_Offset ((Bars), (Beats), (Ticks))) << endl;
1256
1257         for (std::vector<Meter>::iterator m = meters.begin(); m != meters.end(); ++m) {
1258                 for (int B = 1; B < 4; ++B) {
1259                         for (int b = 1; b < 13; ++b) {
1260                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 0);
1261                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 1);
1262                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN/2);
1263                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN);
1264                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 1);
1265                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 2);
1266
1267                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 0);
1268                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 1);
1269                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN/2);
1270                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN);
1271                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 1);
1272                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 2);
1273
1274                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 0);
1275                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 1);
1276                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN/2);
1277                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN);
1278                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 1);
1279                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 2);
1280                         }
1281                 }
1282
1283                 for (int B = 1; B < 4; ++B) {
1284                         for (int b = 1; b < 13; ++b) {
1285                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 0);
1286                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 1);
1287                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN/2);
1288                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN);
1289                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 1);
1290                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 2);
1291                         }
1292                 }
1293         }
1294 }
1295
1296 int
1297 main ()
1298 {
1299         TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1300
1301         //test_bbt_math ();
1302         //return 0;
1303
1304         tmap.set_tempo (Tempo (7), SECONDS_TO_SUPERCLOCK(7));
1305         tmap.set_tempo (Tempo (23), SECONDS_TO_SUPERCLOCK(23));
1306         tmap.set_tempo (Tempo (24), SECONDS_TO_SUPERCLOCK(24), true);
1307         tmap.set_tempo (Tempo (40), SECONDS_TO_SUPERCLOCK(28), true);
1308         tmap.set_tempo (Tempo (100), SECONDS_TO_SUPERCLOCK(100));
1309         tmap.set_tempo (Tempo (123), SECONDS_TO_SUPERCLOCK(23));
1310
1311         tmap.set_meter (Meter (3, 4), SECONDS_TO_SUPERCLOCK(23));
1312         tmap.set_meter (Meter (5, 8), SECONDS_TO_SUPERCLOCK(100));
1313         tmap.set_meter (Meter (5, 7), SECONDS_TO_SUPERCLOCK(7));
1314         tmap.set_meter (Meter (4, 4), SECONDS_TO_SUPERCLOCK(24));
1315         tmap.set_meter (Meter (11, 7), SECONDS_TO_SUPERCLOCK(23));
1316
1317         tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1318
1319         tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1320         tmap.dump (std::cout);
1321
1322         if (tmap.move_to (SECONDS_TO_SUPERCLOCK(23), SECONDS_TO_SUPERCLOCK (72))) {
1323                 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1324                 tmap.dump (std::cout);
1325         }
1326
1327         TempoMapPoints grid;
1328         tmap.get_grid (grid, SECONDS_TO_SUPERCLOCK (12), SECONDS_TO_SUPERCLOCK (44));
1329         cout << "grid contains " << grid.size() << endl;
1330         for (TempoMapPoints::iterator p = grid.begin(); p != grid.end(); ++p) {
1331                 cout << *p << endl;
1332         }
1333
1334         return 0;
1335 }