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