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