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