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