more changes to broken-out tempo code
[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         b += (offset.beats * 4) / _note_value;
145         b += Evoral::Beats::ticks (offset.ticks);
146
147         return b;
148 }
149
150 superclock_t
151 TempoMetric::superclock_per_note_type_at_superclock (superclock_t sc) const
152 {
153         return superclocks_per_note_type () * expm1 (_c_per_superclock * sc);
154 }
155
156 superclock_t
157 TempoMetric::superclocks_per_grid (framecnt_t sr) const
158 {
159         return (superclock_ticks_per_second * Meter::note_value()) / (note_types_per_minute() / Tempo::note_type());
160 }
161
162 superclock_t
163 TempoMetric::superclocks_per_bar (framecnt_t sr) const
164 {
165         return superclocks_per_grid (sr) * _divisions_per_bar;
166 }
167
168 /*
169 Ramp Overview
170
171       |                     *
172 Tempo |                   *
173 Tt----|-----------------*|
174 Ta----|--------------|*  |
175       |            * |   |
176       |         *    |   |
177       |     *        |   |
178 T0----|*             |   |
179   *   |              |   |
180       _______________|___|____
181       time           a   t (next tempo)
182       [        c         ] defines c
183
184 Duration in beats at time a is the integral of some Tempo function.
185 In our case, the Tempo function (Tempo at time t) is
186 T(t) = T0(e^(ct))
187
188 >>1/S(t) = (1/S0)(e^ct) => (1/S)(t) = (e^(ct))/S0 => S(t) = S0/(e^(ct))
189
190 with function constant
191 c = log(Ta/T0)/a
192
193 >>c = log ((1/Sa)/(1/S0)) / a => c = log (S0/Sa) / a
194
195 so
196 a = log(Ta/T0)/c
197
198 >>a = log ((1/Ta)/(1/S0) / c => a = log (S0/Sa) / c
199
200 The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
201 b(t) = T0(e^(ct) - 1) / c
202
203 >>b(t) = 1/S0(e^(ct) - 1) / c  => b(t) = (e^(ct) - 1) / (c * S0)
204
205 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:
206 t(b) = log((c.b / T0) + 1) / c
207
208 >>t(b) = log((c*b / (1/S0)) + 1) / c => t(b) = log ((c*b * S0) + 1) / c
209
210 The time t at which Tempo T occurs is a as above:
211 t(T) = log(T / T0) / c
212
213 >> t(1/S) = log ((1/S) / (1/S0) /c => t(1/S) = log (S0/S) / c
214
215 The beat at which a Tempo T occurs is:
216 b(T) = (T - T0) / c
217
218 >> b(1/S) = (1/S - 1/S0) / c
219
220 The Tempo at which beat b occurs is:
221 T(b) = b.c + T0
222
223 >> T(b) = b.c + (1/S0)
224
225 We define c for this tempo ramp by placing a new tempo section at some time t after this one.
226 Our problem is that we usually don't know t.
227 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.
228 Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
229 t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
230
231 By substituting our expanded t as a in the c function above, our problem is reduced to:
232 c = T0 (e^(log (Ta / T0)) - 1) / b
233
234 >> 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)
235
236 Of course the word 'beat' has been left loosely defined above.
237 In music, a beat is defined by the musical pulse (which comes from the tempo)
238 and the meter in use at a particular time (how many  pulse divisions there are in one bar).
239 It would be more accurate to substitute the work 'pulse' for 'beat' above.
240
241  */
242
243 /* equation to compute c is:
244  *
245  *    c = log (Ta / T0) / a
246  *
247  * where
248  *
249  *   a : time into section (from section start
250  *  T0 : tempo at start of section
251  *  Ta : tempo at time a into section
252  *
253  * THE UNITS QUESTION
254  *
255  * log (Ta / T0) / (time-units) => C is in per-time-units (1/time-units)
256  *
257  * so the question is what are the units of a, and thus c?
258  *
259  * we could use ANY time units (because we can measure a in any time units)
260  * but whichever one we pick dictates how we can use c in the future since
261  * all subsequent computations will need to use the same time units.
262  *
263  * options:
264  *
265  *    pulses        ... whole notes, possibly useful, since we can use it for any other note_type
266  *    quarter notes ... linearly related to pulses
267  *    beats         ... not a fixed unit of time
268  *    minutes       ... linearly related to superclocks
269  *    samples       ... needs sample rate
270  *    superclocks   ... frequently correct
271  *
272  * so one answer might be to compute c in two different units so that we have both available.
273  *
274  * hence, compute_c_superclocks() and compute_c_pulses()
275  */
276
277 void
278 TempoMetric::compute_c_superclock (framecnt_t sr, superclock_t end_scpqn, superclock_t superclock_duration)
279 {
280         if ((superclocks_per_quarter_note() == end_scpqn) || !ramped()) {
281                 _c_per_superclock = 0.0;
282                 return;
283         }
284
285         _c_per_superclock = log ((double) superclocks_per_quarter_note () / end_scpqn) / superclock_duration;
286 }
287 void
288 TempoMetric::compute_c_quarters (framecnt_t sr, superclock_t end_scpqn, Evoral::Beats const & quarter_duration)
289 {
290         if ((superclocks_per_quarter_note () == end_scpqn) || !ramped()) {
291                 _c_per_quarter = 0.0;
292                 return;
293         }
294
295         _c_per_quarter = log (superclocks_per_quarter_note () / (double) end_scpqn) /  quarter_duration.to_double();
296 }
297
298 superclock_t
299 TempoMetric::superclock_at_qn (Evoral::Beats const & qn) const
300 {
301         if (_c_per_quarter == 0.0) {
302                 /* not ramped, use linear */
303                 return llrint (superclocks_per_quarter_note () * qn.to_double());
304         }
305
306         return llrint (superclocks_per_quarter_note() * (log1p (_c_per_quarter * qn.to_double()) / _c_per_quarter));
307 }
308
309 Evoral::Beats
310 TempoMapPoint::quarters_at (superclock_t sc) const
311 {
312         /* This TempoMapPoint must already have a fully computed metric and position */
313
314         if (!ramped()) {
315                 return _quarters + Evoral::Beats ((sc - _sclock) / (double) (metric().superclocks_per_quarter_note ()));
316         }
317
318         return _quarters + Evoral::Beats (expm1 (metric().c_per_superclock() * (sc - _sclock)) / (metric().c_per_superclock() * metric().superclocks_per_quarter_note ()));
319 }
320
321 Evoral::Beats
322 TempoMapPoint::quarters_at (Timecode::BBT_Time const & bbt) const
323 {
324         /* This TempoMapPoint must already have a fully computed metric and position */
325
326         Timecode::BBT_Offset offset = metric().bbt_delta (bbt, _bbt);
327         return _quarters + metric().to_quarters (offset);
328 }
329
330 Timecode::BBT_Time
331 TempoMapPoint::bbt_at (Evoral::Beats const & qn) const
332 {
333         /* This TempoMapPoint must already have a fully computed metric and position */
334
335         Evoral::Beats quarters_delta = qn - _quarters;
336         int32_t ticks_delta = quarters_delta.to_ticks (Evoral::Beats::PPQN);
337         return metric().bbt_add (_bbt, Timecode::BBT_Offset (0, 0,  ticks_delta));
338 }
339
340 TempoMap::TempoMap (Tempo const & initial_tempo, Meter const & initial_meter, framecnt_t sr)
341         : _sample_rate (sr)
342 {
343         TempoMapPoint tmp (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo), initial_tempo, initial_meter, 0, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
344         _points.push_back (tmp);
345 }
346
347 Meter const &
348 TempoMap::meter_at (superclock_t sc) const
349 {
350         Glib::Threads::RWLock::ReaderLock lm (_lock);
351         return meter_at_locked (sc);
352 }
353
354 Meter const &
355 TempoMap::meter_at (Evoral::Beats const & b) const
356 {
357         Glib::Threads::RWLock::ReaderLock lm (_lock);
358         return meter_at_locked (b);
359 }
360
361 Meter const &
362 TempoMap::meter_at (Timecode::BBT_Time const & bbt) const
363 {
364         Glib::Threads::RWLock::ReaderLock lm (_lock);
365         return meter_at_locked (bbt);
366 }
367
368 Tempo const &
369 TempoMap::tempo_at (superclock_t sc) const
370 {
371         Glib::Threads::RWLock::ReaderLock lm (_lock);
372         return tempo_at_locked (sc);
373 }
374
375 Tempo const &
376 TempoMap::tempo_at (Evoral::Beats const &b) const
377 {
378         Glib::Threads::RWLock::ReaderLock lm (_lock);
379         return tempo_at_locked (b);
380 }
381
382 Tempo const &
383 TempoMap::tempo_at (Timecode::BBT_Time const & bbt) const
384 {
385         Glib::Threads::RWLock::ReaderLock lm (_lock);
386         return tempo_at_locked (bbt);
387 }
388
389 void
390 TempoMap::rebuild (superclock_t limit)
391 {
392         Glib::Threads::RWLock::WriterLock lm (_lock);
393
394         /* step one: remove all implicit points after a dirty explicit point */
395
396   restart:
397         TempoMapPoints::iterator tmp = _points.begin();
398         TempoMapPoints::iterator first_explicit_dirty = _points.end();
399
400         while ((tmp != _points.end()) && (tmp->is_implicit() || (tmp->is_explicit() && !tmp->dirty ()))) {
401                 ++tmp;
402         }
403
404         first_explicit_dirty = tmp;
405
406         if (first_explicit_dirty == _points.end()) {
407                 /* nothing is dirty */
408                 return;
409         }
410
411         /* remove all implicit points, because we're going to recalculate them all */
412
413         while (tmp != _points.end()) {
414                 TempoMapPoints::iterator next = tmp;
415                 ++next;
416
417                 if (tmp->is_implicit()) {
418                         _points.erase (tmp);
419                 }
420
421                 tmp = next;
422         }
423
424         /* compute C-by-quarters for all ramped sections, because we need it shortly */
425
426         for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
427                 TempoMapPoints::iterator nxt = tmp;
428                 ++nxt;
429
430                 if (tmp->ramped() && (nxt != _points.end())) {
431                         tmp->compute_c_quarters (_sample_rate, nxt->metric().superclocks_per_quarter_note (), nxt->quarters() - tmp->quarters());
432                 }
433
434                 tmp = nxt;
435         }
436
437         TempoMapPoints::iterator prev = _points.end();
438
439         /* Compute correct quarter-note and superclock times for all music-time locked explicit points */
440
441         for (tmp = first_explicit_dirty; tmp != _points.end(); ) {
442
443                 TempoMapPoints::iterator next = tmp;
444                 ++next;
445
446                 if (prev != _points.end()) {
447                         if ((tmp->lock_style() == MusicTime)) {
448                                 /* determine superclock and quarter note time for this (music-time) locked point */
449
450                                 Evoral::Beats qn = prev->quarters_at (tmp->bbt());
451                                 superclock_t sc = prev->sclock() + prev->metric().superclock_at_qn (qn - prev->quarters());
452
453                                 if (qn != tmp->quarters() || tmp->sclock() != sc) {
454                                         tmp->set_quarters (qn);
455                                         tmp->set_sclock (sc);
456                                         _points.sort (TempoMapPoint::SuperClockComparator());
457                                         goto restart;
458                                 }
459                         }
460                 }
461
462                 prev = tmp;
463                 tmp = next;
464         }
465
466         /* _points is guaranteed sorted in superclock and quarter note order. It may not be sorted BBT order because of re-ordering
467          * of music-time locked points.
468          */
469
470         prev = _points.end();
471
472         /* step two: add new implicit points between each pair of explicit
473          * points, after the dirty explicit point
474          */
475
476         bool hit_dirty = false;
477
478         for (tmp = _points.begin(); tmp != _points.end(); ) {
479
480                 if (!hit_dirty) {
481                         if (!tmp->dirty()) {
482                                 ++tmp;
483                                 continue;
484                         }
485                         hit_dirty = true;
486                 }
487
488                 TempoMapPoints::iterator next = tmp;
489                 ++next;
490
491
492                 if (prev != _points.end()) {
493                         if ((tmp->lock_style() == AudioTime)) {
494                                 /* audio-locked explicit point: recompute it's BBT and quarter-note position since this may have changed */
495                                 tmp->set_quarters (prev->quarters_at (tmp->sclock()));
496                                 if (static_cast<Meter>(tmp->metric()) != static_cast<Meter>(prev->metric())) {
497                                         /* new meter, must be on bar/measure start */
498                                         tmp->set_bbt (prev->metric().round_up_to_bar (prev->bbt_at (tmp->quarters())));
499                                 } else {
500                                         /* no meter change, tempo change required to be on beat */
501                                         tmp->set_bbt (prev->bbt_at (tmp->quarters()).round_up_to_beat());
502                                 }
503                         }
504                 }
505
506                 superclock_t sc = tmp->sclock();
507                 Evoral::Beats qn (tmp->quarters ());
508                 Timecode::BBT_Time bbt (tmp->bbt());
509                 const bool ramped = tmp->ramped () && next != _points.end();
510
511                 /* Evoral::Beats are really quarter notes. This counts how many quarter notes
512                    there are between grid points in this section of the tempo map.
513                  */
514                 const Evoral::Beats qn_step = (Evoral::Beats (1) * 4) / tmp->metric().note_value();
515
516                 /* compute implicit points as far as the next explicit point, or limit,
517                    whichever comes first.
518                 */
519
520                 const superclock_t sc_limit = (next == _points.end() ? limit : (*next).sclock());
521
522                 while (1) {
523
524                         /* define next beat in superclocks, beats and bbt */
525
526                         qn += qn_step;
527                         bbt = tmp->metric().bbt_add (bbt, Timecode::BBT_Offset (0, 1, 0));
528
529                         if (!ramped) {
530                                 sc += tmp->metric().superclocks_per_note_type();
531                         } else {
532                                 sc = tmp->sclock() + tmp->metric().superclock_at_qn (qn - tmp->quarters());
533                         }
534
535                         if (sc >= sc_limit) {
536                                 break;
537                         }
538
539                         _points.insert (next, TempoMapPoint (*tmp, sc, qn, bbt));
540                 }
541
542                 (*tmp).set_dirty (false);
543                 prev = tmp;
544                 tmp = next;
545         }
546 }
547
548 bool
549 TempoMap::set_tempo_and_meter (Tempo const & tempo, Meter const & meter, superclock_t sc, bool ramp, bool flexible)
550 {
551         /* CALLER MUST HOLD LOCK */
552
553         assert (!_points.empty());
554
555         /* special case: first map entry is later than the new point */
556
557         if (_points.front().sclock() > sc) {
558                 /* first point is later than sc. There's no iterator to reference a point at or before sc */
559
560                 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
561                    even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
562                    fractional.
563                 */
564
565                 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
566                 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
567
568                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, b, bbt, AudioTime, ramp));
569                 return true;
570         }
571
572         /* special case #3: only one map entry, at the same time as the new point.
573            This is the common case when editing tempo/meter in a session with a single tempo/meter
574         */
575
576         if (_points.size() == 1 && _points.front().sclock() == sc) {
577                 /* change metrics */
578                 *((Tempo*) &_points.front().metric()) = tempo;
579                 *((Meter*) &_points.front().metric()) = meter;
580                 _points.front().make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
581                 return true;
582         }
583
584         /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
585
586         TempoMapPoints::iterator i = iterator_at (sc);
587         TempoMapPoints::iterator nxt = i;
588         ++nxt;
589
590         if (i->sclock() == sc) {
591                 /* change  metrics */
592                 *((Tempo*) &i->metric()) = tempo;
593                 *((Meter*) &i->metric()) = meter;
594                 i->make_explicit (TempoMapPoint::Flag (TempoMapPoint::ExplicitTempo|TempoMapPoint::ExplicitMeter));
595                 /* done */
596                 return true;
597         }
598
599         if (!flexible && (sc - i->sclock() < i->metric().superclocks_per_note_type())) {
600                 cerr << "new tempo too close to previous ...\n";
601                 return false;
602         }
603
604         TempoMapPoints::iterator e (i);
605         while (!e->is_explicit() && e != _points.begin()) {
606                 --e;
607         }
608
609         if (e->metric().ramped()) {
610                 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
611                    and thus defines the new ramp distance.
612                 */
613                 e->compute_c_superclock (_sample_rate, tempo.superclocks_per_quarter_note (), sc);
614         }
615
616         /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
617            even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
618            fractional.
619          */
620
621         Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
622
623         /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
624          */
625
626         Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
627
628         /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
629          */
630
631         if (i != _points.end()) {
632                 ++i;
633         }
634
635         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, tempo, meter, sc, qn, bbt, AudioTime, ramp));
636         return true;
637 }
638
639 bool
640 TempoMap::set_tempo (Tempo const & t, superclock_t sc, bool ramp)
641 {
642         Glib::Threads::RWLock::WriterLock lm (_lock);
643
644         assert (!_points.empty());
645
646         /* special case: first map entry is later than the new point */
647
648         if (_points.front().sclock() > sc) {
649                 /* first point is later than sc. There's no iterator to reference a point at or before sc */
650
651                 /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
652                    even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
653                    fractional.
654                 */
655
656                 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
657                 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
658
659                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitTempo, t, _points.front().metric(), sc, b, bbt, AudioTime, ramp));
660                 return true;
661         }
662
663         /* special case #3: only one map entry, at the same time as the new point.
664            This is the common case when editing tempo/meter in a session with a single tempo/meter
665         */
666
667         if (_points.size() == 1 && _points.front().sclock() == sc) {
668                 /* change tempo */
669                 *((Tempo*) &_points.front().metric()) = t;
670                 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
671                 return true;
672         }
673
674         /* Remember: iterator_at() returns an iterator that references the TempoMapPoint at or BEFORE sc */
675
676         TempoMapPoints::iterator i = iterator_at (sc);
677         TempoMapPoints::iterator nxt = i;
678         ++nxt;
679
680         if (i->sclock() == sc) {
681                 /* change tempo */
682                 *((Tempo*) &i->metric()) = t;
683                 i->make_explicit (TempoMapPoint::ExplicitTempo);
684                 /* done */
685                 return true;
686         }
687
688         if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
689                 cerr << "new tempo too close to previous ...\n";
690                 return false;
691         }
692
693         Meter const & meter (i->metric());
694
695         TempoMapPoints::iterator e (i);
696         while (!e->is_explicit() && e != _points.begin()) {
697                 --e;
698         }
699
700         if (e->metric().ramped()) {
701                 /* need to adjust ramp constants for preceding explict point, since the new point will be positioned right after it
702                    and thus defines the new ramp distance.
703                 */
704                 e->compute_c_superclock (_sample_rate, t.superclocks_per_quarter_note (), sc);
705         }
706
707         /* determine beats and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
708            even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
709            fractional.
710          */
711
712         Evoral::Beats qn = i->quarters_at (sc).round_to_beat();
713
714         /* rule: all Tempo changes must be on-beat. So determine the nearest later beat to "sc"
715          */
716
717         Timecode::BBT_Time bbt = i->bbt_at (qn).round_up_to_beat ();
718
719         /* Modify the iterator to reference the point AFTER this new one, because STL insert is always "insert-before"
720          */
721
722         if (i != _points.end()) {
723                 ++i;
724         }
725         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, sc, qn, bbt, AudioTime, ramp));
726         return true;
727 }
728
729 bool
730 TempoMap::set_tempo (Tempo const & t, Timecode::BBT_Time const & bbt, bool ramp)
731 {
732         Glib::Threads::RWLock::WriterLock lm (_lock);
733
734         /* tempo changes are required to be on-beat */
735
736         Timecode::BBT_Time on_beat = bbt.round_up_to_beat();
737
738         assert (!_points.empty());
739
740         if (_points.front().bbt() > on_beat) {
741                 cerr << "Cannot insert tempo at " << bbt << " before first point at " << _points.front().bbt() << endl;
742                 return false;
743         }
744
745         if (_points.size() == 1 && _points.front().bbt() == on_beat) {
746                 /* change Meter */
747                 *((Tempo*) &_points.front().metric()) = t;
748                 _points.front().make_explicit (TempoMapPoint::ExplicitTempo);
749                 return true;
750         }
751
752         TempoMapPoints::iterator i = iterator_at (on_beat);
753
754         if (i->bbt() == on_beat) {
755                 *((Tempo*) &i->metric()) = t;
756                 i->make_explicit (TempoMapPoint::ExplicitTempo);
757                 return true;
758         }
759
760         Meter const & meter (i->metric());
761         ++i;
762
763         /* stick a prototype music-locked point up front and let ::rebuild figure out the superclock and quarter time */
764         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitTempo, t, meter, 0, Evoral::Beats(), on_beat, MusicTime, ramp));
765         return true;
766 }
767
768 bool
769 TempoMap::set_meter (Meter const & m, Timecode::BBT_Time const & bbt)
770 {
771         Glib::Threads::RWLock::WriterLock lm (_lock);
772         Timecode::BBT_Time measure_start (m.round_up_to_bar (bbt));
773
774         assert (!_points.empty());
775
776         if (_points.front().bbt() > measure_start) {
777                 cerr << "Cannot insert meter at " << bbt << " before first point at " << _points.front().bbt() << endl;
778                 return false;
779         }
780
781         if (_points.size() == 1 && _points.front().bbt() == measure_start) {
782                 /* change Meter */
783                 *((Meter*) &_points.front().metric()) = m;
784                 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
785                 return true;
786         }
787
788         TempoMapPoints::iterator i = iterator_at (measure_start);
789
790         if (i->bbt() == measure_start) {
791                 *((Meter*) &i->metric()) = m;
792                 i->make_explicit (TempoMapPoint::ExplicitMeter);
793                 return true;
794         }
795
796         Evoral::Beats qn = i->quarters_at (measure_start);
797         superclock_t sc = i->sclock() + i->metric().superclock_at_qn (qn);
798
799         Tempo const & tempo (i->metric());
800         ++i;
801
802         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, qn, measure_start, MusicTime));
803         return true;
804 }
805
806 bool
807 TempoMap::set_meter (Meter const & m, superclock_t sc)
808 {
809         Glib::Threads::RWLock::WriterLock lm (_lock);
810         assert (!_points.empty());
811
812         /* special case #2: first map entry is later than the new point */
813
814         if (_points.front().sclock() > sc) {
815                 /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
816                    even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
817                    fractional.
818                 */
819
820                 Evoral::Beats b = _points.front().quarters_at (sc).round_to_beat();
821                 Timecode::BBT_Time bbt = _points.front().bbt_at (b).round_to_beat ();
822
823                 _points.insert (_points.begin(), TempoMapPoint (TempoMapPoint::ExplicitMeter, _points.front().metric(), m, sc, b, bbt, AudioTime));
824                 return true;
825         }
826
827         /* special case #3: only one map entry, at the same time as the new point.
828
829            This is the common case when editing tempo/meter in a session with a single tempo/meter
830         */
831
832         if (_points.size() == 1 && _points.front().sclock() == sc) {
833                 /* change meter */
834                 *((Meter*) &_points.front().metric()) = m;
835                 _points.front().make_explicit (TempoMapPoint::ExplicitMeter);
836                 return true;
837         }
838
839         TempoMapPoints::iterator i = iterator_at (sc);
840
841         if (i->sclock() == sc) {
842                 /* change meter */
843                 *((Meter*) &i->metric()) = m;
844
845                 /* enforce rule described below regarding meter change positions */
846
847                 if (i->bbt().beats != 1) {
848                         i->set_bbt (Timecode::BBT_Time (i->bbt().bars + 1, 1, 0));
849                 }
850
851                 i->make_explicit (TempoMapPoint::ExplicitMeter);
852
853                 return true;
854         }
855
856         if (sc - i->sclock() < i->metric().superclocks_per_note_type()) {
857                 cerr << "new tempo too close to previous ...\n";
858                 return false;
859         }
860
861         /* determine quarters and BBT time for this new tempo point. Note that tempo changes (points) must be deemed to be on beat,
862            even if the user moves them later. Even after moving, the TempoMapPoint that was beat N is still beat N, and is not
863            fractional.
864         */
865
866         Evoral::Beats b = i->quarters_at (sc).round_to_beat();
867
868         /* rule: all Meter changes must start a new measure. So determine the nearest, lower beat to "sc". If this is not
869            the first division of the measure, move to the next measure.
870          */
871
872         Timecode::BBT_Time bbt = i->bbt_at (b).round_down_to_beat ();
873
874         if (bbt.beats != 1) {
875                 bbt.bars += 1;
876                 bbt.beats = 1;
877                 bbt.ticks = 0;
878         }
879
880         Tempo const & tempo (i->metric());
881         ++i;
882
883         _points.insert (i, TempoMapPoint (TempoMapPoint::ExplicitMeter, tempo, m, sc, b, bbt, AudioTime));
884         return true;
885 }
886
887 TempoMapPoints::iterator
888 TempoMap::iterator_at (superclock_t sc)
889 {
890         /* CALLER MUST HOLD LOCK */
891
892         if (_points.empty()) {
893                 throw EmptyTempoMapException();
894         }
895
896         if (_points.size() == 1) {
897                 return _points.begin();
898         }
899
900         /* Construct an arbitrary TempoMapPoint. The only property we care about is it's superclock time,
901            so other values used in the constructor are arbitrary and irrelevant.
902         */
903
904         TempoMetric const & metric (_points.front().metric());
905         const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, sc, Evoral::Beats(), Timecode::BBT_Time(), AudioTime);
906         TempoMapPoint::SuperClockComparator scmp;
907
908         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, scmp);
909
910         if (tmp != _points.begin()) {
911                 return --tmp;
912         }
913
914         return tmp;
915 }
916
917 TempoMapPoints::iterator
918 TempoMap::iterator_at (Evoral::Beats const & qn)
919 {
920         /* CALLER MUST HOLD LOCK */
921
922         if (_points.empty()) {
923                 throw EmptyTempoMapException();
924         }
925
926         if (_points.size() == 1) {
927                 return _points.begin();
928         }
929
930         /* Construct an arbitrary TempoMapPoint. The only property we care about is its quarters time,
931            so other values used in the constructor are arbitrary and irrelevant.
932         */
933
934         TempoMetric const & metric (_points.front().metric());
935         const TempoMapPoint tp (TempoMapPoint::Flag (0), metric, metric, 0, qn, Timecode::BBT_Time(), AudioTime);
936         TempoMapPoint::QuarterComparator bcmp;
937
938         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
939
940         if (tmp != _points.begin()) {
941                 return --tmp;
942         }
943
944         return tmp;
945 }
946
947 TempoMapPoints::iterator
948 TempoMap::iterator_at (Timecode::BBT_Time const & bbt)
949 {
950         /* CALLER MUST HOLD LOCK */
951
952         if (_points.empty()) {
953                 throw EmptyTempoMapException();
954         }
955
956         if (_points.size() == 1) {
957                 return _points.begin();
958         }
959
960         /* Construct an arbitrary TempoMapPoint. The only property we care about is its bbt time,
961            so other values used in the constructor are arbitrary and irrelevant.
962         */
963
964         TempoMetric const & metric (_points.front().metric());
965         const TempoMapPoint tp (TempoMapPoint::Flag(0), metric, metric, 0, Evoral::Beats(), bbt, MusicTime);
966         TempoMapPoint::BBTComparator bcmp;
967
968         TempoMapPoints::iterator tmp = upper_bound (_points.begin(), _points.end(), tp, bcmp);
969
970         if (tmp != _points.begin()) {
971                 return --tmp;
972         }
973
974         return tmp;
975 }
976
977 Timecode::BBT_Time
978 TempoMap::bbt_at (superclock_t sc) const
979 {
980         Glib::Threads::RWLock::ReaderLock lm (_lock);
981         return bbt_at_locked (sc);
982 }
983
984 Timecode::BBT_Time
985 TempoMap::bbt_at_locked (superclock_t sc) const
986 {
987         TempoMapPoint point (const_point_at (sc));
988         Evoral::Beats b ((sc - point.sclock()) / (double) point.metric().superclocks_per_quarter_note());
989         return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, b.get_beats(), b.get_ticks()));
990 }
991
992 Timecode::BBT_Time
993 TempoMap::bbt_at (Evoral::Beats const & qn) const
994 {
995         Glib::Threads::RWLock::ReaderLock lm (_lock);
996         return bbt_at_locked (qn);
997 }
998
999 Timecode::BBT_Time
1000 TempoMap::bbt_at_locked (Evoral::Beats const & qn) const
1001 {
1002         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1003         TempoMapPoint const & point (const_point_at (qn));
1004         Evoral::Beats delta (qn - point.quarters());
1005         return point.metric().bbt_add (point.bbt(), Timecode::BBT_Offset (0, delta.get_beats(), delta.get_ticks()));
1006 }
1007
1008 superclock_t
1009 TempoMap::superclock_at (Evoral::Beats const & qn) const
1010 {
1011         Glib::Threads::RWLock::ReaderLock lm (_lock);
1012         return superclock_at_locked (qn);
1013 }
1014
1015 superclock_t
1016 TempoMap::superclock_at_locked (Evoral::Beats const & qn) const
1017 {
1018         assert (!_points.empty());
1019
1020         /* only the quarters property matters, since we're just using it to compare */
1021         const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, qn, Timecode::BBT_Time(), MusicTime);
1022         TempoMapPoint::QuarterComparator bcmp;
1023
1024         TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1025
1026         if (i == _points.end()) {
1027                 --i;
1028         }
1029
1030         /* compute distance from reference point to b. Remember that Evoral::Beats is always interpreted as quarter notes */
1031
1032         const Evoral::Beats q_delta = qn - i->quarters();
1033         superclock_t sclock_delta = i->metric().superclock_at_qn (q_delta);
1034         return i->sclock() + sclock_delta;
1035 }
1036
1037 superclock_t
1038 TempoMap::superclock_at (Timecode::BBT_Time const & bbt) const
1039 {
1040         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1041         return superclock_at_locked (bbt);
1042 }
1043
1044 superclock_t
1045 TempoMap::superclock_at_locked (Timecode::BBT_Time const & bbt) const
1046 {
1047         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1048         assert (!_points.empty());
1049
1050         /* only the bbt property matters, since we're just using it to compare */
1051         const TempoMapPoint tmp (TempoMapPoint::Flag (0), Tempo (120), Meter (4, 4), 0, Evoral::Beats(), bbt, MusicTime);
1052         TempoMapPoint::BBTComparator bcmp;
1053
1054         TempoMapPoints::const_iterator i = upper_bound (_points.begin(), _points.end(), tmp, bcmp);
1055
1056         if (i == _points.end()) {
1057                 --i;
1058         }
1059
1060         /* this computes the distance from the point, in beats whose size is
1061            determined by the meter.
1062         */
1063
1064         const Timecode::BBT_Offset delta = i->metric().bbt_delta (bbt, i->bbt());
1065
1066         /* convert to quarter notes */
1067         const int32_t ticks = delta.ticks + (Evoral::Beats::PPQN * delta.beats * 4) / i->metric().note_value();
1068
1069         /* get distance in superclocks */
1070         return i->sclock() + i->metric().superclock_at_qn (Evoral::Beats::ticks (ticks));
1071 }
1072
1073 void
1074 TempoMap::set_sample_rate (framecnt_t new_sr)
1075 {
1076         //Glib::Threads::RWLock::ReaderLock lm (_lock);
1077         double ratio = new_sr / (double) _sample_rate;
1078
1079         for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1080                 i->map_reset_set_sclock_for_sr_change (llrint (ratio * i->sclock()));
1081         }
1082 }
1083
1084 void
1085 TempoMap::dump (std::ostream& ostr)
1086 {
1087         Glib::Threads::RWLock::ReaderLock lm (_lock);
1088         dump_locked (ostr);
1089 }
1090
1091 void
1092 TempoMap::dump_locked (std::ostream& ostr)
1093 {
1094         ostr << "\n\n------------\n";
1095         for (TempoMapPoints::iterator i = _points.begin(); i != _points.end(); ++i) {
1096                 ostr << *i << std::endl;
1097         }
1098 }
1099
1100 void
1101 TempoMap::remove_explicit_point (superclock_t sc)
1102 {
1103         Glib::Threads::RWLock::WriterLock lm (_lock);
1104         TempoMapPoints::iterator p = iterator_at (sc);
1105
1106         if (p->sclock() == sc) {
1107                 _points.erase (p);
1108         }
1109 }
1110
1111 bool
1112 TempoMap::move_to (superclock_t current, superclock_t destination, bool push)
1113 {
1114         Glib::Threads::RWLock::WriterLock lm (_lock);
1115         TempoMapPoints::iterator p = iterator_at (current);
1116
1117         if (p->sclock() != current) {
1118                 cerr << "No point @ " << current << endl;
1119                 return false;
1120         }
1121
1122         /* put a "dirty" flag in at the nearest explicit point to the removal point
1123          */
1124
1125         if (p != _points.begin()) {
1126                 TempoMapPoints::iterator prev (p);
1127                 --prev;
1128                 while (prev != _points.begin() && !prev->is_explicit()) {
1129                         --prev;
1130                 }
1131                 prev->set_dirty (true);
1132         } else {
1133                 TempoMapPoints::iterator nxt (p);
1134                 ++nxt;
1135                 while (nxt != _points.end() && !nxt->is_explicit()) {
1136                         ++nxt;
1137                 }
1138                 if (nxt != _points.end()) {
1139                         nxt->set_dirty (true);
1140                 }
1141         }
1142
1143         if (!set_tempo_and_meter (p->metric(), p->metric(), destination, p->ramped(), true)) {
1144                 return false;
1145         }
1146
1147         if (push) {
1148
1149                 p = iterator_at (destination);
1150                 ++p;
1151
1152                 const superclock_t delta = destination - current;
1153
1154                 while (p != _points.end()) {
1155                         p->set_sclock (p->sclock() + delta);
1156                         ++p;
1157                 }
1158         }
1159
1160         _points.erase (p);
1161
1162         return true;
1163 }
1164
1165 void
1166 TempoMap::get_grid (TempoMapPoints& ret, superclock_t start, superclock_t end, Evoral::Beats const & resolution)
1167 {
1168         Glib::Threads::RWLock::ReaderLock lm (_lock);
1169         TempoMapPoints::iterator p = iterator_at (start);
1170
1171         while (p != _points.end() && p->sclock() < start) {
1172                 ++p;
1173         }
1174
1175         if (resolution == Evoral::Beats()) {
1176                 /* just hand over the points as-is */
1177                 while (p != _points.end() && p->sclock() < end) {
1178                         ret.push_back (*p);
1179                         ++p;
1180                 }
1181                 return;
1182         }
1183
1184         superclock_t pos = p->sclock();
1185         Evoral::Beats qpos;
1186         TempoMapPoints::iterator nxt = p;
1187         ++nxt;
1188
1189         while ((p != _points.end()) && (pos < end)) {
1190                 /* recompute grid down to @param resolution level
1191                  */
1192
1193                 superclock_t sclock_delta = p->metric().superclock_at_qn (qpos);
1194
1195                 ret.push_back (TempoMapPoint (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo),
1196                                               p->metric(), p->metric(),
1197                                               p->sclock() + sclock_delta,
1198                                               p->quarters() + qpos,
1199                                               p->metric().bbt_add (p->bbt(), Timecode::BBT_Offset (0, qpos.get_beats(), qpos.get_ticks())),
1200                                               AudioTime,
1201                                               p->ramped()));
1202
1203                 qpos += resolution;
1204                 pos += sclock_delta;
1205
1206                 if (pos >= nxt->sclock()) {
1207                         p = nxt;
1208                         ++nxt;
1209                 }
1210         }
1211 }
1212
1213
1214 void
1215 TempoMap::get_bar_grid (TempoMapPoints& ret, superclock_t start, superclock_t end, int32_t bar_gap)
1216 {
1217         Glib::Threads::RWLock::ReaderLock lm (_lock);
1218
1219         for (TempoMapPoints::iterator p = iterator_at (start); (p != _points.end()) && (p->sclock() < end); ++p) {
1220
1221                 if ((p->sclock() >= start) && (p->bbt().beats == 1) && ((p->bbt().bars == 1) || (p->bbt().bars % bar_gap == 0))) {
1222                         ret.push_back (TempoMapPoint (TempoMapPoint::Flag (TempoMapPoint::ExplicitMeter|TempoMapPoint::ExplicitTempo),
1223                                                       p->metric(), p->metric(),
1224                                                       p->sclock(),
1225                                                       p->quarters(),
1226                                                       p->bbt(),
1227                                                       AudioTime,
1228                                                       p->ramped()));
1229                 }
1230         }
1231 }
1232
1233 std::ostream&
1234 operator<<(std::ostream& str, Meter const & m)
1235 {
1236         return str << m.divisions_per_bar() << '/' << m.note_value();
1237 }
1238
1239 std::ostream&
1240 operator<<(std::ostream& str, Tempo const & t)
1241 {
1242         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() << ')';
1243 }
1244
1245 std::ostream&
1246 operator<<(std::ostream& str, TempoMapPoint const & tmp)
1247 {
1248         str << '@' << std::setw (12) << tmp.sclock() << ' ' << tmp.sclock() / (double) superclock_ticks_per_second
1249             << (tmp.is_explicit() ? " EXP" : " imp")
1250             << " qn " << tmp.quarters ()
1251             << " bbt " << tmp.bbt()
1252             << " lock to " << tmp.lock_style()
1253                 ;
1254
1255         if (tmp.is_explicit()) {
1256                 str << " tempo " << *((Tempo*) &tmp.metric())
1257                     << " meter " << *((Meter*) &tmp.metric())
1258                         ;
1259         }
1260
1261         if (tmp.is_explicit() && tmp.ramped()) {
1262                 str << " ramp c/sc = " << tmp.metric().c_per_superclock() << " c/qn " << tmp.metric().c_per_quarter();
1263         }
1264         return str;
1265 }
1266
1267 /*******/
1268
1269 #define SAMPLERATE 48000
1270 #define SECONDS_TO_SUPERCLOCK(s) (superclock_ticks_per_second * s)
1271
1272 using std::cerr;
1273 using std::cout;
1274 using std::endl;
1275
1276 void
1277 test_bbt_math ()
1278 {
1279         using namespace Timecode;
1280
1281         BBT_Time a;
1282         BBT_Time b1 (1,1,1919);
1283         BBT_Time n1 (-1,1,1919);
1284         std::vector<Meter> meters;
1285
1286         meters.push_back (Meter (4, 4));
1287         meters.push_back (Meter (5, 8));
1288         meters.push_back (Meter (11, 7));
1289         meters.push_back (Meter (3, 4));
1290
1291 #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;
1292
1293         for (std::vector<Meter>::iterator m = meters.begin(); m != meters.end(); ++m) {
1294                 for (int B = 1; B < 4; ++B) {
1295                         for (int b = 1; b < 13; ++b) {
1296                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 0);
1297                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, 1);
1298                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN/2);
1299                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN);
1300                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 1);
1301                                 PRINT_RESULT((*m), "+", bbt_add, a, B, b, Evoral::Beats::PPQN - 2);
1302
1303                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 0);
1304                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, 1);
1305                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN/2);
1306                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN);
1307                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 1);
1308                                 PRINT_RESULT((*m), "+", bbt_add, b1, B, b, Evoral::Beats::PPQN - 2);
1309
1310                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 0);
1311                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, 1);
1312                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN/2);
1313                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN);
1314                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 1);
1315                                 PRINT_RESULT((*m), "+", bbt_add, n1, B, b, Evoral::Beats::PPQN - 2);
1316                         }
1317                 }
1318
1319                 for (int B = 1; B < 4; ++B) {
1320                         for (int b = 1; b < 13; ++b) {
1321                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 0);
1322                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, 1);
1323                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN/2);
1324                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN);
1325                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 1);
1326                                 PRINT_RESULT ((*m), "-", bbt_subtract, a, B, b, Evoral::Beats::PPQN - 2);
1327                         }
1328                 }
1329         }
1330 }
1331
1332 int
1333 main ()
1334 {
1335         TempoMap tmap (Tempo (140), Meter (4,4), SAMPLERATE);
1336
1337         //test_bbt_math ();
1338         //return 0;
1339
1340         tmap.set_tempo (Tempo (7), SECONDS_TO_SUPERCLOCK(7));
1341         tmap.set_tempo (Tempo (23), SECONDS_TO_SUPERCLOCK(23));
1342         tmap.set_tempo (Tempo (24), SECONDS_TO_SUPERCLOCK(24), true);
1343         tmap.set_tempo (Tempo (40), SECONDS_TO_SUPERCLOCK(28), true);
1344         tmap.set_tempo (Tempo (100), SECONDS_TO_SUPERCLOCK(100));
1345         tmap.set_tempo (Tempo (123), SECONDS_TO_SUPERCLOCK(23));
1346
1347         tmap.set_meter (Meter (3, 4), SECONDS_TO_SUPERCLOCK(23));
1348         tmap.set_meter (Meter (5, 8), SECONDS_TO_SUPERCLOCK(100));
1349         tmap.set_meter (Meter (5, 7), SECONDS_TO_SUPERCLOCK(7));
1350         tmap.set_meter (Meter (4, 4), SECONDS_TO_SUPERCLOCK(24));
1351         tmap.set_meter (Meter (11, 7), SECONDS_TO_SUPERCLOCK(23));
1352
1353         tmap.set_meter (Meter (3, 8), Timecode::BBT_Time (17, 1, 0));
1354
1355         tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1356         tmap.dump (std::cout);
1357
1358         if (tmap.move_to (SECONDS_TO_SUPERCLOCK(23), SECONDS_TO_SUPERCLOCK (72))) {
1359                 tmap.rebuild (SECONDS_TO_SUPERCLOCK (120));
1360                 tmap.dump (std::cout);
1361         }
1362
1363         TempoMapPoints grid;
1364         tmap.get_grid (grid, SECONDS_TO_SUPERCLOCK (12.3), SECONDS_TO_SUPERCLOCK (44), Evoral::Beats::ticks ((Evoral::Beats::PPQN * 4) / 12));
1365         cout << "grid contains " << grid.size() << endl;
1366         for (TempoMapPoints::iterator p = grid.begin(); p != grid.end(); ++p) {
1367                 cout << *p << endl;
1368         }
1369
1370         TempoMapPoints bbt_grid;
1371         tmap.get_bar_grid (bbt_grid, SECONDS_TO_SUPERCLOCK (0), SECONDS_TO_SUPERCLOCK (100), 4);
1372         cout << "bbt_grid contains " << bbt_grid.size() << endl;
1373         for (TempoMapPoints::iterator p = bbt_grid.begin(); p != bbt_grid.end(); ++p) {
1374                 cout << *p << endl;
1375         }
1376
1377         return 0;
1378 }