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