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