we always only use the "C" locale when saving.
[ardour.git] / libs / ardour / tempo.cc
1 /*
2     Copyright (C) 2000-2002 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <algorithm>
21 #include <stdexcept>
22 #include <cmath>
23
24 #include <unistd.h>
25
26 #include <glibmm/threads.h>
27 #include "pbd/xml++.h"
28 #include "evoral/Beats.hpp"
29 #include "ardour/debug.h"
30 #include "ardour/lmath.h"
31 #include "ardour/tempo.h"
32
33 #include "i18n.h"
34 #include <locale.h>
35
36 using namespace std;
37 using namespace ARDOUR;
38 using namespace PBD;
39
40 using Timecode::BBT_Time;
41
42 /* _default tempo is 4/4 qtr=120 */
43
44 Meter    TempoMap::_default_meter (4.0, 4.0);
45 Tempo    TempoMap::_default_tempo (120.0);
46
47 /***********************************************************************/
48
49 double
50 Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
51 {
52         /* This is tempo- and meter-sensitive. The number it returns
53            is based on the interval between any two lines in the
54            grid that is constructed from tempo and meter sections.
55
56            The return value IS NOT interpretable in terms of "beats".
57         */
58
59         return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
60 }
61
62 double
63 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
64 {
65         return frames_per_grid (tempo, sr) * _divisions_per_bar;
66 }
67
68 /***********************************************************************/
69
70 const string TempoSection::xml_state_node_name = "Tempo";
71
72 TempoSection::TempoSection (const XMLNode& node)
73         : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
74 {
75         XMLProperty const * prop;
76         BBT_Time start;
77         LocaleGuard lg ();
78
79         if ((prop = node.property ("start")) == 0) {
80                 error << _("TempoSection XML node has no \"start\" property") << endmsg;
81                 throw failed_constructor();
82         }
83
84         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
85                     &start.bars,
86                     &start.beats,
87                     &start.ticks) < 3) {
88                 error << _("TempoSection XML node has an illegal \"start\" value") << endmsg;
89                 throw failed_constructor();
90         }
91
92         set_start (start);
93
94         if ((prop = node.property ("beats-per-minute")) == 0) {
95                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
96                 throw failed_constructor();
97         }
98
99         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
100                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
101                 throw failed_constructor();
102         }
103
104         if ((prop = node.property ("note-type")) == 0) {
105                 /* older session, make note type be quarter by default */
106                 _note_type = 4.0;
107         } else {
108                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
109                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
110                         throw failed_constructor();
111                 }
112         }
113
114         if ((prop = node.property ("movable")) == 0) {
115                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
116                 throw failed_constructor();
117         }
118
119         set_movable (string_is_affirmative (prop->value()));
120
121         if ((prop = node.property ("bar-offset")) == 0) {
122                 _bar_offset = -1.0;
123         } else {
124                 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
125                         error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
126                         throw failed_constructor();
127                 }
128         }
129 }
130
131 XMLNode&
132 TempoSection::get_state() const
133 {
134         XMLNode *root = new XMLNode (xml_state_node_name);
135         char buf[256];
136         LocaleGuard lg ();
137
138         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
139                   start().bars,
140                   start().beats,
141                   start().ticks);
142         root->add_property ("start", buf);
143         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
144         root->add_property ("beats-per-minute", buf);
145         snprintf (buf, sizeof (buf), "%f", _note_type);
146         root->add_property ("note-type", buf);
147         // snprintf (buf, sizeof (buf), "%f", _bar_offset);
148         // root->add_property ("bar-offset", buf);
149         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
150         root->add_property ("movable", buf);
151
152         return *root;
153 }
154
155 void
156
157 TempoSection::update_bar_offset_from_bbt (const Meter& m)
158 {
159         _bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_beat + start().ticks) /
160                 (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
161
162         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar()));
163 }
164
165 void
166 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
167 {
168         BBT_Time new_start;
169
170         if (_bar_offset < 0.0) {
171                 /* not set yet */
172                 return;
173         }
174
175         new_start.bars = start().bars;
176
177         double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
178         new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
179         new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
180
181         /* remember the 1-based counting properties of beats */
182         new_start.beats += 1;
183
184         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
185                                                        _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
186
187         set_start (new_start);
188 }
189
190 /***********************************************************************/
191
192 const string MeterSection::xml_state_node_name = "Meter";
193
194 MeterSection::MeterSection (const XMLNode& node)
195         : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
196 {
197         XMLProperty const * prop;
198         BBT_Time start;
199         LocaleGuard lg ();
200
201         if ((prop = node.property ("start")) == 0) {
202                 error << _("MeterSection XML node has no \"start\" property") << endmsg;
203                 throw failed_constructor();
204         }
205
206         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
207                     &start.bars,
208                     &start.beats,
209                     &start.ticks) < 3) {
210                 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
211                 throw failed_constructor();
212         }
213
214         set_start (start);
215
216         /* beats-per-bar is old; divisions-per-bar is new */
217
218         if ((prop = node.property ("divisions-per-bar")) == 0) {
219                 if ((prop = node.property ("beats-per-bar")) == 0) {
220                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
221                         throw failed_constructor();
222                 }
223         }
224
225         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
226                 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
227                 throw failed_constructor();
228         }
229
230         if ((prop = node.property ("note-type")) == 0) {
231                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
232                 throw failed_constructor();
233         }
234
235         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
236                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
237                 throw failed_constructor();
238         }
239
240         if ((prop = node.property ("movable")) == 0) {
241                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
242                 throw failed_constructor();
243         }
244
245         set_movable (string_is_affirmative (prop->value()));
246 }
247
248 XMLNode&
249 MeterSection::get_state() const
250 {
251         XMLNode *root = new XMLNode (xml_state_node_name);
252         char buf[256];
253         LocaleGuard lg ();
254
255         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
256                   start().bars,
257                   start().beats,
258                   start().ticks);
259         root->add_property ("start", buf);
260         snprintf (buf, sizeof (buf), "%f", _note_type);
261         root->add_property ("note-type", buf);
262         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
263         root->add_property ("divisions-per-bar", buf);
264         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
265         root->add_property ("movable", buf);
266
267         return *root;
268 }
269
270 /***********************************************************************/
271
272 struct MetricSectionSorter {
273     bool operator() (const MetricSection* a, const MetricSection* b) {
274             return a->start() < b->start();
275     }
276 };
277
278 TempoMap::TempoMap (framecnt_t fr)
279 {
280         _frame_rate = fr;
281         BBT_Time start;
282
283         start.bars = 1;
284         start.beats = 1;
285         start.ticks = 0;
286
287         // these leak memory, well Metrics does
288         TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
289         MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
290
291         t->set_movable (false);
292         m->set_movable (false);
293
294         /* note: frame time is correct (zero) for both of these */
295
296         metrics.push_back (t);
297         metrics.push_back (m);
298 }
299
300 TempoMap::~TempoMap ()
301 {
302 }
303
304 void
305 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
306 {
307         bool removed = false;
308
309         {
310                 Glib::Threads::RWLock::WriterLock lm (lock);
311                 if ((removed = remove_tempo_locked (tempo))) {
312                         if (complete_operation) {
313                                 recompute_map (true);
314                         }
315                 }
316         }
317
318         if (removed && complete_operation) {
319                 PropertyChanged (PropertyChange ());
320         }
321 }
322
323 bool
324 TempoMap::remove_tempo_locked (const TempoSection& tempo)
325 {
326         Metrics::iterator i;
327
328         for (i = metrics.begin(); i != metrics.end(); ++i) {
329                 if (dynamic_cast<TempoSection*> (*i) != 0) {
330                         if (tempo.frame() == (*i)->frame()) {
331                                 if ((*i)->movable()) {
332                                         metrics.erase (i);
333                                         return true;
334                                 }
335                         }
336                 }
337         }
338
339         return false;
340 }
341
342 void
343 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
344 {
345         bool removed = false;
346
347         {
348                 Glib::Threads::RWLock::WriterLock lm (lock);
349                 if ((removed = remove_meter_locked (tempo))) {
350                         if (complete_operation) {
351                                 recompute_map (true);
352                         }
353                 }
354         }
355
356         if (removed && complete_operation) {
357                 PropertyChanged (PropertyChange ());
358         }
359 }
360
361 bool
362 TempoMap::remove_meter_locked (const MeterSection& tempo)
363 {
364         Metrics::iterator i;
365
366         for (i = metrics.begin(); i != metrics.end(); ++i) {
367                 if (dynamic_cast<MeterSection*> (*i) != 0) {
368                         if (tempo.frame() == (*i)->frame()) {
369                                 if ((*i)->movable()) {
370                                         metrics.erase (i);
371                                         return true;
372                                 }
373                         }
374                 }
375         }
376
377         return false;
378 }
379
380 void
381 TempoMap::do_insert (MetricSection* section)
382 {
383         bool need_add = true;
384
385         assert (section->start().ticks == 0);
386
387         /* we only allow new meters to be inserted on beat 1 of an existing
388          * measure.
389          */
390
391         if (dynamic_cast<MeterSection*>(section)) {
392
393                 /* we need to (potentially) update the BBT times of tempo
394                    sections based on this new meter.
395                 */
396
397                 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
398
399                         BBT_Time corrected = section->start();
400                         corrected.beats = 1;
401                         corrected.ticks = 0;
402
403                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
404                                                    section->start(), corrected) << endmsg;
405
406                         section->set_start (corrected);
407                 }
408         }
409
410
411
412         /* Look for any existing MetricSection that is of the same type and
413            in the same bar as the new one, and remove it before adding
414            the new one. Note that this means that if we find a matching,
415            existing section, we can break out of the loop since we're
416            guaranteed that there is only one such match.
417         */
418
419         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
420
421                 bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0;
422                 bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0;
423
424                 if (iter_is_tempo && insert_is_tempo) {
425
426                         /* Tempo sections */
427
428                         if ((*i)->start().bars == section->start().bars &&
429                             (*i)->start().beats == section->start().beats) {
430
431                                 if (!(*i)->movable()) {
432
433                                         /* can't (re)move this section, so overwrite
434                                          * its data content (but not its properties as
435                                          * a section).
436                                          */
437
438                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section));
439                                         need_add = false;
440                                 } else {
441                                         metrics.erase (i);
442                                 }
443                                 break;
444                         }
445
446                 } else if (!iter_is_tempo && !insert_is_tempo) {
447
448                         /* Meter Sections */
449
450                         if ((*i)->start().bars == section->start().bars) {
451
452                                 if (!(*i)->movable()) {
453
454                                         /* can't (re)move this section, so overwrite
455                                          * its data content (but not its properties as
456                                          * a section
457                                          */
458
459                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section));
460                                         need_add = false;
461                                 } else {
462                                         metrics.erase (i);
463
464                                 }
465
466                                 break;
467                         }
468                 } else {
469                         /* non-matching types, so we don't care */
470                 }
471         }
472
473         /* Add the given MetricSection, if we didn't just reset an existing
474          * one above
475          */
476
477         if (need_add) {
478
479                 Metrics::iterator i;
480
481                 for (i = metrics.begin(); i != metrics.end(); ++i) {
482                         if ((*i)->start() > section->start()) {
483                                 break;
484                         }
485                 }
486
487                 metrics.insert (i, section);
488         }
489 }
490
491 void
492 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where)
493 {
494         {
495                 Glib::Threads::RWLock::WriterLock lm (lock);
496                 TempoSection& first (first_tempo());
497
498                 if (ts.start() != first.start()) {
499                         remove_tempo_locked (ts);
500                         add_tempo_locked (tempo, where, true);
501                 } else {
502                         {
503                                 /* cannot move the first tempo section */
504                                 *static_cast<Tempo*>(&first) = tempo;
505                                 recompute_map (false);
506                         }
507                 }
508         }
509
510         PropertyChanged (PropertyChange ());
511 }
512
513 void
514 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
515 {
516         {
517                 Glib::Threads::RWLock::WriterLock lm (lock);
518                 add_tempo_locked (tempo, where, true);
519         }
520
521
522         PropertyChanged (PropertyChange ());
523 }
524
525 void
526 TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute)
527 {
528         /* new tempos always start on a beat */
529         where.ticks = 0;
530
531         TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type());
532
533         /* find the meter to use to set the bar offset of this
534          * tempo section.
535          */
536
537         const Meter* meter = &first_meter();
538
539         /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
540            at something, because we insert the default tempo and meter during
541            TempoMap construction.
542
543            now see if we can find better candidates.
544         */
545
546         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
547
548                 const MeterSection* m;
549
550                 if (where < (*i)->start()) {
551                         break;
552                 }
553
554                 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
555                         meter = m;
556                 }
557         }
558
559         ts->update_bar_offset_from_bbt (*meter);
560
561         /* and insert it */
562
563         do_insert (ts);
564
565         if (recompute) {
566                 recompute_map (false);
567         }
568 }
569
570 void
571 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
572 {
573         {
574                 Glib::Threads::RWLock::WriterLock lm (lock);
575                 MeterSection& first (first_meter());
576
577                 if (ms.start() != first.start()) {
578                         remove_meter_locked (ms);
579                         add_meter_locked (meter, where, true);
580                 } else {
581                         /* cannot move the first meter section */
582                         *static_cast<Meter*>(&first) = meter;
583                         recompute_map (true);
584                 }
585         }
586
587         PropertyChanged (PropertyChange ());
588 }
589
590 void
591 TempoMap::add_meter (const Meter& meter, BBT_Time where)
592 {
593         {
594                 Glib::Threads::RWLock::WriterLock lm (lock);
595                 add_meter_locked (meter, where, true);
596         }
597
598
599 #ifndef NDEBUG
600         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
601                 dump (std::cerr);
602         }
603 #endif
604
605         PropertyChanged (PropertyChange ());
606 }
607
608 void
609 TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
610 {
611         /* a new meter always starts a new bar on the first beat. so
612            round the start time appropriately. remember that
613            `where' is based on the existing tempo map, not
614            the result after we insert the new meter.
615
616         */
617
618         if (where.beats != 1) {
619                 where.beats = 1;
620                 where.bars++;
621         }
622
623         /* new meters *always* start on a beat. */
624         where.ticks = 0;
625
626         do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
627
628         if (recompute) {
629                 recompute_map (true);
630         }
631
632 }
633
634 void
635 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
636 {
637         Tempo newtempo (beats_per_minute, note_type);
638         TempoSection* t;
639
640         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
641                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
642                         {
643                                 Glib::Threads::RWLock::WriterLock lm (lock);
644                                 *((Tempo*) t) = newtempo;
645                                 recompute_map (false);
646                         }
647                         PropertyChanged (PropertyChange ());
648                         break;
649                 }
650         }
651 }
652
653 void
654 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
655 {
656         Tempo newtempo (beats_per_minute, note_type);
657
658         TempoSection* prev;
659         TempoSection* first;
660         Metrics::iterator i;
661
662         /* find the TempoSection immediately preceding "where"
663          */
664
665         for (first = 0, i = metrics.begin(), prev = 0; i != metrics.end(); ++i) {
666
667                 if ((*i)->frame() > where) {
668                         break;
669                 }
670
671                 TempoSection* t;
672
673                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
674                         if (!first) {
675                                 first = t;
676                         }
677                         prev = t;
678                 }
679         }
680
681         if (!prev) {
682                 if (!first) {
683                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
684                         return;
685                 }
686
687                 prev = first;
688         }
689
690         /* reset */
691
692         {
693                 Glib::Threads::RWLock::WriterLock lm (lock);
694                 /* cannot move the first tempo section */
695                 *((Tempo*)prev) = newtempo;
696                 recompute_map (false);
697         }
698
699         PropertyChanged (PropertyChange ());
700 }
701
702 const MeterSection&
703 TempoMap::first_meter () const
704 {
705         const MeterSection *m = 0;
706
707         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
708                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
709                         return *m;
710                 }
711         }
712
713         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
714         abort(); /*NOTREACHED*/
715         return *m;
716 }
717
718 MeterSection&
719 TempoMap::first_meter ()
720 {
721         MeterSection *m = 0;
722
723         /* CALLER MUST HOLD LOCK */
724
725         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
726                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
727                         return *m;
728                 }
729         }
730
731         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
732         abort(); /*NOTREACHED*/
733         return *m;
734 }
735
736 const TempoSection&
737 TempoMap::first_tempo () const
738 {
739         const TempoSection *t = 0;
740
741         /* CALLER MUST HOLD LOCK */
742
743         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
744                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
745                         return *t;
746                 }
747         }
748
749         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
750         abort(); /*NOTREACHED*/
751         return *t;
752 }
753
754 TempoSection&
755 TempoMap::first_tempo ()
756 {
757         TempoSection *t = 0;
758
759         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
760                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
761                         return *t;
762                 }
763         }
764
765         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
766         abort(); /*NOTREACHED*/
767         return *t;
768 }
769
770 void
771 TempoMap::require_map_to (framepos_t pos)
772 {
773         Glib::Threads::RWLock::WriterLock lm (lock);
774
775         if (_map.empty() || _map.back().frame < pos) {
776                 extend_map (pos);
777         }
778 }
779
780 void
781 TempoMap::require_map_to (const BBT_Time& bbt)
782 {
783         Glib::Threads::RWLock::WriterLock lm (lock);
784
785         /* since we have no idea where BBT is if its off the map, see the last
786          * point in the map is past BBT, and if not add an arbitrary amount of
787          * time until it is.
788          */
789
790         int additional_minutes = 1;
791
792         while (1) {
793                 if (!_map.empty() && _map.back().bar >= (bbt.bars + 1)) {
794                         break;
795                 }
796                 /* add some more distance, using bigger steps each time */
797                 extend_map (_map.back().frame + (_frame_rate * 60 * additional_minutes));
798                 additional_minutes *= 2;
799         }
800 }
801
802 void
803 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
804 {
805         /* CALLER MUST HOLD WRITE LOCK */
806
807         MeterSection* meter = 0;
808         TempoSection* tempo = 0;
809         double current_frame;
810         BBT_Time current;
811         Metrics::iterator next_metric;
812
813         if (end < 0) {
814
815                 /* we will actually stop once we hit
816                    the last metric.
817                 */
818                 end = max_framepos;
819
820         } else {
821                 if (!_map.empty ()) {
822                         /* never allow the map to be shortened */
823                         end = max (end, _map.back().frame);
824                 }
825         }
826
827         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
828
829         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
830                 MeterSection* ms;
831
832                 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
833                         meter = ms;
834                         break;
835                 }
836         }
837
838         assert(meter);
839
840         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
841                 TempoSection* ts;
842
843                 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
844                         tempo = ts;
845                         break;
846                 }
847         }
848
849         assert(tempo);
850
851         /* assumes that the first meter & tempo are at frame zero */
852         current_frame = 0;
853         meter->set_frame (0);
854         tempo->set_frame (0);
855
856         /* assumes that the first meter & tempo are at 1|1|0 */
857         current.bars = 1;
858         current.beats = 1;
859         current.ticks = 0;
860
861         if (reassign_tempo_bbt) {
862
863                 MeterSection* rmeter = meter;
864
865                 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
866
867                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
868
869                         TempoSection* ts;
870                         MeterSection* ms;
871
872                         if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
873
874                                 /* reassign the BBT time of this tempo section
875                                  * based on its bar offset position.
876                                  */
877
878                                 ts->update_bbt_time_from_bar_offset (*rmeter);
879
880                         } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
881                                 rmeter = ms;
882                         } else {
883                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
884                                 abort(); /*NOTREACHED*/
885                         }
886                 }
887         }
888
889         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
890
891         next_metric = metrics.begin();
892         ++next_metric; // skip meter (or tempo)
893         ++next_metric; // skip tempo (or meter)
894
895         _map.clear ();
896
897         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
898         _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), 1, 1));
899
900         if (end == 0) {
901                 /* silly call from Session::process() during startup
902                  */
903                 return;
904         }
905
906         _extend_map (tempo, meter, next_metric, current, current_frame, end);
907 }
908
909 void
910 TempoMap::extend_map (framepos_t end)
911 {
912         /* CALLER MUST HOLD WRITE LOCK */
913
914         if (_map.empty()) {
915                 recompute_map (false, end);
916                 return;
917         }
918
919         BBTPointList::const_iterator i = _map.end();
920         Metrics::iterator next_metric;
921
922         --i;
923
924         BBT_Time last_metric_start;
925
926         if ((*i).tempo->frame() > (*i).meter->frame()) {
927                 last_metric_start = (*i).tempo->start();
928         } else {
929                 last_metric_start = (*i).meter->start();
930         }
931
932         /* find the metric immediately after the tempo + meter sections for the
933          * last point in the map
934          */
935
936         for (next_metric = metrics.begin(); next_metric != metrics.end(); ++next_metric) {
937                 if ((*next_metric)->start() > last_metric_start) {
938                         break;
939                 }
940         }
941
942         /* we cast away const here because this is the one place where we need
943          * to actually modify the frame time of each metric section.
944          */
945
946         _extend_map (const_cast<TempoSection*> ((*i).tempo),
947                      const_cast<MeterSection*> ((*i).meter),
948                      next_metric, BBT_Time ((*i).bar, (*i).beat, 0), (*i).frame, end);
949 }
950
951 void
952 TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
953                        Metrics::iterator next_metric,
954                        BBT_Time current, framepos_t current_frame, framepos_t end)
955 {
956         /* CALLER MUST HOLD WRITE LOCK */
957
958         TempoSection* ts;
959         MeterSection* ms;
960         double beat_frames;
961         double current_frame_exact;
962         framepos_t bar_start_frame;
963
964         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Extend map to %1 from %2 = %3\n", end, current, current_frame));
965
966         if (current.beats == 1) {
967                 bar_start_frame = current_frame;
968         } else {
969                 bar_start_frame = 0;
970         }
971
972         beat_frames = meter->frames_per_grid (*tempo,_frame_rate);
973         current_frame_exact = current_frame;
974
975         while (current_frame < end) {
976
977                 current.beats++;
978                 current_frame_exact += beat_frames;
979                 current_frame = llrint(current_frame_exact);
980
981                 if (current.beats > meter->divisions_per_bar()) {
982                         current.bars++;
983                         current.beats = 1;
984                 }
985
986                 if (next_metric != metrics.end()) {
987
988                         /* no operator >= so invert operator < */
989
990                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1 next metric @ %2\n", current, (*next_metric)->start()));
991
992                         if (!(current < (*next_metric)->start())) {
993
994                 set_metrics:
995                                 if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0)) {
996
997                                         tempo = ts;
998
999                                         /* new tempo section: if its on a beat,
1000                                          * we don't have to do anything other
1001                                          * than recompute various distances,
1002                                          * done further below as we transition
1003                                          * the next metric section.
1004                                          *
1005                                          * if its not on the beat, we have to
1006                                          * compute the duration of the beat it
1007                                          * is within, which will be different
1008                                          * from the preceding following ones
1009                                          * since it takes part of its duration
1010                                          * from the preceding tempo and part
1011                                          * from this new tempo.
1012                                          */
1013
1014                                         if (tempo->start().ticks != 0) {
1015
1016                                                 double next_beat_frames = tempo->frames_per_beat (_frame_rate);
1017
1018                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
1019                                                                                                tempo->start(), current_frame, tempo->bar_offset()));
1020
1021                                                 /* back up to previous beat */
1022                                                 current_frame_exact -= beat_frames;
1023                                                 current_frame = llrint(current_frame_exact);
1024
1025                                                 /* set tempo section location
1026                                                  * based on offset from last
1027                                                  * bar start
1028                                                  */
1029                                                 tempo->set_frame (bar_start_frame +
1030                                                                   llrint ((ts->bar_offset() * meter->divisions_per_bar() * beat_frames)));
1031
1032                                                 /* advance to the location of
1033                                                  * the new (adjusted) beat. do
1034                                                  * this by figuring out the
1035                                                  * offset within the beat that
1036                                                  * would have been there
1037                                                  * without the tempo
1038                                                  * change. then stretch the
1039                                                  * beat accordingly.
1040                                                  */
1041
1042                                                 double offset_within_old_beat = (tempo->frame() - current_frame) / beat_frames;
1043
1044                                                 current_frame_exact += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
1045                                                 current_frame = llrint(current_frame_exact);
1046
1047                                                 /* next metric doesn't have to
1048                                                  * match this precisely to
1049                                                  * merit a reloop ...
1050                                                  */
1051                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Adjusted last beat to %1\n", current_frame));
1052
1053                                         } else {
1054
1055                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into beat-aligned tempo metric at %1 = %2\n",
1056                                                                                                tempo->start(), current_frame));
1057                                                 tempo->set_frame (current_frame);
1058                                         }
1059
1060                                 } else if ((ms = dynamic_cast<MeterSection*>(*next_metric)) != 0) {
1061
1062                                         meter = ms;
1063
1064                                         /* new meter section: always defines the
1065                                          * start of a bar.
1066                                          */
1067
1068                                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into meter section at %1 vs %2 (%3)\n",
1069                                                                                        meter->start(), current, current_frame));
1070
1071                                         assert (current.beats == 1);
1072
1073                                         meter->set_frame (current_frame);
1074                                 }
1075
1076                                 beat_frames = meter->frames_per_grid (*tempo, _frame_rate);
1077
1078                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 dpb %2 meter %3 tempo %4\n",
1079                                                                                beat_frames, meter->divisions_per_bar(), *((Meter*)meter), *((Tempo*)tempo)));
1080
1081                                 ++next_metric;
1082
1083                                 if (next_metric != metrics.end() && ((*next_metric)->start() == current)) {
1084                                         /* same position so go back and set this one up before advancing
1085                                          */
1086                                         goto set_metrics;
1087                                 }
1088
1089                         }
1090                 }
1091
1092                 if (current.beats == 1) {
1093                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
1094                         _map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, 1));
1095                         bar_start_frame = current_frame;
1096                 } else {
1097                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
1098                         _map.push_back (BBTPoint (*meter, *tempo, current_frame, current.bars, current.beats));
1099                 }
1100
1101                 if (next_metric == metrics.end()) {
1102                         /* no more metrics - we've timestamped them all, stop here */
1103                         if (end == max_framepos) {
1104                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stop extending map now that we've reach the end @ %1|%2 = %3\n",
1105                                                                                current.bars, current.beats, current_frame));
1106                                 break;
1107                         }
1108                 }
1109         }
1110 }
1111
1112 TempoMetric
1113 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1114 {
1115         Glib::Threads::RWLock::ReaderLock lm (lock);
1116         TempoMetric m (first_meter(), first_tempo());
1117
1118         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1119            at something, because we insert the default tempo and meter during
1120            TempoMap construction.
1121
1122            now see if we can find better candidates.
1123         */
1124
1125         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1126
1127                 if ((*i)->frame() > frame) {
1128                         break;
1129                 }
1130
1131                 m.set_metric(*i);
1132
1133                 if (last) {
1134                         *last = i;
1135                 }
1136         }
1137
1138         return m;
1139 }
1140
1141 TempoMetric
1142 TempoMap::metric_at (BBT_Time bbt) const
1143 {
1144         Glib::Threads::RWLock::ReaderLock lm (lock);
1145         TempoMetric m (first_meter(), first_tempo());
1146
1147         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1148            at something, because we insert the default tempo and meter during
1149            TempoMap construction.
1150
1151            now see if we can find better candidates.
1152         */
1153
1154         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1155
1156                 BBT_Time section_start ((*i)->start());
1157
1158                 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1159                         break;
1160                 }
1161
1162                 m.set_metric (*i);
1163         }
1164
1165         return m;
1166 }
1167
1168 void
1169 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1170 {
1171         require_map_to (frame);
1172
1173         Glib::Threads::RWLock::ReaderLock lm (lock);
1174
1175         if (frame < 0) {
1176                 bbt.bars = 1;
1177                 bbt.beats = 1;
1178                 bbt.ticks = 0;
1179                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1180                 return;
1181         }
1182
1183         return bbt_time (frame, bbt, bbt_before_or_at (frame));
1184 }
1185
1186 void
1187 TempoMap::bbt_time_rt (framepos_t frame, BBT_Time& bbt)
1188 {
1189         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1190
1191         if (!lm.locked()) {
1192                 throw std::logic_error ("TempoMap::bbt_time_rt() could not lock tempo map");
1193         }
1194
1195         if (_map.empty() || _map.back().frame < frame) {
1196                 throw std::logic_error (string_compose ("map not long enough to reach %1", frame));
1197         }
1198
1199         return bbt_time (frame, bbt, bbt_before_or_at (frame));
1200 }
1201
1202 void
1203 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt, const BBTPointList::const_iterator& i)
1204 {
1205         /* CALLER MUST HOLD READ LOCK */
1206
1207         bbt.bars = (*i).bar;
1208         bbt.beats = (*i).beat;
1209
1210         if ((*i).frame == frame) {
1211                 bbt.ticks = 0;
1212         } else {
1213                 bbt.ticks = llrint (((frame - (*i).frame) / (*i).tempo->frames_per_beat(_frame_rate)) *
1214                                     BBT_Time::ticks_per_beat);
1215         }
1216 }
1217
1218 framepos_t
1219 TempoMap::frame_time (const BBT_Time& bbt)
1220 {
1221         if (bbt.bars < 1) {
1222                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1223                 return 0;
1224         }
1225
1226         if (bbt.beats < 1) {
1227                 throw std::logic_error ("beats are counted from one");
1228         }
1229
1230         require_map_to (bbt);
1231
1232         Glib::Threads::RWLock::ReaderLock lm (lock);
1233
1234         BBTPointList::const_iterator s = bbt_before_or_at (BBT_Time (1, 1, 0));
1235         BBTPointList::const_iterator e = bbt_before_or_at (BBT_Time (bbt.bars, bbt.beats, 0));
1236
1237         if (bbt.ticks != 0) {
1238                 return ((*e).frame - (*s).frame) +
1239                         llrint ((*e).tempo->frames_per_beat (_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat));
1240         } else {
1241                 return ((*e).frame - (*s).frame);
1242         }
1243 }
1244
1245 framecnt_t
1246 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1247 {
1248         BBT_Time when;
1249         bbt_time (pos, when);
1250
1251         Glib::Threads::RWLock::ReaderLock lm (lock);
1252         return bbt_duration_at_unlocked (when, bbt, dir);
1253 }
1254
1255 framecnt_t
1256 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int /*dir*/)
1257 {
1258         if (bbt.bars == 0 && bbt.beats == 0 && bbt.ticks == 0) {
1259                 return 0;
1260         }
1261
1262         /* round back to the previous precise beat */
1263         BBTPointList::const_iterator wi = bbt_before_or_at (BBT_Time (when.bars, when.beats, 0));
1264         BBTPointList::const_iterator start (wi);
1265
1266         assert (wi != _map.end());
1267
1268         uint32_t bars = 0;
1269         uint32_t beats = 0;
1270
1271         while (wi != _map.end() && bars < bbt.bars) {
1272                 ++wi;
1273                 if ((*wi).is_bar()) {
1274                         ++bars;
1275                 }
1276         }
1277         assert (wi != _map.end());
1278
1279         while (wi != _map.end() && beats < bbt.beats) {
1280                 ++wi;
1281                 ++beats;
1282         }
1283         assert (wi != _map.end());
1284
1285         /* add any additional frames related to ticks in the added value */
1286
1287         if (bbt.ticks != 0) {
1288                 return ((*wi).frame - (*start).frame) +
1289                         (*wi).tempo->frames_per_beat (_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat);
1290         } else {
1291                 return ((*wi).frame - (*start).frame);
1292         }
1293 }
1294
1295 framepos_t
1296 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
1297 {
1298         return round_to_type (fr, dir, Bar);
1299 }
1300
1301 framepos_t
1302 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
1303 {
1304         return round_to_type (fr, dir, Beat);
1305 }
1306
1307 framepos_t
1308 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
1309 {
1310         require_map_to (fr);
1311
1312         Glib::Threads::RWLock::ReaderLock lm (lock);
1313         BBTPointList::const_iterator i = bbt_before_or_at (fr);
1314         BBT_Time the_beat;
1315         uint32_t ticks_one_subdivisions_worth;
1316
1317         bbt_time (fr, the_beat, i);
1318
1319         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("round %1 to nearest 1/%2 beat, before-or-at = %3 @ %4|%5 precise = %6\n",
1320                                                      fr, sub_num, (*i).frame, (*i).bar, (*i).beat, the_beat));
1321
1322         ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1323
1324         if (dir > 0) {
1325
1326                 /* round to next (or same iff dir == RoundUpMaybe) */
1327
1328                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1329
1330                 if (mod == 0 && dir == RoundUpMaybe) {
1331                         /* right on the subdivision, which is fine, so do nothing */
1332
1333                 } else if (mod == 0) {
1334                         /* right on the subdivision, so the difference is just the subdivision ticks */
1335                         the_beat.ticks += ticks_one_subdivisions_worth;
1336
1337                 } else {
1338                         /* not on subdivision, compute distance to next subdivision */
1339
1340                         the_beat.ticks += ticks_one_subdivisions_worth - mod;
1341                 }
1342
1343                 if (the_beat.ticks > BBT_Time::ticks_per_beat) {
1344                         assert (i != _map.end());
1345                         ++i;
1346                         assert (i != _map.end());
1347                         the_beat.ticks -= BBT_Time::ticks_per_beat;
1348                 }
1349
1350
1351         } else if (dir < 0) {
1352
1353                 /* round to previous (or same iff dir == RoundDownMaybe) */
1354
1355                 uint32_t difference = the_beat.ticks % ticks_one_subdivisions_worth;
1356
1357                 if (difference == 0 && dir == RoundDownAlways) {
1358                         /* right on the subdivision, but force-rounding down,
1359                            so the difference is just the subdivision ticks */
1360                         difference = ticks_one_subdivisions_worth;
1361                 }
1362
1363                 if (the_beat.ticks < difference) {
1364                         if (i == _map.begin()) {
1365                                 /* can't go backwards from wherever pos is, so just return it */
1366                                 return fr;
1367                         }
1368                         --i;
1369                         the_beat.ticks = BBT_Time::ticks_per_beat - the_beat.ticks;
1370                 } else {
1371                         the_beat.ticks -= difference;
1372                 }
1373
1374         } else {
1375                 /* round to nearest */
1376
1377                 double rem;
1378
1379                 /* compute the distance to the previous and next subdivision */
1380
1381                 if ((rem = fmod ((double) the_beat.ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1382
1383                         /* closer to the next subdivision, so shift forward */
1384
1385                         the_beat.ticks = lrint (the_beat.ticks + (ticks_one_subdivisions_worth - rem));
1386
1387                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", the_beat.ticks));
1388
1389                         if (the_beat.ticks > BBT_Time::ticks_per_beat) {
1390                                 assert (i != _map.end());
1391                                 ++i;
1392                                 assert (i != _map.end());
1393                                 the_beat.ticks -= BBT_Time::ticks_per_beat;
1394                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", the_beat));
1395                         }
1396
1397                 } else if (rem > 0) {
1398
1399                         /* closer to previous subdivision, so shift backward */
1400
1401                         if (rem > the_beat.ticks) {
1402                                 if (i == _map.begin()) {
1403                                         /* can't go backwards past zero, so ... */
1404                                         return 0;
1405                                 }
1406                                 /* step back to previous beat */
1407                                 --i;
1408                                 the_beat.ticks = lrint (BBT_Time::ticks_per_beat - rem);
1409                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", the_beat));
1410                         } else {
1411                                 the_beat.ticks = lrint (the_beat.ticks - rem);
1412                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", the_beat.ticks));
1413                         }
1414                 } else {
1415                         /* on the subdivision, do nothing */
1416                 }
1417         }
1418
1419         return (*i).frame + (the_beat.ticks/BBT_Time::ticks_per_beat) *
1420                 (*i).tempo->frames_per_beat (_frame_rate);
1421 }
1422
1423 framepos_t
1424 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
1425 {
1426         require_map_to (frame);
1427
1428         Glib::Threads::RWLock::ReaderLock lm (lock);
1429         BBTPointList::const_iterator fi;
1430
1431         if (dir > 0) {
1432                 fi = bbt_after_or_at (frame);
1433         } else {
1434                 fi = bbt_before_or_at (frame);
1435         }
1436
1437         assert (fi != _map.end());
1438
1439         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("round from %1 (%3|%4 @ %5) to %6 in direction %2\n", frame, dir, (*fi).bar, (*fi).beat, (*fi).frame,
1440                                                      (type == Bar ? "bar" : "beat")));
1441
1442         switch (type) {
1443         case Bar:
1444                 if (dir < 0) {
1445                         /* find bar previous to 'frame' */
1446
1447                         if (fi == _map.begin()) {
1448                                 return 0;
1449                         }
1450
1451                         if ((*fi).is_bar() && (*fi).frame == frame) {
1452                                 if (dir == RoundDownMaybe) {
1453                                         return frame;
1454                                 }
1455                                 --fi;
1456                         }
1457
1458                         while (!(*fi).is_bar()) {
1459                                 if (fi == _map.begin()) {
1460                                         break;
1461                                 }
1462                                 fi--;
1463                         }
1464                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to bar: map iter at %1|%2 %3, return\n",
1465                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1466                         return (*fi).frame;
1467
1468                 } else if (dir > 0) {
1469
1470                         /* find bar following 'frame' */
1471
1472                         if ((*fi).is_bar() && (*fi).frame == frame) {
1473                                 if (dir == RoundUpMaybe) {
1474                                         return frame;
1475                                 }
1476                                 ++fi;
1477                         }
1478
1479                         while (!(*fi).is_bar()) {
1480                                 fi++;
1481                                 if (fi == _map.end()) {
1482                                         --fi;
1483                                         break;
1484                                 }
1485                         }
1486
1487                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to bar: map iter at %1|%2 %3, return\n",
1488                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1489                         return (*fi).frame;
1490
1491                 } else {
1492
1493                         /* true rounding: find nearest bar */
1494
1495                         BBTPointList::const_iterator prev = fi;
1496                         BBTPointList::const_iterator next = fi;
1497
1498                         if ((*fi).frame == frame) {
1499                                 return frame;
1500                         }
1501
1502                         while ((*prev).beat != 1) {
1503                                 if (prev == _map.begin()) {
1504                                         break;
1505                                 }
1506                                 prev--;
1507                         }
1508
1509                         while ((next != _map.end()) && (*next).beat != 1) {
1510                                 next++;
1511                         }
1512
1513                         if ((next == _map.end()) || (frame - (*prev).frame) < ((*next).frame - frame)) {
1514                                 return (*prev).frame;
1515                         } else {
1516                                 return (*next).frame;
1517                         }
1518
1519                 }
1520
1521                 break;
1522
1523         case Beat:
1524                 if (dir < 0) {
1525
1526                         if (fi == _map.begin()) {
1527                                 return 0;
1528                         }
1529
1530                         if ((*fi).frame > frame || ((*fi).frame == frame && dir == RoundDownAlways)) {
1531                                 DEBUG_TRACE (DEBUG::SnapBBT, "requested frame is on beat, step back\n");
1532                                 --fi;
1533                         }
1534                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to beat: map iter at %1|%2 %3, return\n",
1535                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1536                         return (*fi).frame;
1537                 } else if (dir > 0) {
1538                         if ((*fi).frame < frame || ((*fi).frame == frame && dir == RoundUpAlways)) {
1539                                 DEBUG_TRACE (DEBUG::SnapBBT, "requested frame is on beat, step forward\n");
1540                                 ++fi;
1541                         }
1542                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to beat: map iter at %1|%2 %3, return\n",
1543                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1544                         return (*fi).frame;
1545                 } else {
1546                         /* find beat nearest to frame */
1547                         if ((*fi).frame == frame) {
1548                                 return frame;
1549                         }
1550
1551                         BBTPointList::const_iterator prev = fi;
1552                         BBTPointList::const_iterator next = fi;
1553
1554                         /* fi is already the beat before_or_at frame, and
1555                            we've just established that its not at frame, so its
1556                            the beat before frame.
1557                         */
1558                         ++next;
1559
1560                         if ((next == _map.end()) || (frame - (*prev).frame) < ((*next).frame - frame)) {
1561                                 return (*prev).frame;
1562                         } else {
1563                                 return (*next).frame;
1564                         }
1565                 }
1566                 break;
1567         }
1568
1569         abort(); /* NOTREACHED */
1570         return 0;
1571 }
1572
1573 void
1574 TempoMap::get_grid (TempoMap::BBTPointList::const_iterator& begin,
1575                     TempoMap::BBTPointList::const_iterator& end,
1576                     framepos_t lower, framepos_t upper)
1577 {
1578         {
1579                 Glib::Threads::RWLock::WriterLock lm (lock);
1580                 if (_map.empty() || (_map.back().frame < upper)) {
1581                         recompute_map (false, upper);
1582                 }
1583         }
1584
1585         begin = lower_bound (_map.begin(), _map.end(), lower);
1586         end = upper_bound (_map.begin(), _map.end(), upper);
1587 }
1588
1589 const TempoSection&
1590 TempoMap::tempo_section_at (framepos_t frame) const
1591 {
1592         Glib::Threads::RWLock::ReaderLock lm (lock);
1593         Metrics::const_iterator i;
1594         TempoSection* prev = 0;
1595
1596         for (i = metrics.begin(); i != metrics.end(); ++i) {
1597                 TempoSection* t;
1598
1599                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1600
1601                         if ((*i)->frame() > frame) {
1602                                 break;
1603                         }
1604
1605                         prev = t;
1606                 }
1607         }
1608
1609         if (prev == 0) {
1610                 fatal << endmsg;
1611                 abort(); /*NOTREACHED*/
1612         }
1613
1614         return *prev;
1615 }
1616
1617 const Tempo&
1618 TempoMap::tempo_at (framepos_t frame) const
1619 {
1620         TempoMetric m (metric_at (frame));
1621         return m.tempo();
1622 }
1623
1624 const MeterSection&
1625 TempoMap::meter_section_at (framepos_t frame) const
1626 {
1627         Glib::Threads::RWLock::ReaderLock lm (lock);
1628         Metrics::const_iterator i;
1629         MeterSection* prev = 0;
1630
1631         for (i = metrics.begin(); i != metrics.end(); ++i) {
1632                 MeterSection* t;
1633
1634                 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1635
1636                         if ((*i)->frame() > frame) {
1637                                 break;
1638                         }
1639
1640                         prev = t;
1641                 }
1642         }
1643
1644         if (prev == 0) {
1645                 fatal << endmsg;
1646                 abort(); /*NOTREACHED*/
1647         }
1648
1649         return *prev;
1650 }
1651
1652 const Meter&
1653 TempoMap::meter_at (framepos_t frame) const
1654 {
1655         TempoMetric m (metric_at (frame));
1656         return m.meter();
1657 }
1658
1659 XMLNode&
1660 TempoMap::get_state ()
1661 {
1662         Metrics::const_iterator i;
1663         XMLNode *root = new XMLNode ("TempoMap");
1664
1665         {
1666                 Glib::Threads::RWLock::ReaderLock lm (lock);
1667                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1668                         root->add_child_nocopy ((*i)->get_state());
1669                 }
1670         }
1671
1672         return *root;
1673 }
1674
1675 int
1676 TempoMap::set_state (const XMLNode& node, int /*version*/)
1677 {
1678         {
1679                 Glib::Threads::RWLock::WriterLock lm (lock);
1680
1681                 XMLNodeList nlist;
1682                 XMLNodeConstIterator niter;
1683                 Metrics old_metrics (metrics);
1684                 MeterSection* last_meter = 0;
1685                 metrics.clear();
1686
1687                 nlist = node.children();
1688
1689                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1690                         XMLNode* child = *niter;
1691
1692                         if (child->name() == TempoSection::xml_state_node_name) {
1693
1694                                 try {
1695                                         TempoSection* ts = new TempoSection (*child);
1696                                         metrics.push_back (ts);
1697
1698                                         if (ts->bar_offset() < 0.0) {
1699                                                 if (last_meter) {
1700                                                         ts->update_bar_offset_from_bbt (*last_meter);
1701                                                 }
1702                                         }
1703                                 }
1704
1705                                 catch (failed_constructor& err){
1706                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1707                                         metrics = old_metrics;
1708                                         break;
1709                                 }
1710
1711                         } else if (child->name() == MeterSection::xml_state_node_name) {
1712
1713                                 try {
1714                                         MeterSection* ms = new MeterSection (*child);
1715                                         metrics.push_back (ms);
1716                                         last_meter = ms;
1717                                 }
1718
1719                                 catch (failed_constructor& err) {
1720                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1721                                         metrics = old_metrics;
1722                                         break;
1723                                 }
1724                         }
1725                 }
1726
1727                 if (niter == nlist.end()) {
1728                         MetricSectionSorter cmp;
1729                         metrics.sort (cmp);
1730                 }
1731
1732                 /* check for multiple tempo/meters at the same location, which
1733                    ardour2 somehow allowed.
1734                 */
1735
1736                 Metrics::iterator prev = metrics.end();
1737                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1738                         if (prev != metrics.end()) {
1739                                 if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
1740                                         if ((*prev)->start() == (*i)->start()) {
1741                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
1742                                                 error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
1743                                                 return -1;
1744                                         }
1745                                 } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
1746                                         if ((*prev)->start() == (*i)->start()) {
1747                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
1748                                                 error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
1749                                                 return -1;
1750                                         }
1751                                 }
1752                         }
1753                         prev = i;
1754                 }
1755
1756                 recompute_map (true, -1);
1757         }
1758
1759         PropertyChanged (PropertyChange ());
1760
1761         return 0;
1762 }
1763
1764 void
1765 TempoMap::dump (std::ostream& o) const
1766 {
1767         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1768         const MeterSection* m;
1769         const TempoSection* t;
1770
1771         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1772
1773                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1774                         o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (movable? "
1775                           << t->movable() << ')' << endl;
1776                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1777                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1778                           << " (movable? " << m->movable() << ')' << endl;
1779                 }
1780         }
1781 }
1782
1783 int
1784 TempoMap::n_tempos() const
1785 {
1786         Glib::Threads::RWLock::ReaderLock lm (lock);
1787         int cnt = 0;
1788
1789         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1790                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1791                         cnt++;
1792                 }
1793         }
1794
1795         return cnt;
1796 }
1797
1798 int
1799 TempoMap::n_meters() const
1800 {
1801         Glib::Threads::RWLock::ReaderLock lm (lock);
1802         int cnt = 0;
1803
1804         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1805                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1806                         cnt++;
1807                 }
1808         }
1809
1810         return cnt;
1811 }
1812
1813 void
1814 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1815 {
1816         {
1817                 Glib::Threads::RWLock::WriterLock lm (lock);
1818                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1819                         if ((*i)->frame() >= where && (*i)->movable ()) {
1820                                 (*i)->set_frame ((*i)->frame() + amount);
1821                         }
1822                 }
1823
1824                 /* now reset the BBT time of all metrics, based on their new
1825                  * audio time. This is the only place where we do this reverse
1826                  * timestamp.
1827                  */
1828
1829                 Metrics::iterator i;
1830                 const MeterSection* meter;
1831                 const TempoSection* tempo;
1832                 MeterSection *m;
1833                 TempoSection *t;
1834
1835                 meter = &first_meter ();
1836                 tempo = &first_tempo ();
1837
1838                 BBT_Time start;
1839                 BBT_Time end;
1840
1841                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
1842
1843                 bool first = true;
1844                 MetricSection* prev = 0;
1845
1846                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1847
1848                         BBT_Time bbt;
1849                         TempoMetric metric (*meter, *tempo);
1850
1851                         if (prev) {
1852                                 metric.set_start (prev->start());
1853                                 metric.set_frame (prev->frame());
1854                         } else {
1855                                 // metric will be at frames=0 bbt=1|1|0 by default
1856                                 // which is correct for our purpose
1857                         }
1858
1859                         BBTPointList::const_iterator bi = bbt_before_or_at ((*i)->frame());
1860                         bbt_time ((*i)->frame(), bbt, bi);
1861
1862                         // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
1863
1864                         if (first) {
1865                                 first = false;
1866                         } else {
1867
1868                                 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
1869                                         /* round up to next beat */
1870                                         bbt.beats += 1;
1871                                 }
1872
1873                                 bbt.ticks = 0;
1874
1875                                 if (bbt.beats != 1) {
1876                                         /* round up to next bar */
1877                                         bbt.bars += 1;
1878                                         bbt.beats = 1;
1879                                 }
1880                         }
1881
1882                         // cerr << bbt << endl;
1883
1884                         (*i)->set_start (bbt);
1885
1886                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1887                                 tempo = t;
1888                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
1889                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
1890                                 meter = m;
1891                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
1892                         } else {
1893                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
1894                                 abort(); /*NOTREACHED*/
1895                         }
1896
1897                         prev = (*i);
1898                 }
1899
1900                 recompute_map (true);
1901         }
1902
1903
1904         PropertyChanged (PropertyChange ());
1905 }
1906 bool
1907 TempoMap::remove_time (framepos_t where, framecnt_t amount)
1908 {
1909         bool moved = false;
1910
1911         std::list<MetricSection*> metric_kill_list;
1912
1913         TempoSection* last_tempo = NULL;
1914         MeterSection* last_meter = NULL;
1915         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
1916         bool meter_after = false; // is there a meter marker likewise?
1917         {
1918                 Glib::Threads::RWLock::WriterLock lm (lock);
1919                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1920                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
1921                                 metric_kill_list.push_back(*i);
1922                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
1923                                 if (lt)
1924                                         last_tempo = lt;
1925                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
1926                                 if (lm)
1927                                         last_meter = lm;
1928                         }
1929                         else if ((*i)->frame() >= where) {
1930                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
1931                                 (*i)->set_frame ((*i)->frame() - amount);
1932                                 if ((*i)->frame() == where) {
1933                                         // marker was immediately after end of range
1934                                         tempo_after = dynamic_cast<TempoSection*> (*i);
1935                                         meter_after = dynamic_cast<MeterSection*> (*i);
1936                                 }
1937                                 moved = true;
1938                         }
1939                 }
1940
1941                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
1942                 if (last_tempo && !tempo_after) {
1943                         metric_kill_list.remove(last_tempo);
1944                         last_tempo->set_frame(where);
1945                         moved = true;
1946                 }
1947                 if (last_meter && !meter_after) {
1948                         metric_kill_list.remove(last_meter);
1949                         last_meter->set_frame(where);
1950                         moved = true;
1951                 }
1952
1953                 //remove all the remaining metrics
1954                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
1955                         metrics.remove(*i);
1956                         moved = true;
1957                 }
1958
1959                 if (moved) {
1960                         recompute_map (true);
1961                 }
1962         }
1963         PropertyChanged (PropertyChange ());
1964         return moved;
1965 }
1966
1967 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1968  *  pos can be -ve, if required.
1969  */
1970 framepos_t
1971 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
1972 {
1973         Glib::Threads::RWLock::ReaderLock lm (lock);
1974         Metrics::const_iterator next_tempo;
1975         const TempoSection* tempo = 0;
1976
1977         /* Find the starting tempo metric */
1978
1979         for (next_tempo = metrics.begin(); next_tempo != metrics.end(); ++next_tempo) {
1980
1981                 const TempoSection* t;
1982
1983                 if ((t = dynamic_cast<const TempoSection*>(*next_tempo)) != 0) {
1984
1985                         /* This is a bit of a hack, but pos could be -ve, and if it is,
1986                            we consider the initial metric changes (at time 0) to actually
1987                            be in effect at pos.
1988                         */
1989
1990                         framepos_t f = (*next_tempo)->frame ();
1991
1992                         if (pos < 0 && f == 0) {
1993                                 f = pos;
1994                         }
1995
1996                         if (f > pos) {
1997                                 break;
1998                         }
1999
2000                         tempo = t;
2001                 }
2002         }
2003
2004         /* We now have:
2005
2006            tempo       -> the Tempo for "pos"
2007            next_tempo  -> first tempo after "pos", possibly metrics.end()
2008         */
2009         assert(tempo);
2010
2011         DEBUG_TRACE (DEBUG::TempoMath,
2012                      string_compose ("frame %1 plus %2 beats, start with tempo = %3 @ %4\n",
2013                                      pos, beats, *((const Tempo*)tempo), tempo->frame()));
2014
2015         while (!!beats) {
2016
2017                 /* Distance to the end of this section in frames */
2018                 framecnt_t distance_frames = (next_tempo == metrics.end() ? max_framepos : ((*next_tempo)->frame() - pos));
2019
2020                 /* Distance to the end in beats */
2021                 Evoral::Beats distance_beats = Evoral::Beats::ticks_at_rate(
2022                         distance_frames, tempo->frames_per_beat (_frame_rate));
2023
2024                 /* Amount to subtract this time */
2025                 Evoral::Beats const delta = min (distance_beats, beats);
2026
2027                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n",
2028                                                                (next_tempo == metrics.end() ? max_framepos : (*next_tempo)->frame()),
2029                                                                distance_frames, distance_beats));
2030
2031                 /* Update */
2032                 beats -= delta;
2033                 pos += delta.to_ticks(tempo->frames_per_beat (_frame_rate));
2034
2035                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left\n", pos, beats));
2036
2037                 /* step forwards to next tempo section */
2038
2039                 if (next_tempo != metrics.end()) {
2040
2041                         tempo = dynamic_cast<const TempoSection*>(*next_tempo);
2042
2043                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
2044                                                                        *((const Tempo*)tempo), tempo->frame(),
2045                                                                        tempo->frames_per_beat (_frame_rate)));
2046
2047                         while (next_tempo != metrics.end ()) {
2048
2049                                 ++next_tempo;
2050
2051                                 if (next_tempo != metrics.end() && dynamic_cast<const TempoSection*>(*next_tempo)) {
2052                                         break;
2053                                 }
2054                         }
2055                 }
2056         }
2057
2058         return pos;
2059 }
2060
2061 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2062 framepos_t
2063 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2064 {
2065         Glib::Threads::RWLock::ReaderLock lm (lock);
2066         Metrics::const_reverse_iterator prev_tempo;
2067         const TempoSection* tempo = 0;
2068
2069         /* Find the starting tempo metric */
2070
2071         for (prev_tempo = metrics.rbegin(); prev_tempo != metrics.rend(); ++prev_tempo) {
2072
2073                 const TempoSection* t;
2074
2075                 if ((t = dynamic_cast<const TempoSection*>(*prev_tempo)) != 0) {
2076
2077                         /* This is a bit of a hack, but pos could be -ve, and if it is,
2078                            we consider the initial metric changes (at time 0) to actually
2079                            be in effect at pos.
2080                         */
2081
2082                         framepos_t f = (*prev_tempo)->frame ();
2083
2084                         if (pos < 0 && f == 0) {
2085                                 f = pos;
2086                         }
2087
2088                         /* this is slightly more complex than the forward case
2089                            because we reach the tempo in effect at pos after
2090                            passing through pos (rather before, as in the
2091                            forward case). having done that, we then need to
2092                            keep going to get the previous tempo (or
2093                            metrics.rend())
2094                         */
2095
2096                         if (f <= pos) {
2097                                 if (tempo == 0) {
2098                                         /* first tempo with position at or
2099                                            before pos
2100                                         */
2101                                         tempo = t;
2102                                 } else if (f < pos) {
2103                                         /* some other tempo section that
2104                                            is even earlier than 'tempo'
2105                                         */
2106                                         break;
2107                                 }
2108                         }
2109                 }
2110         }
2111
2112         assert(tempo);
2113         DEBUG_TRACE (DEBUG::TempoMath,
2114                      string_compose ("frame %1 minus %2 beats, start with tempo = %3 @ %4 prev at beg? %5\n",
2115                                      pos, beats, *((const Tempo*)tempo), tempo->frame(),
2116                                      prev_tempo == metrics.rend()));
2117
2118         /* We now have:
2119
2120            tempo       -> the Tempo for "pos"
2121            prev_tempo  -> the first metric before "pos", possibly metrics.rend()
2122         */
2123
2124         while (!!beats) {
2125
2126                 /* Distance to the start of this section in frames */
2127                 framecnt_t distance_frames = (pos - tempo->frame());
2128
2129                 /* Distance to the start in beats */
2130                 Evoral::Beats distance_beats = Evoral::Beats::ticks_at_rate(
2131                         distance_frames, tempo->frames_per_beat (_frame_rate));
2132
2133                 /* Amount to subtract this time */
2134                 Evoral::Beats const sub = min (distance_beats, beats);
2135
2136                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n",
2137                                                                tempo->frame(), distance_frames, distance_beats));
2138                 /* Update */
2139
2140                 beats -= sub;
2141                 pos -= sub.to_double() * tempo->frames_per_beat (_frame_rate);
2142
2143                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left, prev at end ? %3\n", pos, beats,
2144                                                                (prev_tempo == metrics.rend())));
2145
2146                 /* step backwards to prior TempoSection */
2147
2148                 if (prev_tempo != metrics.rend()) {
2149
2150                         tempo = dynamic_cast<const TempoSection*>(*prev_tempo);
2151
2152                         DEBUG_TRACE (DEBUG::TempoMath,
2153                                      string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
2154                                                      *((const Tempo*)tempo), tempo->frame(),
2155                                                      tempo->frames_per_beat (_frame_rate)));
2156
2157                         while (prev_tempo != metrics.rend ()) {
2158
2159                                 ++prev_tempo;
2160
2161                                 if (prev_tempo != metrics.rend() && dynamic_cast<const TempoSection*>(*prev_tempo) != 0) {
2162                                         break;
2163                                 }
2164                         }
2165                 } else {
2166                         pos -= llrint (beats.to_double() * tempo->frames_per_beat (_frame_rate));
2167                         beats = Evoral::Beats();
2168                 }
2169         }
2170
2171         return pos;
2172 }
2173
2174 /** Add the BBT interval op to pos and return the result */
2175 framepos_t
2176 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2177 {
2178         Glib::Threads::RWLock::ReaderLock lm (lock);
2179         Metrics::const_iterator i;
2180         const MeterSection* meter;
2181         const MeterSection* m;
2182         const TempoSection* tempo;
2183         const TempoSection* t;
2184         double frames_per_beat;
2185         framepos_t effective_pos = max (pos, (framepos_t) 0);
2186
2187         meter = &first_meter ();
2188         tempo = &first_tempo ();
2189
2190         assert (meter);
2191         assert (tempo);
2192
2193         /* find the starting metrics for tempo & meter */
2194
2195         for (i = metrics.begin(); i != metrics.end(); ++i) {
2196
2197                 if ((*i)->frame() > effective_pos) {
2198                         break;
2199                 }
2200
2201                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2202                         tempo = t;
2203                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2204                         meter = m;
2205                 }
2206         }
2207
2208         /* We now have:
2209
2210            meter -> the Meter for "pos"
2211            tempo -> the Tempo for "pos"
2212            i     -> for first new metric after "pos", possibly metrics.end()
2213         */
2214
2215         /* now comes the complicated part. we have to add one beat a time,
2216            checking for a new metric on every beat.
2217         */
2218
2219         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2220
2221         uint64_t bars = 0;
2222
2223         while (op.bars) {
2224
2225                 bars++;
2226                 op.bars--;
2227
2228                 /* check if we need to use a new metric section: has adding frames moved us
2229                    to or after the start of the next metric section? in which case, use it.
2230                 */
2231
2232                 if (i != metrics.end()) {
2233                         if ((*i)->frame() <= pos) {
2234
2235                                 /* about to change tempo or meter, so add the
2236                                  * number of frames for the bars we've just
2237                                  * traversed before we change the
2238                                  * frames_per_beat value.
2239                                  */
2240
2241                                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2242                                 bars = 0;
2243
2244                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2245                                         tempo = t;
2246                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2247                                         meter = m;
2248                                 }
2249                                 ++i;
2250                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2251
2252                         }
2253                 }
2254
2255         }
2256
2257         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2258
2259         uint64_t beats = 0;
2260
2261         while (op.beats) {
2262
2263                 /* given the current meter, have we gone past the end of the bar ? */
2264
2265                 beats++;
2266                 op.beats--;
2267
2268                 /* check if we need to use a new metric section: has adding frames moved us
2269                    to or after the start of the next metric section? in which case, use it.
2270                 */
2271
2272                 if (i != metrics.end()) {
2273                         if ((*i)->frame() <= pos) {
2274
2275                                 /* about to change tempo or meter, so add the
2276                                  * number of frames for the beats we've just
2277                                  * traversed before we change the
2278                                  * frames_per_beat value.
2279                                  */
2280
2281                                 pos += llrint (beats * frames_per_beat);
2282                                 beats = 0;
2283
2284                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2285                                         tempo = t;
2286                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2287                                         meter = m;
2288                                 }
2289                                 ++i;
2290                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2291                         }
2292                 }
2293         }
2294
2295         pos += llrint (beats * frames_per_beat);
2296
2297         if (op.ticks) {
2298                 if (op.ticks >= BBT_Time::ticks_per_beat) {
2299                         pos += llrint (frames_per_beat + /* extra beat */
2300                                        (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) /
2301                                                            (double) BBT_Time::ticks_per_beat)));
2302                 } else {
2303                         pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2304                 }
2305         }
2306
2307         return pos;
2308 }
2309
2310 /** Count the number of beats that are equivalent to distance when going forward,
2311     starting at pos.
2312 */
2313 Evoral::Beats
2314 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2315 {
2316         Glib::Threads::RWLock::ReaderLock lm (lock);
2317         Metrics::const_iterator next_tempo;
2318         const TempoSection* tempo = 0;
2319         framepos_t effective_pos = max (pos, (framepos_t) 0);
2320
2321         /* Find the relevant initial tempo metric  */
2322
2323         for (next_tempo = metrics.begin(); next_tempo != metrics.end(); ++next_tempo) {
2324
2325                 const TempoSection* t;
2326
2327                 if ((t = dynamic_cast<const TempoSection*>(*next_tempo)) != 0) {
2328
2329                         if ((*next_tempo)->frame() > effective_pos) {
2330                                 break;
2331                         }
2332
2333                         tempo = t;
2334                 }
2335         }
2336
2337         /* We now have:
2338
2339            tempo -> the Tempo for "pos"
2340            next_tempo -> the next tempo after "pos", possibly metrics.end()
2341         */
2342         assert (tempo);
2343
2344         DEBUG_TRACE (DEBUG::TempoMath,
2345                      string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n",
2346                                      pos, distance, *((const Tempo*)tempo), tempo->frame()));
2347
2348         Evoral::Beats beats = Evoral::Beats();
2349
2350         while (distance) {
2351
2352                 /* End of this section */
2353                 framepos_t end;
2354                 /* Distance to `end' in frames */
2355                 framepos_t distance_to_end;
2356
2357                 if (next_tempo == metrics.end ()) {
2358                         /* We can't do (end - pos) if end is max_framepos, as it will overflow if pos is -ve */
2359                         end = max_framepos;
2360                         distance_to_end = max_framepos;
2361                 } else {
2362                         end = (*next_tempo)->frame ();
2363                         distance_to_end = end - pos;
2364                 }
2365
2366                 /* Amount to subtract this time in frames */
2367                 framecnt_t const sub = min (distance, distance_to_end);
2368
2369                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("to reach end at %1 (end ? %2), distance= %3 sub=%4\n", end, (next_tempo == metrics.end()),
2370                                                                distance_to_end, sub));
2371
2372                 /* Update */
2373                 pos += sub;
2374                 distance -= sub;
2375                 assert (tempo);
2376                 beats += Evoral::Beats::ticks_at_rate(sub, tempo->frames_per_beat (_frame_rate));
2377
2378                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1, beats = %2 distance left %3\n",
2379                                                                pos, beats, distance));
2380
2381                 /* Move on if there's anything to move to */
2382
2383                 if (next_tempo != metrics.end()) {
2384
2385                         tempo = dynamic_cast<const TempoSection*>(*next_tempo);
2386
2387                         DEBUG_TRACE (DEBUG::TempoMath,
2388                                      string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
2389                                                      *((const Tempo*)tempo), tempo->frame(),
2390                                                      tempo->frames_per_beat (_frame_rate)));
2391
2392                         while (next_tempo != metrics.end ()) {
2393
2394                                 ++next_tempo;
2395
2396                                 if (next_tempo != metrics.end() && dynamic_cast<const TempoSection*>(*next_tempo)) {
2397                                         break;
2398                                 }
2399                         }
2400
2401                         if (next_tempo == metrics.end()) {
2402                                 DEBUG_TRACE (DEBUG::TempoMath, "no more tempo sections\n");
2403                         } else {
2404                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("next tempo section is %1 @ %2\n",
2405                                                                                **next_tempo, (*next_tempo)->frame()));
2406                         }
2407
2408                 }
2409                 assert (tempo);
2410         }
2411
2412         return beats;
2413 }
2414
2415 TempoMap::BBTPointList::const_iterator
2416 TempoMap::bbt_before_or_at (framepos_t pos)
2417 {
2418         /* CALLER MUST HOLD READ LOCK */
2419
2420         BBTPointList::const_iterator i;
2421
2422         if (pos < 0) {
2423                 /* not really correct, but we should catch pos < 0 at a higher
2424                    level
2425                 */
2426                 return _map.begin();
2427         }
2428
2429         i = lower_bound (_map.begin(), _map.end(), pos);
2430         assert (i != _map.end());
2431         if ((*i).frame > pos) {
2432                 assert (i != _map.begin());
2433                 --i;
2434         }
2435         return i;
2436 }
2437
2438 struct bbtcmp {
2439     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2440             return a < b;
2441     }
2442 };
2443
2444 TempoMap::BBTPointList::const_iterator
2445 TempoMap::bbt_before_or_at (const BBT_Time& bbt)
2446 {
2447         BBTPointList::const_iterator i;
2448         bbtcmp cmp;
2449
2450         i = lower_bound (_map.begin(), _map.end(), bbt, cmp);
2451         assert (i != _map.end());
2452         if ((*i).bar > bbt.bars || (*i).beat > bbt.beats) {
2453                 assert (i != _map.begin());
2454                 --i;
2455         }
2456         return i;
2457 }
2458
2459 TempoMap::BBTPointList::const_iterator
2460 TempoMap::bbt_after_or_at (framepos_t pos)
2461 {
2462         /* CALLER MUST HOLD READ LOCK */
2463
2464         BBTPointList::const_iterator i;
2465
2466         if (_map.back().frame == pos) {
2467                 i = _map.end();
2468                 assert (i != _map.begin());
2469                 --i;
2470                 return i;
2471         }
2472
2473         i = upper_bound (_map.begin(), _map.end(), pos);
2474         assert (i != _map.end());
2475         return i;
2476 }
2477
2478 std::ostream&
2479 operator<< (std::ostream& o, const Meter& m) {
2480         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2481 }
2482
2483 std::ostream&
2484 operator<< (std::ostream& o, const Tempo& t) {
2485         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2486 }
2487
2488 std::ostream&
2489 operator<< (std::ostream& o, const MetricSection& section) {
2490
2491         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2492
2493         const TempoSection* ts;
2494         const MeterSection* ms;
2495
2496         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2497                 o << *((const Tempo*) ts);
2498         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2499                 o << *((const Meter*) ms);
2500         }
2501
2502         return o;
2503 }