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