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