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