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