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