Move reader lock to avoid deadlock when calling bbt_time().
[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                 /* we will actually stop once we hit
754                    the last metric.
755                 */
756                 end = max_framepos;
757
758         } else {
759                 if (!_map.empty ()) {
760                         /* never allow the map to be shortened */
761                         end = max (end, _map.back().frame);
762                 }
763         }
764
765         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
766
767         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
768                 MeterSection* ms;
769
770                 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
771                         meter = ms;
772                         break;
773                 }
774         }
775
776         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
777                 TempoSection* ts;
778
779                 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
780                         tempo = ts;
781                         break;
782                 }
783         }
784
785         /* assumes that the first meter & tempo are at frame zero */
786         current_frame = 0;
787         meter->set_frame (0);
788         tempo->set_frame (0);
789
790         /* assumes that the first meter & tempo are at 1|1|0 */
791         current.bars = 1;
792         current.beats = 1;
793         current.ticks = 0;
794
795         if (reassign_tempo_bbt) {
796
797                 MeterSection* rmeter = meter;
798
799                 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
800
801                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
802
803                         TempoSection* ts;
804                         MeterSection* ms;
805         
806                         if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
807
808                                 /* reassign the BBT time of this tempo section
809                                  * based on its bar offset position.
810                                  */
811
812                                 ts->update_bbt_time_from_bar_offset (*rmeter);
813
814                         } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
815                                 rmeter = ms;
816                         } else {
817                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
818                                 /*NOTREACHED*/
819                         }
820                 }
821         }
822
823         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
824
825         next_metric = metrics.begin();
826         ++next_metric; // skip meter (or tempo)
827         ++next_metric; // skip tempo (or meter)
828
829         _map.clear ();
830
831         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
832         _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), 1, 1));
833
834         if (end == 0) {
835                 /* silly call from Session::process() during startup
836                  */
837                 return;
838         }
839
840         _extend_map (tempo, meter, next_metric, current, current_frame, end);
841 }
842
843 void
844 TempoMap::extend_map (framepos_t end)
845 {
846         /* CALLER MUST HOLD WRITE LOCK */
847
848         if (_map.empty()) {
849                 recompute_map (false, end);
850                 return;
851         }
852
853         BBTPointList::const_iterator i = _map.end();    
854         Metrics::iterator next_metric;
855
856         --i;
857
858         BBT_Time last_metric_start;
859
860         if ((*i).tempo->frame() > (*i).meter->frame()) {
861                 last_metric_start = (*i).tempo->start();
862         } else {
863                 last_metric_start = (*i).meter->start();
864         }
865
866         /* find the metric immediately after the tempo + meter sections for the
867          * last point in the map 
868          */
869
870         for (next_metric = metrics.begin(); next_metric != metrics.end(); ++next_metric) {
871                 if ((*next_metric)->start() > last_metric_start) {
872                         break;
873                 }
874         }
875
876         /* we cast away const here because this is the one place where we need
877          * to actually modify the frame time of each metric section. 
878          */
879
880         _extend_map (const_cast<TempoSection*> ((*i).tempo), 
881                      const_cast<MeterSection*> ((*i).meter),
882                      next_metric, BBT_Time ((*i).bar, (*i).beat, 0), (*i).frame, end);
883 }
884
885 void
886 TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter, 
887                        Metrics::iterator next_metric,
888                        BBT_Time current, framepos_t current_frame, framepos_t end)
889 {
890         /* CALLER MUST HOLD WRITE LOCK */
891
892         TempoSection* ts;
893         MeterSection* ms;
894         double beat_frames;
895         framepos_t bar_start_frame;
896
897         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Extend map to %1 from %2 = %3\n", end, current, current_frame));
898
899         if (current.beats == 1) {
900                 bar_start_frame = current_frame;
901         } else {
902                 bar_start_frame = 0;
903         }
904
905         beat_frames = meter->frames_per_grid (*tempo,_frame_rate);
906
907         while (current_frame < end) {
908
909                 current.beats++;
910                 current_frame += beat_frames;
911
912                 if (current.beats > meter->divisions_per_bar()) {
913                         current.bars++;
914                         current.beats = 1;
915                 }
916
917                 if (next_metric != metrics.end()) {
918
919                         /* no operator >= so invert operator < */
920
921                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1 next metric @ %2\n", current, (*next_metric)->start()));
922
923                         if (!(current < (*next_metric)->start())) {
924
925                           set_metrics:
926                                 if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0)) {
927
928                                         tempo = ts;
929
930                                         /* new tempo section: if its on a beat,
931                                          * we don't have to do anything other
932                                          * than recompute various distances,
933                                          * done further below as we transition
934                                          * the next metric section.
935                                          *
936                                          * if its not on the beat, we have to
937                                          * compute the duration of the beat it
938                                          * is within, which will be different
939                                          * from the preceding following ones
940                                          * since it takes part of its duration
941                                          * from the preceding tempo and part 
942                                          * from this new tempo.
943                                          */
944
945                                         if (tempo->start().ticks != 0) {
946                                                 
947                                                 double next_beat_frames = tempo->frames_per_beat (_frame_rate);                                 
948                                                 
949                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
950                                                                                                tempo->start(), current_frame, tempo->bar_offset()));
951                                                 
952                                                 /* back up to previous beat */
953                                                 current_frame -= beat_frames;
954
955                                                 /* set tempo section location
956                                                  * based on offset from last
957                                                  * bar start 
958                                                  */
959                                                 tempo->set_frame (bar_start_frame + 
960                                                                   llrint ((ts->bar_offset() * meter->divisions_per_bar() * beat_frames)));
961                                                 
962                                                 /* advance to the location of
963                                                  * the new (adjusted) beat. do
964                                                  * this by figuring out the
965                                                  * offset within the beat that
966                                                  * would have been there
967                                                  * without the tempo
968                                                  * change. then stretch the
969                                                  * beat accordingly.
970                                                  */
971
972                                                 double offset_within_old_beat = (tempo->frame() - current_frame) / beat_frames;
973
974                                                 current_frame += (offset_within_old_beat * beat_frames) + ((1.0 - offset_within_old_beat) * next_beat_frames);
975
976                                                 /* next metric doesn't have to
977                                                  * match this precisely to
978                                                  * merit a reloop ...
979                                                  */
980                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Adjusted last beat to %1\n", current_frame));
981                                                 
982                                         } else {
983                                                 
984                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into beat-aligned tempo metric at %1 = %2\n",
985                                                                                                tempo->start(), current_frame));
986                                                 tempo->set_frame (current_frame);
987                                         }
988
989                                 } else if ((ms = dynamic_cast<MeterSection*>(*next_metric)) != 0) {
990                                         
991                                         meter = ms;
992
993                                         /* new meter section: always defines the
994                                          * start of a bar.
995                                          */
996                                         
997                                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into meter section at %1 vs %2 (%3)\n",
998                                                                                        meter->start(), current, current_frame));
999                                         
1000                                         assert (current.beats == 1);
1001
1002                                         meter->set_frame (current_frame);
1003                                 }
1004                                 
1005                                 beat_frames = meter->frames_per_grid (*tempo, _frame_rate);
1006                                 
1007                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 dpb %2 meter %3 tempo %4\n", 
1008                                                                                beat_frames, meter->divisions_per_bar(), *((Meter*)meter), *((Tempo*)tempo)));
1009                         
1010                                 ++next_metric;
1011
1012                                 if (next_metric != metrics.end() && ((*next_metric)->start() == current)) {
1013                                         /* same position so go back and set this one up before advancing
1014                                         */
1015                                         goto set_metrics;
1016                                 }
1017                         }
1018                 } 
1019
1020                 if (current.beats == 1) {
1021                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
1022                         _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), current.bars, 1));
1023                         bar_start_frame = current_frame;
1024                 } else {
1025                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
1026                         _map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), current.bars, current.beats));
1027                 }
1028
1029                 if (next_metric == metrics.end()) {
1030                         /* no more metrics - we've timestamped them all, stop here */
1031                         if (end == max_framepos) {
1032                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stop extending map now that we've reach the end @ %1|%2 = %3\n",
1033                                                                                current.bars, current.beats, current_frame));
1034                                 break;
1035                         }
1036                 }
1037         }
1038 }
1039
1040 TempoMetric
1041 TempoMap::metric_at (framepos_t frame) const
1042 {
1043         Glib::RWLock::ReaderLock lm (lock);
1044         TempoMetric m (first_meter(), first_tempo());
1045         const Meter* meter;
1046         const Tempo* tempo;
1047
1048         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1049            at something, because we insert the default tempo and meter during
1050            TempoMap construction.
1051
1052            now see if we can find better candidates.
1053         */
1054
1055         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1056
1057                 if ((*i)->frame() > frame) {
1058                         break;
1059                 }
1060
1061                 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
1062                         m.set_tempo (*tempo);
1063                 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
1064                         m.set_meter (*meter);
1065                 }
1066
1067                 m.set_frame ((*i)->frame ());
1068                 m.set_start ((*i)->start ());
1069         }
1070         
1071         return m;
1072 }
1073
1074 TempoMetric
1075 TempoMap::metric_at (BBT_Time bbt) const
1076 {
1077         Glib::RWLock::ReaderLock lm (lock);
1078         TempoMetric m (first_meter(), first_tempo());
1079         const Meter* meter;
1080         const Tempo* tempo;
1081
1082         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1083            at something, because we insert the default tempo and meter during
1084            TempoMap construction.
1085
1086            now see if we can find better candidates.
1087         */
1088
1089         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1090
1091                 BBT_Time section_start ((*i)->start());
1092
1093                 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1094                         break;
1095                 }
1096
1097                 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
1098                         m.set_tempo (*tempo);
1099                 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
1100                         m.set_meter (*meter);
1101                 }
1102
1103                 m.set_frame ((*i)->frame ());
1104                 m.set_start (section_start);
1105         }
1106
1107         return m;
1108 }
1109
1110 void
1111 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1112 {
1113         require_map_to (frame);
1114
1115         Glib::RWLock::ReaderLock lm (lock);
1116
1117         if (frame < 0) {
1118                 bbt.bars = 1;
1119                 bbt.beats = 1;
1120                 bbt.ticks = 0;
1121                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1122                 return;
1123         }
1124
1125         return bbt_time (frame, bbt, bbt_before_or_at (frame));
1126 }
1127
1128 void
1129 TempoMap::bbt_time_rt (framepos_t frame, BBT_Time& bbt)
1130 {
1131         Glib::RWLock::ReaderLock lm (lock, Glib::TRY_LOCK);
1132
1133         if (!lm.locked()) {
1134                 throw std::logic_error ("TempoMap::bbt_time_rt() could not lock tempo map");
1135         }
1136         
1137         if (_map.empty() || _map.back().frame < frame) {
1138                 throw std::logic_error (string_compose ("map not long enough to reach %1", frame));
1139         }
1140
1141         return bbt_time (frame, bbt, bbt_before_or_at (frame));
1142 }
1143
1144 void
1145 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt, const BBTPointList::const_iterator& i)
1146 {
1147         /* CALLER MUST HOLD READ LOCK */
1148
1149         bbt.bars = (*i).bar;
1150         bbt.beats = (*i).beat;
1151
1152         if ((*i).frame == frame) {
1153                 bbt.ticks = 0;
1154         } else {
1155                 bbt.ticks = llrint (((frame - (*i).frame) / (*i).tempo->frames_per_beat(_frame_rate)) *
1156                                     BBT_Time::ticks_per_beat);
1157         }
1158 }
1159
1160 framepos_t
1161 TempoMap::frame_time (const BBT_Time& bbt)
1162 {
1163         if (bbt.bars < 1) {
1164                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1165                 return 0;
1166         }
1167         
1168         if (bbt.beats < 1) {
1169                 throw std::logic_error ("beats are counted from one");
1170         }
1171
1172         require_map_to (bbt);
1173
1174         Glib::RWLock::ReaderLock lm (lock);
1175
1176         BBTPointList::const_iterator s = bbt_before_or_at (BBT_Time (1, 1, 0));
1177         BBTPointList::const_iterator e = bbt_before_or_at (BBT_Time (bbt.bars, bbt.beats, 0));
1178
1179         if (bbt.ticks != 0) {
1180                 return ((*e).frame - (*s).frame) + 
1181                         llrint ((*e).tempo->frames_per_beat (_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat));
1182         } else {
1183                 return ((*e).frame - (*s).frame);
1184         }
1185 }
1186
1187 framecnt_t
1188 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1189 {
1190         BBT_Time when;
1191         bbt_time (pos, when);
1192         
1193         Glib::RWLock::ReaderLock lm (lock);
1194         return bbt_duration_at_unlocked (when, bbt, dir);
1195 }
1196
1197 framecnt_t
1198 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) 
1199 {
1200         if (bbt.bars == 0 && bbt.beats == 0 && bbt.ticks == 0) {
1201                 return 0;
1202         }
1203
1204         /* round back to the previous precise beat */
1205         BBTPointList::const_iterator wi = bbt_before_or_at (BBT_Time (when.bars, when.beats, 0));
1206         BBTPointList::const_iterator start (wi);
1207         double tick_frames = 0;
1208
1209         assert (wi != _map.end());
1210
1211         /* compute how much rounding we did because of non-zero ticks */
1212
1213         if (when.ticks != 0) {
1214                 tick_frames = (*wi).tempo->frames_per_beat (_frame_rate) * (when.ticks/BBT_Time::ticks_per_beat);
1215         }
1216         
1217         uint32_t bars = 0;
1218         uint32_t beats = 0;
1219
1220         while (wi != _map.end() && bars < bbt.bars) {
1221                 ++wi;
1222                 if ((*wi).is_bar()) {
1223                         ++bars;
1224                 }
1225         }
1226         assert (wi != _map.end());
1227
1228         while (wi != _map.end() && beats < bbt.beats) {
1229                 ++wi;
1230                 ++beats;
1231         }
1232         assert (wi != _map.end());
1233
1234         /* add any additional frames related to ticks in the added value */
1235
1236         if (bbt.ticks != 0) {
1237                 tick_frames += (*wi).tempo->frames_per_beat (_frame_rate) * (bbt.ticks/BBT_Time::ticks_per_beat);
1238         }
1239
1240         return ((*wi).frame - (*start).frame) + llrint (tick_frames);
1241 }
1242
1243 framepos_t
1244 TempoMap::round_to_bar (framepos_t fr, int dir)
1245 {
1246         return round_to_type (fr, dir, Bar);
1247 }
1248
1249 framepos_t
1250 TempoMap::round_to_beat (framepos_t fr, int dir)
1251 {
1252         return round_to_type (fr, dir, Beat);
1253 }
1254
1255 framepos_t
1256 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1257 {
1258         require_map_to (fr);
1259
1260         Glib::RWLock::ReaderLock lm (lock);
1261         BBTPointList::const_iterator i = bbt_before_or_at (fr);
1262         BBT_Time the_beat;
1263         uint32_t ticks_one_subdivisions_worth;
1264         uint32_t difference;
1265
1266         bbt_time (fr, the_beat, i);
1267
1268         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("round %1 to nearest 1/%2 beat, before-or-at = %3 @ %4|%5 precise = %6\n",
1269                                                      fr, sub_num, (*i).frame, (*i).bar, (*i).beat, the_beat));
1270
1271         ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1272
1273         if (dir > 0) {
1274
1275                 /* round to next (even if we're on a subdivision */
1276
1277                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1278
1279                 if (mod == 0) {
1280                         /* right on the subdivision, so the difference is just the subdivision ticks */
1281                         the_beat.ticks += ticks_one_subdivisions_worth;
1282
1283                 } else {
1284                         /* not on subdivision, compute distance to next subdivision */
1285
1286                         the_beat.ticks += ticks_one_subdivisions_worth - mod;
1287                 }
1288
1289                 if (the_beat.ticks > BBT_Time::ticks_per_beat) {
1290                         assert (i != _map.end());
1291                         ++i;
1292                         assert (i != _map.end());
1293                         the_beat.ticks -= BBT_Time::ticks_per_beat;
1294                 } 
1295
1296
1297         } else if (dir < 0) {
1298
1299                 /* round to previous (even if we're on a subdivision) */
1300
1301                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1302
1303                 if (mod == 0) {
1304                         /* right on the subdivision, so the difference is just the subdivision ticks */
1305                         difference = ticks_one_subdivisions_worth;
1306                 } else {
1307                         /* not on subdivision, compute distance to previous subdivision, which
1308                            is just the modulus.
1309                         */
1310
1311                         difference = mod;
1312                 }
1313
1314                 if (the_beat.ticks < difference) {
1315                         if (i == _map.begin()) {
1316                                 /* can't go backwards from wherever pos is, so just return it */
1317                                 return fr;
1318                         }
1319                         --i;
1320                         the_beat.ticks = BBT_Time::ticks_per_beat - the_beat.ticks;
1321                 } else {
1322                         the_beat.ticks -= difference;
1323                 }
1324
1325         } else {
1326                 /* round to nearest */
1327
1328                 double rem;
1329
1330                 /* compute the distance to the previous and next subdivision */
1331                 
1332                 if ((rem = fmod ((double) the_beat.ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1333                         
1334                         /* closer to the next subdivision, so shift forward */
1335
1336                         the_beat.ticks = lrint (the_beat.ticks + (ticks_one_subdivisions_worth - rem));
1337
1338                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", the_beat.ticks));
1339
1340                         if (the_beat.ticks > BBT_Time::ticks_per_beat) {
1341                                 assert (i != _map.end());
1342                                 ++i;
1343                                 assert (i != _map.end());
1344                                 the_beat.ticks -= BBT_Time::ticks_per_beat;
1345                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", the_beat));
1346                         } 
1347
1348                 } else if (rem > 0) {
1349                         
1350                         /* closer to previous subdivision, so shift backward */
1351
1352                         if (rem > the_beat.ticks) {
1353                                 if (i == _map.begin()) {
1354                                         /* can't go backwards past zero, so ... */
1355                                         return 0;
1356                                 }
1357                                 /* step back to previous beat */
1358                                 --i;
1359                                 the_beat.ticks = lrint (BBT_Time::ticks_per_beat - rem);
1360                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", the_beat));
1361                         } else {
1362                                 the_beat.ticks = lrint (the_beat.ticks - rem);
1363                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", the_beat.ticks));
1364                         }
1365                 } else {
1366                         /* on the subdivision, do nothing */
1367                 }
1368         }
1369
1370         return (*i).frame + (the_beat.ticks/BBT_Time::ticks_per_beat) * 
1371                 (*i).tempo->frames_per_beat (_frame_rate);
1372 }
1373
1374 framepos_t
1375 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1376 {
1377         require_map_to (frame);
1378
1379         Glib::RWLock::ReaderLock lm (lock);
1380         BBTPointList::const_iterator fi;
1381
1382         if (dir > 0) {
1383                 fi = bbt_after_or_at (frame);
1384         } else {
1385                 fi = bbt_before_or_at (frame);
1386         }
1387
1388         assert (fi != _map.end());
1389
1390         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,
1391                                                      (type == Bar ? "bar" : "beat")));
1392                 
1393         switch (type) {
1394         case Bar:
1395                 if (dir < 0) {
1396                         /* find bar previous to 'frame' */
1397
1398                         if (fi == _map.begin()) {
1399                                 return 0;
1400                         }
1401
1402                         if ((*fi).is_bar() && (*fi).frame == frame) {
1403                                 --fi;
1404                         }
1405
1406                         while (!(*fi).is_bar()) {
1407                                 if (fi == _map.begin()) {
1408                                         break;
1409                                 }
1410                                 fi--;
1411                         }
1412                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to bar: map iter at %1|%2 %3, return\n", 
1413                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1414                         return (*fi).frame;
1415
1416                 } else if (dir > 0) {
1417
1418                         /* find bar following 'frame' */
1419
1420                         if ((*fi).is_bar() && (*fi).frame == frame) {
1421                                 ++fi;
1422                         }
1423
1424                         while (!(*fi).is_bar()) {
1425                                 fi++;
1426                                 if (fi == _map.end()) {
1427                                         --fi;
1428                                         break;
1429                                 }
1430                         }
1431
1432                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to bar: map iter at %1|%2 %3, return\n", 
1433                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1434                         return (*fi).frame;
1435
1436                 } else {
1437                         
1438                         /* true rounding: find nearest bar */
1439
1440                         BBTPointList::const_iterator prev = fi;
1441                         BBTPointList::const_iterator next = fi;
1442
1443                         if ((*fi).frame == frame) {
1444                                 return frame;
1445                         }
1446
1447                         while ((*prev).beat != 1) {
1448                                 if (prev == _map.begin()) {
1449                                         break;
1450                                 }
1451                                 prev--;
1452                         }
1453
1454                         while ((next != _map.end()) && (*next).beat != 1) {
1455                                 next++;
1456                         }
1457
1458                         if ((next == _map.end()) || (frame - (*prev).frame) < ((*next).frame - frame)) {
1459                                 return (*prev).frame;
1460                         } else {
1461                                 return (*next).frame;
1462                         }
1463                         
1464                 }
1465
1466                 break;
1467
1468         case Beat:
1469                 if (dir < 0) {
1470
1471                         if (fi == _map.begin()) {
1472                                 return 0;
1473                         }
1474
1475                         if ((*fi).frame >= frame) {
1476                                 DEBUG_TRACE (DEBUG::SnapBBT, "requested frame is on beat, step back\n");
1477                                 --fi;
1478                         }
1479                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to beat: map iter at %1|%2 %3, return\n", 
1480                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1481                         return (*fi).frame;
1482                 } else if (dir > 0) {
1483                         if ((*fi).frame <= frame) {
1484                                 DEBUG_TRACE (DEBUG::SnapBBT, "requested frame is on beat, step forward\n");
1485                                 ++fi;
1486                         }
1487                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to beat: map iter at %1|%2 %3, return\n", 
1488                                                                      (*fi).bar, (*fi).beat, (*fi).frame));
1489                         return (*fi).frame;
1490                 } else {
1491                         /* find beat nearest to frame */
1492                         if ((*fi).frame == frame) {
1493                                 return frame;
1494                         }
1495
1496                         BBTPointList::const_iterator prev = fi;
1497                         BBTPointList::const_iterator next = fi;
1498
1499                         /* fi is already the beat before_or_at frame, and
1500                            we've just established that its not at frame, so its
1501                            the beat before frame.
1502                         */
1503                         ++next;
1504                         
1505                         if ((next == _map.end()) || (frame - (*prev).frame) < ((*next).frame - frame)) {
1506                                 return (*prev).frame;
1507                         } else {
1508                                 return (*next).frame;
1509                         }
1510                 }
1511                 break;
1512         }
1513
1514         /* NOTREACHED */
1515         assert (false);
1516         return 0;
1517 }
1518
1519 void
1520 TempoMap::get_grid (TempoMap::BBTPointList::const_iterator& begin, 
1521                     TempoMap::BBTPointList::const_iterator& end, 
1522                     framepos_t lower, framepos_t upper) 
1523 {
1524         { 
1525                 Glib::RWLock::WriterLock lm (lock);
1526                 if (_map.empty() || (_map.back().frame < upper)) {
1527                         recompute_map (false, upper);
1528                 }
1529         }
1530
1531         begin = lower_bound (_map.begin(), _map.end(), lower);
1532         end = upper_bound (_map.begin(), _map.end(), upper);
1533 }
1534
1535 const TempoSection&
1536 TempoMap::tempo_section_at (framepos_t frame) const
1537 {
1538         Glib::RWLock::ReaderLock lm (lock);
1539         Metrics::const_iterator i;
1540         TempoSection* prev = 0;
1541
1542         for (i = metrics.begin(); i != metrics.end(); ++i) {
1543                 TempoSection* t;
1544
1545                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1546
1547                         if ((*i)->frame() > frame) {
1548                                 break;
1549                         }
1550
1551                         prev = t;
1552                 }
1553         }
1554
1555         if (prev == 0) {
1556                 fatal << endmsg;
1557         }
1558
1559         return *prev;
1560 }
1561
1562 const Tempo&
1563 TempoMap::tempo_at (framepos_t frame) const
1564 {
1565         TempoMetric m (metric_at (frame));
1566         return m.tempo();
1567 }
1568
1569
1570 const Meter&
1571 TempoMap::meter_at (framepos_t frame) const
1572 {
1573         TempoMetric m (metric_at (frame));
1574         return m.meter();
1575 }
1576
1577 XMLNode&
1578 TempoMap::get_state ()
1579 {
1580         Metrics::const_iterator i;
1581         XMLNode *root = new XMLNode ("TempoMap");
1582
1583         {
1584                 Glib::RWLock::ReaderLock lm (lock);
1585                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1586                         root->add_child_nocopy ((*i)->get_state());
1587                 }
1588         }
1589
1590         return *root;
1591 }
1592
1593 int
1594 TempoMap::set_state (const XMLNode& node, int /*version*/)
1595 {
1596         {
1597                 Glib::RWLock::WriterLock lm (lock);
1598
1599                 XMLNodeList nlist;
1600                 XMLNodeConstIterator niter;
1601                 Metrics old_metrics (metrics);
1602                 MeterSection* last_meter = 0;
1603                 metrics.clear();
1604
1605                 nlist = node.children();
1606                 
1607                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1608                         XMLNode* child = *niter;
1609
1610                         if (child->name() == TempoSection::xml_state_node_name) {
1611
1612                                 try {
1613                                         TempoSection* ts = new TempoSection (*child);
1614                                         metrics.push_back (ts);
1615
1616                                         if (ts->bar_offset() < 0.0) {
1617                                                 if (last_meter) {
1618                                                         ts->update_bar_offset_from_bbt (*last_meter);
1619                                                 } 
1620                                         }
1621                                 }
1622
1623                                 catch (failed_constructor& err){
1624                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1625                                         metrics = old_metrics;
1626                                         break;
1627                                 }
1628
1629                         } else if (child->name() == MeterSection::xml_state_node_name) {
1630
1631                                 try {
1632                                         MeterSection* ms = new MeterSection (*child);
1633                                         metrics.push_back (ms);
1634                                         last_meter = ms;
1635                                 }
1636
1637                                 catch (failed_constructor& err) {
1638                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1639                                         metrics = old_metrics;
1640                                         break;
1641                                 }
1642                         }
1643                 }
1644
1645                 if (niter == nlist.end()) {
1646                         MetricSectionSorter cmp;
1647                         metrics.sort (cmp);
1648                 }
1649
1650                 recompute_map (true, -1);
1651         }
1652
1653         PropertyChanged (PropertyChange ());
1654
1655         return 0;
1656 }
1657
1658 void
1659 TempoMap::dump (std::ostream& o) const
1660 {
1661         Glib::RWLock::ReaderLock lm (lock, Glib::TRY_LOCK);
1662         const MeterSection* m;
1663         const TempoSection* t;
1664
1665         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1666
1667                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1668                         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? "
1669                           << t->movable() << ')' << endl;
1670                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1671                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1672                           << " (movable? " << m->movable() << ')' << endl;
1673                 }
1674         }
1675 }
1676
1677 int
1678 TempoMap::n_tempos() const
1679 {
1680         Glib::RWLock::ReaderLock lm (lock);
1681         int cnt = 0;
1682
1683         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1684                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1685                         cnt++;
1686                 }
1687         }
1688
1689         return cnt;
1690 }
1691
1692 int
1693 TempoMap::n_meters() const
1694 {
1695         Glib::RWLock::ReaderLock lm (lock);
1696         int cnt = 0;
1697
1698         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1699                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1700                         cnt++;
1701                 }
1702         }
1703
1704         return cnt;
1705 }
1706
1707 void
1708 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1709 {
1710         {
1711                 Glib::RWLock::WriterLock lm (lock);
1712                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1713                         if ((*i)->frame() >= where && (*i)->movable ()) {
1714                                 (*i)->set_frame ((*i)->frame() + amount);
1715                         }
1716                 }
1717
1718                 /* now reset the BBT time of all metrics, based on their new
1719                  * audio time. This is the only place where we do this reverse
1720                  * timestamp.
1721                  */
1722
1723                 Metrics::iterator i;
1724                 const MeterSection* meter;
1725                 const TempoSection* tempo;
1726                 MeterSection *m;
1727                 TempoSection *t;
1728                 
1729                 meter = &first_meter ();
1730                 tempo = &first_tempo ();
1731                 
1732                 BBT_Time start;
1733                 BBT_Time end;
1734                 
1735                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
1736                 
1737                 bool first = true;
1738                 MetricSection* prev = 0;
1739                 
1740                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1741                         
1742                         BBT_Time bbt;
1743                         TempoMetric metric (*meter, *tempo);
1744                         
1745                         if (prev) {
1746                                 metric.set_start (prev->start());
1747                                 metric.set_frame (prev->frame());
1748                         } else {
1749                                 // metric will be at frames=0 bbt=1|1|0 by default
1750                                 // which is correct for our purpose
1751                         }
1752                         
1753                         BBTPointList::const_iterator bi = bbt_before_or_at ((*i)->frame());
1754                         bbt_time ((*i)->frame(), bbt, bi);
1755                         
1756                         // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
1757                         
1758                         if (first) {
1759                                 first = false;
1760                         } else {
1761                                 
1762                                 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
1763                                         /* round up to next beat */
1764                                         bbt.beats += 1;
1765                                 }
1766                                 
1767                                 bbt.ticks = 0;
1768                                 
1769                                 if (bbt.beats != 1) {
1770                                         /* round up to next bar */
1771                                         bbt.bars += 1;
1772                                         bbt.beats = 1;
1773                                 }
1774                         }
1775                         
1776                         // cerr << bbt << endl;
1777                         
1778                         (*i)->set_start (bbt);
1779                         
1780                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1781                                 tempo = t;
1782                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
1783                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
1784                                 meter = m;
1785                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
1786                         } else {
1787                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
1788                                 /*NOTREACHED*/
1789                         }
1790                         
1791                         prev = (*i);
1792                 }
1793                 
1794                 recompute_map (true);
1795         }
1796
1797
1798         PropertyChanged (PropertyChange ());
1799 }
1800
1801 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1802  *  pos can be -ve, if required.
1803  */
1804 framepos_t
1805 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
1806 {
1807         Glib::RWLock::ReaderLock lm (lock);
1808         Metrics::const_iterator next_tempo;
1809         const TempoSection* tempo;
1810
1811         /* Find the starting tempo metric */
1812
1813         for (next_tempo = metrics.begin(); next_tempo != metrics.end(); ++next_tempo) {
1814
1815                 const TempoSection* t;
1816
1817                 if ((t = dynamic_cast<const TempoSection*>(*next_tempo)) != 0) {
1818
1819                         /* This is a bit of a hack, but pos could be -ve, and if it is,
1820                            we consider the initial metric changes (at time 0) to actually
1821                            be in effect at pos.
1822                         */
1823
1824                         framepos_t f = (*next_tempo)->frame ();
1825
1826                         if (pos < 0 && f == 0) {
1827                                 f = pos;
1828                         }
1829                         
1830                         if (f > pos) {
1831                                 break;
1832                         }
1833                         
1834                         tempo = t;
1835                 }
1836         }
1837
1838         /* We now have:
1839
1840            tempo       -> the Tempo for "pos"
1841            next_tempo  -> first tempo after "pos", possibly metrics.end()
1842         */
1843
1844         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frame %1 plus %2 beats, start with tempo = %3 @ %4\n",
1845                                                        pos, beats, *((Tempo*)tempo), tempo->frame()));
1846
1847         while (beats) {
1848
1849                 /* Distance to the end of this section in frames */
1850                 framecnt_t distance_frames = (next_tempo == metrics.end() ? max_framepos : ((*next_tempo)->frame() - pos));
1851
1852                 /* Distance to the end in beats */
1853                 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
1854
1855                 /* Amount to subtract this time */
1856                 double const delta = min (distance_beats, beats);
1857
1858                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n",
1859                                                                (next_tempo == metrics.end() ? max_framepos : (*next_tempo)->frame()),
1860                                                                distance_frames, distance_beats));
1861
1862                 /* Update */
1863                 beats -= delta;
1864                 pos += delta * tempo->frames_per_beat (_frame_rate);
1865
1866                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left\n", pos, beats));
1867
1868                 /* step forwards to next tempo section */
1869
1870                 if (next_tempo != metrics.end()) {
1871
1872                         tempo = dynamic_cast<const TempoSection*>(*next_tempo);
1873
1874                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
1875                                                                        *((Tempo*)tempo), tempo->frame(),
1876                                                                        tempo->frames_per_beat (_frame_rate)));
1877
1878                         while (next_tempo != metrics.end ()) {
1879
1880                                 ++next_tempo;
1881                                 
1882                                 if (next_tempo != metrics.end() && dynamic_cast<const TempoSection*>(*next_tempo)) {
1883                                         break;
1884                                 }
1885                         }
1886                 }
1887         }
1888
1889         return pos;
1890 }
1891
1892 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
1893 framepos_t
1894 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
1895 {
1896         Glib::RWLock::ReaderLock lm (lock);
1897         Metrics::const_reverse_iterator prev_tempo;
1898         const TempoSection* tempo = 0;
1899
1900         /* Find the starting tempo metric */
1901
1902         for (prev_tempo = metrics.rbegin(); prev_tempo != metrics.rend(); ++prev_tempo) {
1903
1904                 const TempoSection* t;
1905
1906                 if ((t = dynamic_cast<const TempoSection*>(*prev_tempo)) != 0) {
1907
1908                         /* This is a bit of a hack, but pos could be -ve, and if it is,
1909                            we consider the initial metric changes (at time 0) to actually
1910                            be in effect at pos.
1911                         */
1912
1913                         framepos_t f = (*prev_tempo)->frame ();
1914
1915                         if (pos < 0 && f == 0) {
1916                                 f = pos;
1917                         }
1918
1919                         /* this is slightly more complex than the forward case
1920                            because we reach the tempo in effect at pos after
1921                            passing through pos (rather before, as in the
1922                            forward case). having done that, we then need to
1923                            keep going to get the previous tempo (or
1924                            metrics.rend())
1925                         */
1926                         
1927                         if (f <= pos) {
1928                                 if (tempo == 0) {
1929                                         /* first tempo with position at or
1930                                            before pos
1931                                         */
1932                                         tempo = t;
1933                                 } else if (f < pos) {
1934                                         /* some other tempo section that
1935                                            is even earlier than 'tempo'
1936                                         */
1937                                         break;
1938                                 }
1939                         }
1940                 }
1941         }
1942
1943         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frame %1 minus %2 beats, start with tempo = %3 @ %4 prev at beg? %5\n",
1944                                                        pos, beats, *((Tempo*)tempo), tempo->frame(),
1945                                                        prev_tempo == metrics.rend()));
1946
1947         /* We now have:
1948
1949            tempo       -> the Tempo for "pos"
1950            prev_tempo  -> the first metric before "pos", possibly metrics.rend()
1951         */
1952
1953         while (beats) {
1954                 
1955                 /* Distance to the start of this section in frames */
1956                 framecnt_t distance_frames = (pos - tempo->frame());
1957
1958                 /* Distance to the start in beats */
1959                 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
1960
1961                 /* Amount to subtract this time */
1962                 double const sub = min (distance_beats, beats);
1963
1964                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tdistance to %1 = %2 (%3 beats)\n",
1965                                                                tempo->frame(), distance_frames, distance_beats));
1966                 /* Update */
1967
1968                 beats -= sub;
1969                 pos -= sub * tempo->frames_per_beat (_frame_rate);
1970
1971                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnow at %1, %2 beats left, prev at end ? %3\n", pos, beats,
1972                                                                (prev_tempo == metrics.rend())));
1973
1974                 /* step backwards to prior TempoSection */
1975
1976                 if (prev_tempo != metrics.rend()) {
1977
1978                         tempo = dynamic_cast<const TempoSection*>(*prev_tempo);
1979
1980                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
1981                                                                        *((Tempo*)tempo), tempo->frame(),
1982                                                                        tempo->frames_per_beat (_frame_rate)));
1983
1984                         while (prev_tempo != metrics.rend ()) {
1985
1986                                 ++prev_tempo;
1987
1988                                 if (prev_tempo != metrics.rend() && dynamic_cast<const TempoSection*>(*prev_tempo) != 0) {
1989                                         break;
1990                                 }
1991                         }
1992                 } else {
1993                         pos -= llrint (beats * tempo->frames_per_beat (_frame_rate));
1994                         beats = 0;
1995                 }
1996         }
1997
1998         return pos;
1999 }
2000
2001 /** Add the BBT interval op to pos and return the result */
2002 framepos_t
2003 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2004 {
2005         Glib::RWLock::ReaderLock lm (lock);
2006         Metrics::const_iterator i;
2007         const MeterSection* meter;
2008         const MeterSection* m;
2009         const TempoSection* tempo;
2010         const TempoSection* t;
2011         double frames_per_beat;
2012         framepos_t effective_pos = max (pos, (framepos_t) 0);
2013
2014         meter = &first_meter ();
2015         tempo = &first_tempo ();
2016
2017         assert (meter);
2018         assert (tempo);
2019
2020         /* find the starting metrics for tempo & meter */
2021
2022         for (i = metrics.begin(); i != metrics.end(); ++i) {
2023
2024                 if ((*i)->frame() > effective_pos) {
2025                         break;
2026                 }
2027
2028                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2029                         tempo = t;
2030                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2031                         meter = m;
2032                 }
2033         }
2034
2035         /* We now have:
2036
2037            meter -> the Meter for "pos"
2038            tempo -> the Tempo for "pos"
2039            i     -> for first new metric after "pos", possibly metrics.end()
2040         */
2041
2042         /* now comes the complicated part. we have to add one beat a time,
2043            checking for a new metric on every beat.
2044         */
2045
2046         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2047
2048         uint64_t bars = 0;
2049
2050         while (op.bars) {
2051
2052                 bars++;
2053                 op.bars--;
2054
2055                 /* check if we need to use a new metric section: has adding frames moved us
2056                    to or after the start of the next metric section? in which case, use it.
2057                 */
2058
2059                 if (i != metrics.end()) {
2060                         if ((*i)->frame() <= pos) {
2061
2062                                 /* about to change tempo or meter, so add the
2063                                  * number of frames for the bars we've just
2064                                  * traversed before we change the
2065                                  * frames_per_beat value.
2066                                  */
2067                                 
2068                                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2069                                 bars = 0;
2070
2071                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2072                                         tempo = t;
2073                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2074                                         meter = m;
2075                                 }
2076                                 ++i;
2077                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2078
2079                         }
2080                 }
2081
2082         }
2083
2084         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2085
2086         uint64_t beats = 0;
2087
2088         while (op.beats) {
2089
2090                 /* given the current meter, have we gone past the end of the bar ? */
2091
2092                 beats++;
2093                 op.beats--;
2094
2095                 /* check if we need to use a new metric section: has adding frames moved us
2096                    to or after the start of the next metric section? in which case, use it.
2097                 */
2098
2099                 if (i != metrics.end()) {
2100                         if ((*i)->frame() <= pos) {
2101
2102                                 /* about to change tempo or meter, so add the
2103                                  * number of frames for the beats we've just
2104                                  * traversed before we change the
2105                                  * frames_per_beat value.
2106                                  */
2107
2108                                 pos += llrint (beats * frames_per_beat);
2109                                 beats = 0;
2110
2111                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2112                                         tempo = t;
2113                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2114                                         meter = m;
2115                                 }
2116                                 ++i;
2117                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2118                         }
2119                 }
2120         }
2121
2122         pos += llrint (beats * frames_per_beat);
2123
2124         if (op.ticks) {
2125                 if (op.ticks >= BBT_Time::ticks_per_beat) {
2126                         pos += llrint (frames_per_beat + /* extra beat */
2127                                        (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) / 
2128                                                            (double) BBT_Time::ticks_per_beat)));
2129                 } else {
2130                         pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2131                 }
2132         }
2133
2134         return pos;
2135 }
2136
2137 /** Count the number of beats that are equivalent to distance when going forward,
2138     starting at pos.
2139 */
2140 Evoral::MusicalTime
2141 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2142 {
2143         Glib::RWLock::ReaderLock lm (lock);
2144         Metrics::const_iterator next_tempo;
2145         const TempoSection* tempo = 0;
2146         framepos_t effective_pos = max (pos, (framepos_t) 0);
2147
2148         /* Find the relevant initial tempo metric  */
2149
2150         for (next_tempo = metrics.begin(); next_tempo != metrics.end(); ++next_tempo) {
2151
2152                 const TempoSection* t;
2153
2154                 if ((t = dynamic_cast<const TempoSection*>(*next_tempo)) != 0) {
2155
2156                         if ((*next_tempo)->frame() > effective_pos) {
2157                                 break;
2158                         }
2159
2160                         tempo = t;
2161                 }
2162         }
2163
2164         /* We now have:
2165
2166            tempo -> the Tempo for "pos"
2167            next_tempo -> the next tempo after "pos", possibly metrics.end()
2168         */
2169
2170         assert (tempo);
2171
2172         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frame %1 walk by %2 frames, start with tempo = %3 @ %4\n",
2173                                                        pos, distance, *((Tempo*)tempo), tempo->frame()));
2174         
2175         Evoral::MusicalTime beats = 0;
2176
2177         while (distance) {
2178
2179                 /* End of this section */
2180                 framepos_t const end = ((next_tempo == metrics.end()) ? max_framepos : (*next_tempo)->frame ());
2181
2182                 /* Distance to the end in frames */
2183                 framecnt_t const distance_to_end = end - pos;
2184
2185                 /* Amount to subtract this time */
2186                 double const sub = min (distance, distance_to_end);
2187
2188                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("to reach end at %1 (end ? %2), distance= %3 sub=%4\n", end, (next_tempo == metrics.end()),
2189                                                                distance_to_end, sub));
2190
2191                 /* Update */
2192                 pos += sub;
2193                 distance -= sub;
2194                 assert (tempo);
2195                 beats += sub / tempo->frames_per_beat (_frame_rate);
2196
2197                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1, beats = %2 distance left %3\n",
2198                                                                pos, beats, distance));
2199
2200                 /* Move on if there's anything to move to */
2201
2202                 if (next_tempo != metrics.end()) {
2203
2204                         tempo = dynamic_cast<const TempoSection*>(*next_tempo);
2205
2206                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("\tnew tempo = %1 @ %2 fpb = %3\n",
2207                                                                        *((Tempo*)tempo), tempo->frame(),
2208                                                                        tempo->frames_per_beat (_frame_rate)));
2209
2210                         while (next_tempo != metrics.end ()) {
2211
2212                                 ++next_tempo;
2213                                 
2214                                 if (next_tempo != metrics.end() && dynamic_cast<const TempoSection*>(*next_tempo)) {
2215                                         break;
2216                                 }
2217                         }
2218
2219                         if (next_tempo == metrics.end()) {
2220                                 DEBUG_TRACE (DEBUG::TempoMath, "no more tempo sections\n");
2221                         } else {
2222                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("next tempo section is %1 @ %2\n",
2223                                                                                **next_tempo, (*next_tempo)->frame()));
2224                         }
2225
2226                 }
2227                 assert (tempo);
2228         }
2229
2230         return beats;
2231 }
2232
2233 TempoMap::BBTPointList::const_iterator
2234 TempoMap::bbt_before_or_at (framepos_t pos)
2235 {
2236         /* CALLER MUST HOLD READ LOCK */
2237
2238         BBTPointList::const_iterator i;
2239
2240         if (pos < 0) {
2241                 /* not really correct, but we should catch pos < 0 at a higher
2242                    level 
2243                 */
2244                 return _map.begin();
2245         }
2246
2247         i = lower_bound (_map.begin(), _map.end(), pos);
2248         assert (i != _map.end());
2249         if ((*i).frame > pos) {
2250                 assert (i != _map.begin());
2251                 --i;
2252         }
2253         return i;
2254 }
2255
2256 struct bbtcmp {
2257     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2258             return a < b;
2259     }
2260 };
2261
2262 TempoMap::BBTPointList::const_iterator
2263 TempoMap::bbt_before_or_at (const BBT_Time& bbt)
2264 {
2265         BBTPointList::const_iterator i;
2266         bbtcmp cmp;
2267
2268         i = lower_bound (_map.begin(), _map.end(), bbt, cmp);
2269         assert (i != _map.end());
2270         if ((*i).bar > bbt.bars || (*i).beat > bbt.beats) {
2271                 assert (i != _map.begin());
2272                 --i;
2273         }
2274         return i;
2275 }
2276
2277 TempoMap::BBTPointList::const_iterator
2278 TempoMap::bbt_after_or_at (framepos_t pos) 
2279 {
2280         /* CALLER MUST HOLD READ LOCK */
2281
2282         BBTPointList::const_iterator i;
2283
2284         if (_map.back().frame == pos) {
2285                 i = _map.end();
2286                 assert (i != _map.begin());
2287                 --i;
2288                 return i;
2289         }
2290
2291         i = upper_bound (_map.begin(), _map.end(), pos);
2292         assert (i != _map.end());
2293         return i;
2294 }
2295
2296 std::ostream& 
2297 operator<< (std::ostream& o, const Meter& m) {
2298         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2299 }
2300
2301 std::ostream& 
2302 operator<< (std::ostream& o, const Tempo& t) {
2303         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2304 }
2305
2306 std::ostream& 
2307 operator<< (std::ostream& o, const MetricSection& section) {
2308
2309         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2310
2311         const TempoSection* ts;
2312         const MeterSection* ms;
2313
2314         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2315                 o << *((Tempo*) ts);
2316         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2317                 o << *((Meter*) ms);
2318         }
2319
2320         return o;
2321 }