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