clean up comments and commented code
[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 = ((double) (start().beats - 1) + (start().ticks/Timecode::BBT_Time::ticks_per_bar_division)) /
160                 (m.divisions_per_bar() - 1);
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 * (_bar_offset * (meter.divisions_per_bar() - 1));
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         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n", 
182                                                        _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
183
184         /* remember the 1-based counting properties of beats */
185         new_start.beats += 1;
186                                             
187         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("tempo updated BBT time to %1 from bar offset %2 w/dpb = %3\n", new_start,  _bar_offset, meter.divisions_per_bar()));
188         
189         set_start (new_start);
190 }
191
192 /***********************************************************************/
193
194 const string MeterSection::xml_state_node_name = "Meter";
195
196 MeterSection::MeterSection (const XMLNode& node)
197         : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
198 {
199         const XMLProperty *prop;
200         BBT_Time start;
201         LocaleGuard lg (X_("POSIX"));
202
203         if ((prop = node.property ("start")) == 0) {
204                 error << _("MeterSection XML node has no \"start\" property") << endmsg;
205                 throw failed_constructor();
206         }
207
208         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
209                     &start.bars,
210                     &start.beats,
211                     &start.ticks) < 3) {
212                 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
213                 throw failed_constructor();
214         }
215
216         set_start (start);
217
218         /* beats-per-bar is old; divisions-per-bar is new */
219
220         if ((prop = node.property ("divisions-per-bar")) == 0) {
221                 if ((prop = node.property ("beats-per-bar")) == 0) {
222                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
223                         throw failed_constructor();
224                 } 
225         }
226
227         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
228                 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
229                 throw failed_constructor();
230         }
231
232         if ((prop = node.property ("note-type")) == 0) {
233                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
234                 throw failed_constructor();
235         }
236
237         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
238                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
239                 throw failed_constructor();
240         }
241
242         if ((prop = node.property ("movable")) == 0) {
243                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
244                 throw failed_constructor();
245         }
246
247         set_movable (string_is_affirmative (prop->value()));
248 }
249
250 XMLNode&
251 MeterSection::get_state() const
252 {
253         XMLNode *root = new XMLNode (xml_state_node_name);
254         char buf[256];
255         LocaleGuard lg (X_("POSIX"));
256
257         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
258                   start().bars,
259                   start().beats,
260                   start().ticks);
261         root->add_property ("start", buf);
262         snprintf (buf, sizeof (buf), "%f", _note_type);
263         root->add_property ("note-type", buf);
264         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
265         root->add_property ("divisions-per-bar", buf);
266         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
267         root->add_property ("movable", buf);
268
269         return *root;
270 }
271
272 /***********************************************************************/
273
274 struct MetricSectionSorter {
275     bool operator() (const MetricSection* a, const MetricSection* b) {
276             return a->start() < b->start();
277     }
278 };
279
280 TempoMap::TempoMap (framecnt_t fr)
281 {
282         metrics = new Metrics;
283         _frame_rate = fr;
284         last_bbt_valid = false;
285         BBT_Time start;
286
287         start.bars = 1;
288         start.beats = 1;
289         start.ticks = 0;
290
291         TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
292         MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
293
294         t->set_movable (false);
295         m->set_movable (false);
296
297         /* note: frame time is correct (zero) for both of these */
298
299         metrics->push_back (t);
300         metrics->push_back (m);
301 }
302
303 TempoMap::~TempoMap ()
304 {
305 }
306
307 void
308 TempoMap::remove_tempo (const TempoSection& tempo, bool send_signal)
309 {
310         bool removed = false;
311
312         {
313                 Glib::RWLock::WriterLock lm (lock);
314                 Metrics::iterator i;
315
316                 for (i = metrics->begin(); i != metrics->end(); ++i) {
317                         if (dynamic_cast<TempoSection*> (*i) != 0) {
318                                 if (tempo.frame() == (*i)->frame()) {
319                                         if ((*i)->movable()) {
320                                                 metrics->erase (i);
321                                                 removed = true;
322                                                 break;
323                                         }
324                                 }
325                         }
326                 }
327         }
328
329         if (removed) {
330                 timestamp_metrics (false);
331                 if (send_signal) {
332                         PropertyChanged (PropertyChange ());
333                 }
334         }
335 }
336
337 void
338 TempoMap::remove_meter (const MeterSection& tempo, bool send_signal)
339 {
340         bool removed = false;
341
342         {
343                 Glib::RWLock::WriterLock lm (lock);
344                 Metrics::iterator i;
345
346                 for (i = metrics->begin(); i != metrics->end(); ++i) {
347                         if (dynamic_cast<MeterSection*> (*i) != 0) {
348                                 if (tempo.frame() == (*i)->frame()) {
349                                         if ((*i)->movable()) {
350                                                 metrics->erase (i);
351                                                 removed = true;
352                                                 break;
353                                         }
354                                 }
355                         }
356                 }
357         }
358
359         if (removed) {
360                 timestamp_metrics (true);
361                 if (send_signal) {
362                         PropertyChanged (PropertyChange ());
363                 }
364         }
365 }
366
367 void
368 TempoMap::do_insert (MetricSection* section)
369 {
370         bool reassign_tempo_bbt = false;
371
372         assert (section->start().ticks == 0);
373
374         /* we only allow new meters to be inserted on beat 1 of an existing
375          * measure. 
376          */
377
378         if (dynamic_cast<MeterSection*>(section)) {
379
380                 /* we need to (potentially) update the BBT times of tempo
381                    sections based on this new meter.
382                 */
383                 
384                 reassign_tempo_bbt = true;
385
386                 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
387                         
388                         BBT_Time corrected = section->start();
389                         corrected.beats = 1;
390                         corrected.ticks = 0;
391                         
392                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
393                                                    section->start(), corrected) << endmsg;
394                         
395                         section->set_start (corrected);
396                 }
397         }
398
399         Metrics::iterator i;
400
401         /* Look for any existing MetricSection that is of the same type and
402            at the same time as the new one, and remove it before adding
403            the new one.
404         */
405
406         Metrics::iterator to_remove = metrics->end ();
407
408         for (i = metrics->begin(); i != metrics->end(); ++i) {
409
410                 int const c = (*i)->compare (*section);
411
412                 if (c < 0) {
413                         /* this section is before the one to be added; go back round */
414                         continue;
415                 } else if (c > 0) {
416                         /* this section is after the one to be added; there can't be any at the same time */
417                         break;
418                 }
419
420                 /* hacky comparison of type */
421                 bool const a = dynamic_cast<TempoSection*> (*i) != 0;
422                 bool const b = dynamic_cast<TempoSection*> (section) != 0;
423
424                 if (a == b) {
425                         to_remove = i;
426                         break;
427                 }
428         }
429
430         if (to_remove != metrics->end()) {
431                 /* remove the MetricSection at the same time as the one we are about to add */
432                 metrics->erase (to_remove);
433         }
434
435         /* Add the given MetricSection */
436
437         for (i = metrics->begin(); i != metrics->end(); ++i) {
438
439                 if ((*i)->compare (*section) < 0) {
440                         continue;
441                 }
442
443                 metrics->insert (i, section);
444                 break;
445         }
446
447         if (i == metrics->end()) {
448                 metrics->insert (metrics->end(), section);
449         }
450         
451         timestamp_metrics (reassign_tempo_bbt);
452 }
453
454 void
455 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where)
456 {
457         const TempoSection& first (first_tempo());
458
459         if (ts != first) {
460                 remove_tempo (ts, false);
461                 add_tempo (tempo, where);
462         } else {
463                 /* cannot move the first tempo section */
464                 *((Tempo*)&first) = tempo;
465                 timestamp_metrics (false);
466         }
467
468         PropertyChanged (PropertyChange ());
469 }
470
471 void
472 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
473 {
474         {
475                 Glib::RWLock::WriterLock lm (lock);
476
477                 /* new tempos always start on a beat */
478                 where.ticks = 0;
479
480                 TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type());
481                 
482                 /* find the meter to use to set the bar offset of this
483                  * tempo section.
484                  */
485
486                 const Meter* meter = &first_meter();
487                 
488                 /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
489                    at something, because we insert the default tempo and meter during
490                    TempoMap construction.
491                    
492                    now see if we can find better candidates.
493                 */
494                 
495                 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
496                         
497                         const MeterSection* m;
498                         
499                         if (where < (*i)->start()) {
500                                 break;
501                         }
502                         
503                         if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
504                                 meter = m;
505                         }
506                 }
507
508                 ts->update_bar_offset_from_bbt (*meter);
509
510                 /* and insert it */
511
512                 do_insert (ts);
513         }
514
515         PropertyChanged (PropertyChange ());
516 }
517
518 void
519 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
520 {
521         const MeterSection& first (first_meter());
522
523         if (ms != first) {
524                 remove_meter (ms, false);
525                 add_meter (meter, where);
526         } else {
527                 /* cannot move the first meter section */
528                 *((Meter*)&first) = meter;
529                 timestamp_metrics (true);
530         }
531
532         PropertyChanged (PropertyChange ());
533 }
534
535 void
536 TempoMap::add_meter (const Meter& meter, BBT_Time where)
537 {
538         {
539                 Glib::RWLock::WriterLock lm (lock);
540
541                 /* a new meter always starts a new bar on the first beat. so
542                    round the start time appropriately. remember that
543                    `where' is based on the existing tempo map, not
544                    the result after we insert the new meter.
545
546                 */
547
548                 if (where.beats != 1) {
549                         where.beats = 1;
550                         where.bars++;
551                 }
552
553                 /* new meters *always* start on a beat. */
554                 where.ticks = 0;
555
556                 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
557         }
558
559 #ifndef NDEBUG
560         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
561                 dump (std::cerr);
562         }
563 #endif
564
565         PropertyChanged (PropertyChange ());
566 }
567
568 void
569 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
570 {
571         Tempo newtempo (beats_per_minute, note_type);
572         TempoSection* t;
573
574         for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
575                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
576                         *((Tempo*) t) = newtempo;
577                         PropertyChanged (PropertyChange ());
578                         break;
579                 }
580         }
581 }
582
583 void
584 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
585 {
586         Tempo newtempo (beats_per_minute, note_type);
587
588         TempoSection* prev;
589         TempoSection* first;
590         Metrics::iterator i;
591
592         /* find the TempoSection immediately preceding "where"
593          */
594
595         for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
596
597                 if ((*i)->frame() > where) {
598                         break;
599                 }
600
601                 TempoSection* t;
602
603                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
604                         if (!first) {
605                                 first = t;
606                         }
607                         prev = t;
608                 }
609         }
610
611         if (!prev) {
612                 if (!first) {
613                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
614                         return;
615                 }
616
617                 prev = first;
618         }
619
620         /* reset */
621
622         *((Tempo*)prev) = newtempo;
623         PropertyChanged (PropertyChange ());
624 }
625
626 const MeterSection&
627 TempoMap::first_meter () const
628 {
629         const MeterSection *m = 0;
630
631         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
632                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
633                         return *m;
634                 }
635         }
636
637         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
638         /*NOTREACHED*/
639         return *m;
640 }
641
642 const TempoSection&
643 TempoMap::first_tempo () const
644 {
645         const TempoSection *t = 0;
646
647         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
648                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
649                         return *t;
650                 }
651         }
652
653         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
654         /*NOTREACHED*/
655         return *t;
656 }
657
658 void
659 TempoMap::timestamp_metrics_from_audio_time ()
660 {
661         Metrics::iterator i;
662         const MeterSection* meter;
663         const TempoSection* tempo;
664         MeterSection *m;
665         TempoSection *t;
666
667         meter = &first_meter ();
668         tempo = &first_tempo ();
669
670         BBT_Time start;
671         BBT_Time end;
672         
673         // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
674
675         bool first = true;
676         MetricSection* prev = 0;
677
678         for (i = metrics->begin(); i != metrics->end(); ++i) {
679
680                 BBT_Time bbt;
681                 TempoMetric metric (*meter, *tempo);
682
683                 if (prev) {
684                         metric.set_start (prev->start());
685                         metric.set_frame (prev->frame());
686                 } else {
687                         // metric will be at frames=0 bbt=1|1|0 by default
688                         // which is correct for our purpose
689                 }
690
691                 bbt_time_with_metric ((*i)->frame(), bbt, metric);
692                         
693                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
694
695                 if (first) {
696                         first = false;
697                 } else {
698
699                         if (bbt.ticks > BBT_Time::ticks_per_bar_division/2) {
700                                 /* round up to next beat */
701                                 bbt.beats += 1;
702                         }
703
704                         bbt.ticks = 0;
705
706                         if (bbt.beats != 1) {
707                                 /* round up to next bar */
708                                 bbt.bars += 1;
709                                 bbt.beats = 1;
710                         }
711                 }
712
713                 // cerr << bbt << endl;
714
715                 (*i)->set_start (bbt);
716                         
717                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
718                         tempo = t;
719                         // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
720                 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
721                         meter = m;
722                         // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
723                 } else {
724                         fatal << _("programming error: unhandled MetricSection type") << endmsg;
725                         /*NOTREACHED*/
726                 }
727
728                 prev = (*i);
729         }
730
731 #ifndef NDEBUG
732         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
733                 dump (cerr);
734         }
735 #endif
736
737 }
738
739 void
740 TempoMap::timestamp_metrics (bool reassign_tempo_bbt)
741 {
742         Metrics::iterator i;
743         const MeterSection* meter;
744         const TempoSection* tempo;
745         MeterSection *m;
746         TempoSection *t;
747
748         DEBUG_TRACE (DEBUG::TempoMath, "###################### TIMESTAMP via BBT ##############\n");
749         
750         framepos_t current = 0;
751         framepos_t section_frames;
752         BBT_Time start;
753         BBT_Time end;
754         
755         if (reassign_tempo_bbt) {
756
757                 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
758
759                 meter = &first_meter ();
760                 tempo = &first_tempo ();
761
762                 for (i = metrics->begin(); i != metrics->end(); ++i) {
763                         
764                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
765
766                                 /* reassign the BBT time of this tempo section
767                                  * based on its bar offset position.
768                                  */
769
770                                 t->update_bbt_time_from_bar_offset (*meter);
771                                 tempo = t;
772
773                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
774                                 meter = m;
775                         } else {
776                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
777                                 /*NOTREACHED*/
778                         }
779                 }
780         }
781
782         meter = &first_meter ();
783         tempo = &first_tempo ();
784
785         for (i = metrics->begin(); i != metrics->end(); ++i) {
786
787                 end = (*i)->start();
788                              
789                 section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
790                 current += section_frames;
791
792                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frames between %1 & %2 = %3 using %4 & %6 puts %7 at %8\n",
793                                                                start, end, section_frames, 
794                                                                *((Meter*) meter), *((Tempo*) tempo),
795                                                                (*i)->start(), current));
796
797                 start = end;
798
799                 (*i)->set_frame (current);
800
801                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
802                         tempo = t;
803                 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
804                         meter = m;
805                 } else {
806                         fatal << _("programming error: unhandled MetricSection type") << endmsg;
807                         /*NOTREACHED*/
808                 }
809
810         }
811
812 #ifndef NDEBUG
813         if (DEBUG_ENABLED(DEBUG::TempoMath)) {
814                 dump (cerr);
815         }
816 #endif
817
818         DEBUG_TRACE (DEBUG::TempoMath, "###############################################\n");
819
820 }
821
822 TempoMetric
823 TempoMap::metric_at (framepos_t frame) const
824 {
825         TempoMetric m (first_meter(), first_tempo());
826         const Meter* meter;
827         const Tempo* tempo;
828
829         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
830            at something, because we insert the default tempo and meter during
831            TempoMap construction.
832
833            now see if we can find better candidates.
834         */
835
836         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
837
838                 // cerr << "Looking at a metric section " << **i << endl;
839
840                 if ((*i)->frame() > frame) {
841                         break;
842                 }
843
844                 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
845                         m.set_tempo (*tempo);
846                 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
847                         m.set_meter (*meter);
848                 }
849
850                 m.set_frame ((*i)->frame ());
851                 m.set_start ((*i)->start ());
852         }
853         
854         // cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << " location " << m.frame() << " = " << m.start() << endl;
855         return m;
856 }
857
858 TempoMetric
859 TempoMap::metric_at (BBT_Time bbt) const
860 {
861         TempoMetric m (first_meter(), first_tempo());
862         const Meter* meter;
863         const Tempo* tempo;
864
865         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
866            at something, because we insert the default tempo and meter during
867            TempoMap construction.
868
869            now see if we can find better candidates.
870         */
871
872         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
873
874                 BBT_Time section_start ((*i)->start());
875
876                 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
877                         break;
878                 }
879
880                 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
881                         m.set_tempo (*tempo);
882                 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
883                         m.set_meter (*meter);
884                 }
885
886                 m.set_frame ((*i)->frame ());
887                 m.set_start (section_start);
888         }
889
890         return m;
891 }
892
893 void
894 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt) const
895 {
896         {
897                 Glib::RWLock::ReaderLock lm (lock);
898                 bbt_time_unlocked (frame, bbt);
899         }
900 }
901
902 void
903 TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt) const
904 {
905         bbt_time_with_metric (frame, bbt, metric_at (frame));
906 }
907
908 void
909 TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetric& metric) const
910 {
911         const double divisions_per_bar = metric.meter().divisions_per_bar();
912         const double frames_per_tick = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_bar_division;
913
914         /* now compute how far beyond the metric we actually are, and add the
915          * relevant number of ticks to the metric's BBT time
916          */
917
918         framecnt_t frame_diff = frame - metric.frame();
919         uint32_t tick_diff = (uint32_t) lrint ((double) frame_diff / frames_per_tick);
920
921         bbt.ticks = metric.start().ticks + tick_diff;
922         uint32_t beat_overflow = bbt.ticks / (uint32_t) BBT_Time::ticks_per_bar_division;
923         bbt.ticks = bbt.ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
924         bbt.beats = metric.start().beats + beat_overflow;
925         /* bbt.beats uses 1-based counting, so adjust to get the right answer */
926         uint32_t bar_overflow = (bbt.beats - 1) / (uint32_t) divisions_per_bar;
927         bbt.bars = metric.start().bars + bar_overflow;
928
929         /* fmod will map bbt.beats as follows:
930
931            Beats      divisions per bar   Normalized beat
932            0          N                   => 0
933            1          N                   => 1
934            2          N                   => 2
935            3          N                   => 3
936            .   
937            .
938            .
939            N-1        N                   => N-1
940            N          N                   => 0
941            N+1        N                   => 1
942            .
943            .
944            .
945            2N-1       N                   => N-1
946            2N         N                   => 0
947    
948            so, the only special cases are 0, N, 2N etc. however bbt.beats is
949            never zero, so the only actual special cases are N, 2N and so on,
950            allowing us to use a special case check for fmod () == 0 and
951            changing the value to divisions per bar
952         */
953
954         bbt.beats = (uint32_t) fmod (bbt.beats, divisions_per_bar);
955
956         if (bbt.beats == 0) {
957                 bbt.beats = divisions_per_bar;
958         }
959 }
960
961 framecnt_t
962 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
963 {
964         TempoMetric bm = metric_at (start);
965         TempoMetric em = metric_at (end);
966
967         return count_frames_with_metrics (bm, em, start, end);
968 }
969
970 framecnt_t
971 TempoMap::count_frames_with_metrics (const TempoMetric& bm, const TempoMetric& em, const BBT_Time& start, const BBT_Time& end) const
972 {
973         framecnt_t frames = 0;
974         framepos_t start_frame = 0;
975         framepos_t end_frame = 0;
976
977         uint32_t bar_offset = start.bars - bm.start().bars;
978
979         double  beat_offset = bar_offset*bm.meter().divisions_per_bar() - (bm.start().beats-1) + (start.beats -1)
980                 + start.ticks/BBT_Time::ticks_per_bar_division;
981
982         start_frame = bm.frame() + (framepos_t) rint(beat_offset * bm.meter().frames_per_division(bm.tempo(),_frame_rate));
983
984 #if 0
985         cerr << "from start " << start << " compute frame = " << start_frame 
986          <<  " from metric at " << bm.frame() << " tempo = " << bm.tempo().beats_per_minute () << " meter " 
987          << bm.meter().divisions_per_bar() << '/' << bm.meter().note_divisor() 
988          << endl;
989 #endif
990
991         bar_offset = end.bars - em.start().bars;
992
993         beat_offset = bar_offset * em.meter().divisions_per_bar() - (em.start().beats -1) + (end.beats - 1)
994                 + end.ticks/BBT_Time::ticks_per_bar_division;
995
996         end_frame = em.frame() + (framepos_t) rint(beat_offset * em.meter().frames_per_division(em.tempo(),_frame_rate));
997
998 #if 0
999          cerr << "from end " << end << " compute frame = " << end_frame 
1000          <<  " from metric at " << em.frame() << " tempo = " << em.tempo().beats_per_minute () << " meter " 
1001          << em.meter().divisions_per_bar() << '/' << em.meter().note_divisor() 
1002          << endl;
1003 #endif
1004
1005         frames = end_frame - start_frame;
1006
1007         return frames;
1008 }
1009
1010 framecnt_t
1011 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
1012 {
1013         /* this is used in timestamping the metrics by actually counting the
1014          * beats between two metrics ONLY. this means that we know we have a
1015          * fixed divisions_per_bar and frames_per_division for the entire
1016          * computation. 
1017          */
1018
1019         framecnt_t frames = 0;
1020         uint32_t bar = start.bars;
1021         double beat = (double) start.beats;
1022         double divisions_counted = 0;
1023         double divisions_per_bar = 0;
1024         double division_frames = 0;
1025         double max_divs;
1026         int32_t ticks = 0;
1027
1028         divisions_per_bar = meter.divisions_per_bar();
1029         max_divs = ceil (divisions_per_bar);
1030         division_frames = meter.frames_per_division (tempo, _frame_rate);
1031
1032         if (start.ticks > 0) {
1033                 ticks = -start.ticks;
1034                 
1035         }
1036
1037         frames = 0;
1038
1039         while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
1040
1041                 ++beat;
1042                 ++divisions_counted;
1043                 
1044                 if (beat > max_divs) {
1045
1046                         if (beat > divisions_per_bar) {
1047                                 
1048                                 /* this is a fractional beat at the end of a fractional bar
1049                                    so it should only count for the fraction
1050                                 */
1051                                 
1052                                 divisions_counted -= (max_divs - divisions_per_bar);
1053                         }
1054
1055                         ++bar;
1056                         beat = 1;
1057                 }
1058         }
1059
1060         ticks += end.ticks;
1061
1062 #if 0   
1063         cerr << "for " << start.ticks << " and " << end.ticks << " adjust divs by " << ticks << " = " 
1064              << (ticks/BBT_Time::ticks_per_bar_division) << " divs => " 
1065              << ((ticks/BBT_Time::ticks_per_bar_division) * division_frames)
1066              << " (fpd = " << division_frames << ')'
1067              << endl;
1068 #endif
1069
1070         frames = (framecnt_t) llrint (floor ((divisions_counted + (ticks/BBT_Time::ticks_per_bar_division)) * division_frames));
1071
1072 #if 0
1073         cerr << "Counted " << divisions_counted << " + " << ticks << " from " << start << " to " << end
1074              << " dpb were " << divisions_per_bar
1075              << " fpd was " << division_frames
1076              << " => " 
1077              << frames 
1078              << endl;
1079 #endif
1080
1081         return frames;
1082
1083 }
1084
1085 framepos_t
1086 TempoMap::frame_time (const BBT_Time& bbt) const
1087 {
1088         BBT_Time start ; /* 1|1|0 */
1089
1090         return count_frames_between (start, bbt);
1091 }
1092
1093 framecnt_t
1094 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1095 {
1096         framecnt_t frames = 0;
1097
1098         BBT_Time when;
1099         bbt_time(pos, when);
1100
1101         {
1102                 Glib::RWLock::ReaderLock lm (lock);
1103                 frames = bbt_duration_at_unlocked (when, bbt,dir);
1104         }
1105
1106         return frames;
1107 }
1108
1109 framecnt_t
1110 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1111 {
1112         framecnt_t frames = 0;
1113
1114         double divisions_per_bar;
1115         BBT_Time result;
1116
1117         result.bars = max(1U, when.bars + dir * bbt.bars) ;
1118         result.beats = 1;
1119         result.ticks = 0;
1120
1121         TempoMetric     metric = metric_at(result);
1122         divisions_per_bar = metric.meter().divisions_per_bar();
1123
1124         /* Reduce things to legal bbt values we have to handle possible
1125           fractional=shorter beats at the end of measures and things like 0|11|9000
1126           as a duration in a 4.5/4 measure the musical decision is that the
1127           fractional beat is also a beat , although a shorter one
1128         */
1129
1130         if (dir >= 0) {
1131                 result.beats = when.beats +  bbt.beats;
1132                 result.ticks = when.ticks +  bbt.ticks;
1133
1134                 while (result.beats >= (divisions_per_bar + 1)) {
1135                         result.bars++;
1136                         result.beats -=  (uint32_t) ceil(divisions_per_bar);
1137                         metric = metric_at(result); // maybe there is a meter change
1138                         divisions_per_bar = metric.meter().divisions_per_bar();
1139
1140                 }
1141
1142                 /* We now counted the beats and landed in the target measure, now deal
1143                   with ticks this seems complicated, but we want to deal with the
1144                   corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1145                   with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1146                   ticks
1147                 */
1148
1149                 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1150                  */
1151
1152                 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1153                                         (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_bar_division
1154                                            : BBT_Time::ticks_per_bar_division );
1155
1156                 while (result.ticks >= ticks_at_beat) {
1157                         result.beats++;
1158                         result.ticks -= ticks_at_beat;
1159                         if  (result.beats >= (divisions_per_bar + 1)) {
1160                                 result.bars++;
1161                                 result.beats = 1;
1162                                 metric = metric_at(result); // maybe there is a meter change
1163                                 divisions_per_bar = metric.meter().divisions_per_bar();
1164                         }
1165                         ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1166                                        (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_bar_division
1167                                        : BBT_Time::ticks_per_bar_division);
1168                 }
1169
1170
1171         } else {
1172                 uint32_t b = bbt.beats;
1173
1174                 /* count beats */
1175                 while (b > when.beats) {
1176                         --result.bars;
1177                         result.bars = max(1U, result.bars);
1178                         metric = metric_at(result); // maybe there is a meter change
1179                         divisions_per_bar = metric.meter().divisions_per_bar();
1180                         if (b >= ceil(divisions_per_bar)) {
1181                                 b -= (uint32_t) ceil(divisions_per_bar);
1182                         } else {
1183                                 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1184                         }
1185                 }
1186                 result.beats = when.beats - b;
1187
1188                 /* count ticks */
1189
1190                 if (bbt.ticks <= when.ticks) {
1191                         result.ticks = when.ticks - bbt.ticks;
1192                 } else {
1193
1194                         uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_bar_division;
1195                         uint32_t t = bbt.ticks - when.ticks;
1196
1197                         do {
1198
1199                                 if (result.beats == 1) {
1200                                         --result.bars;
1201                                         result.bars = max(1U, result.bars) ;
1202                                         metric = metric_at(result); // maybe there is a meter change
1203                                         divisions_per_bar = metric.meter().divisions_per_bar();
1204                                         result.beats = (uint32_t) ceil(divisions_per_bar);
1205                                         ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_bar_division) ;
1206                                 } else {
1207                                         --result.beats;
1208                                         ticks_at_beat = (uint32_t) BBT_Time::ticks_per_bar_division;
1209                                 }
1210
1211                                 if (t <= ticks_at_beat) {
1212                                         result.ticks = ticks_at_beat - t;
1213                                 } else {
1214                                         t-= ticks_at_beat;
1215                                 }
1216                         } while (t > ticks_at_beat);
1217
1218                 }
1219
1220
1221         }
1222
1223         if (dir < 0) {
1224                 frames = count_frames_between(result, when);
1225         } else {
1226                 frames = count_frames_between(when,result);
1227         }
1228
1229         return frames;
1230 }
1231
1232
1233
1234 framepos_t
1235 TempoMap::round_to_bar (framepos_t fr, int dir)
1236 {
1237         {
1238                 Glib::RWLock::ReaderLock lm (lock);
1239                 return round_to_type (fr, dir, Bar);
1240         }
1241 }
1242
1243
1244 framepos_t
1245 TempoMap::round_to_beat (framepos_t fr, int dir)
1246 {
1247         {
1248                 Glib::RWLock::ReaderLock lm (lock);
1249                 return round_to_type (fr, dir, Beat);
1250         }
1251 }
1252
1253 framepos_t
1254 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1255 {
1256         BBT_Time the_beat;
1257         uint32_t ticks_one_half_subdivisions_worth;
1258         uint32_t ticks_one_subdivisions_worth;
1259         uint32_t difference;
1260
1261         bbt_time(fr, the_beat);
1262
1263         ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_bar_division / sub_num;
1264         ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1265
1266         if (dir > 0) {
1267
1268                 /* round to next */
1269
1270                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1271
1272                 if (mod == 0) {
1273                         /* right on the subdivision, so the difference is just the subdivision ticks */
1274                         difference = ticks_one_subdivisions_worth;
1275
1276                 } else {
1277                         /* not on subdivision, compute distance to next subdivision */
1278
1279                         difference = ticks_one_subdivisions_worth - mod;
1280                 }
1281
1282                 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1283
1284         } else if (dir < 0) {
1285
1286                 /* round to previous */
1287
1288                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1289
1290                 if (mod == 0) {
1291                         /* right on the subdivision, so the difference is just the subdivision ticks */
1292                         difference = ticks_one_subdivisions_worth;
1293                 } else {
1294                         /* not on subdivision, compute distance to previous subdivision, which
1295                            is just the modulus.
1296                         */
1297
1298                         difference = mod;
1299                 }
1300
1301                 try {
1302                         the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1303                 } catch (...) {
1304                         /* can't go backwards from wherever pos is, so just return it */
1305                         return fr;
1306                 }
1307
1308         } else {
1309                 /* round to nearest */
1310
1311                 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1312                         difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1313                         the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1314                 } else {
1315                         // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1316                         the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1317                 }
1318         }
1319
1320         return frame_time (the_beat);
1321 }
1322
1323 framepos_t
1324 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1325 {
1326         TempoMetric metric = metric_at (frame);
1327         BBT_Time bbt;
1328         BBT_Time start;
1329         BBT_Time one_bar (1,0,0);
1330         BBT_Time one_beat (0,1,0);
1331
1332         bbt_time_with_metric (frame, bbt, metric);
1333
1334         switch (type) {
1335         case Bar:
1336                 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1337
1338                 if (dir < 0) {
1339
1340                         /* find bar position preceding frame */
1341
1342                         try {
1343                                 bbt = bbt_subtract (bbt, one_bar);
1344                         }
1345
1346                         catch (...) {
1347                                 return frame;
1348                         }
1349
1350
1351                 } else if (dir > 0) {
1352
1353                         /* find bar position following frame */
1354
1355                         try {
1356                                 bbt = bbt_add (bbt, one_bar, metric);
1357                         }
1358                         catch (...) {
1359                                 return frame;
1360                         }
1361
1362                 } else {
1363
1364                         /* "true" rounding */
1365
1366                         float midbar_beats;
1367                         float midbar_ticks;
1368
1369                         midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1370                         midbar_ticks = BBT_Time::ticks_per_bar_division * fmod (midbar_beats, 1.0f);
1371                         midbar_beats = floor (midbar_beats);
1372
1373                         BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1374
1375                         if (bbt < midbar) {
1376                                 /* round down */
1377                                 bbt.beats = 1;
1378                                 bbt.ticks = 0;
1379                         } else {
1380                                 /* round up */
1381                                 bbt.bars++;
1382                                 bbt.beats = 1;
1383                                 bbt.ticks = 0;
1384                         }
1385                 }
1386                 /* force beats & ticks to their values at the start of a bar */
1387                 bbt.beats = 1;
1388                 bbt.ticks = 0;
1389                 break;
1390
1391         case Beat:
1392                 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1393
1394                 if (dir < 0) {
1395
1396                         /* find beat position preceding frame */
1397
1398                         try {
1399                                 bbt = bbt_subtract (bbt, one_beat);
1400                         }
1401
1402                         catch (...) {
1403                                 return frame;
1404                         }
1405
1406
1407                 } else if (dir > 0) {
1408
1409                         /* find beat position following frame */
1410
1411                         try {
1412                                 bbt = bbt_add (bbt, one_beat, metric);
1413                         }
1414                         catch (...) {
1415                                 return frame;
1416                         }
1417
1418                 } else {
1419
1420                         /* "true" rounding */
1421
1422                         /* round to nearest beat */
1423                         if (bbt.ticks >= (BBT_Time::ticks_per_bar_division/2)) {
1424
1425                                 try {
1426                                         bbt = bbt_add (bbt, one_beat, metric);
1427                                 }
1428                                 catch (...) {
1429                                         return frame;
1430                                 }
1431                         }
1432                 }
1433                 /* force ticks to the value at the start of a beat */
1434                 bbt.ticks = 0;
1435                 break;
1436
1437         }
1438
1439         DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("\tat %1 count frames from %2 to %3 = %4\n", metric.frame(), metric.start(), bbt, count_frames_between (metric.start(), bbt)));
1440         return metric.frame() + count_frames_between (metric.start(), bbt);
1441 }
1442
1443 TempoMap::BBTPointList *
1444 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1445 {
1446         Metrics::const_iterator next_metric;
1447         BBTPointList *points;
1448         double current;
1449         const MeterSection* meter;
1450         const MeterSection* m;
1451         const TempoSection* tempo;
1452         const TempoSection* t;
1453         uint32_t bar;
1454         uint32_t beat;
1455         double divisions_per_bar;
1456         double beat_frame;
1457         double beat_frames;
1458         double frames_per_bar;
1459         double delta_bars;
1460         double delta_beats;
1461         double dummy;
1462         framepos_t limit;
1463
1464         meter = &first_meter ();
1465         tempo = &first_tempo ();
1466
1467         /* find the starting point */
1468
1469         for (next_metric = metrics->begin(); next_metric != metrics->end(); ++next_metric) {
1470
1471                 if ((*next_metric)->frame() > lower) {
1472                         break;
1473                 }
1474
1475                 if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1476                         tempo = t;
1477                 } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1478                         meter = m;
1479                 }
1480         }
1481
1482         /* We now have:
1483
1484            meter -> the Meter for "lower"
1485            tempo -> the Tempo for "lower"
1486            i     -> for first new metric after "lower", possibly metrics->end()
1487
1488            Now start generating points.
1489         */
1490
1491         divisions_per_bar = meter->divisions_per_bar ();
1492         frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1493         beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1494         
1495         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Start with beat frames = %1 bar = %2\n", beat_frames, frames_per_bar));
1496
1497         if (meter->frame() > tempo->frame()) {
1498                 bar = meter->start().bars;
1499                 beat = meter->start().beats;
1500                 current = meter->frame();
1501         } else {
1502                 bar = tempo->start().bars;
1503                 beat = tempo->start().beats;
1504                 current = tempo->frame();
1505         }
1506
1507         /* initialize current to point to the bar/beat just prior to the
1508            lower frame bound passed in.  assumes that current is initialized
1509            above to be on a beat.
1510         */
1511
1512         delta_bars = (lower-current) / frames_per_bar;
1513         delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1514         current += (floor(delta_bars) * frames_per_bar) +  (floor(delta_beats) * beat_frames);
1515
1516         // adjust bars and beats too
1517         bar += (uint32_t) (floor(delta_bars));
1518         beat += (uint32_t) (floor(delta_beats));
1519
1520         points = new BBTPointList;
1521
1522         do {
1523
1524                 /* we're going to add bar or beat points until we hit the
1525                      earlier of:
1526                      
1527                     (1) the end point of this request
1528                     (2) the next metric section
1529                 */
1530                 
1531                 if (next_metric == metrics->end()) {
1532                         limit = upper;
1533                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to end of request @ %1\n", limit));
1534                 } else {
1535                         limit = (*next_metric)->frame();
1536                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to next metric section @ %1\n", limit));
1537                 }
1538
1539                 limit = min (limit, upper);
1540
1541                 bool reset_current_to_metric_section = true;
1542                 bool bar_adjusted = false;
1543                 TempoSection* ts;
1544
1545                 while (current < limit) {
1546
1547                         /* if we're at the start of a bar, add bar point */
1548
1549                         if (beat == 1) {
1550                                 if (current >= lower) {
1551                                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", bar, current));
1552                                         points->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current), Bar, bar, 1));
1553
1554                                 }
1555                         }
1556
1557                         /* add some beats if we can */
1558
1559                         beat_frame = current;
1560
1561                         const uint32_t max_divs = ceil (divisions_per_bar);
1562
1563                         while (beat <= max_divs && beat_frame < limit) {
1564
1565                                 if (beat_frame >= lower) {
1566                                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", bar, beat, beat_frame));
1567                                         points->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(beat_frame), Beat, bar, beat));
1568                                 }
1569
1570                                 beat_frame += beat_frames;
1571                                 current = beat_frame;
1572                                 beat++;
1573                         }
1574
1575                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("break in beats addition @ end ? %1 out of bpb ? %2 beat frame @ %3 vs %4 beat @ %5 vs %6\n",
1576                                                                        (next_metric == metrics->end()), (beat > max_divs), beat_frame, limit, beat, max_divs));
1577
1578                         if (beat <= max_divs) {
1579
1580                                 /* we didn't reach the end of the bar. 
1581
1582                                    this could be be because we hit "upper"
1583                                    or a new metric section.
1584
1585                                 */
1586                                 
1587                                 if (next_metric != metrics->end() && limit == (*next_metric)->frame()) {
1588
1589                                         /* we bumped into a new metric
1590                                          * section. meter sections are always
1591                                          * at bar boundaries, but tempo
1592                                          * sections can begin anywhere and need
1593                                          * special handling if they are not on
1594                                          * a beat boundary.
1595                                          */
1596
1597                                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stopped at metric at %1 @ 2\n", (*next_metric)->start(), (*next_metric)->frame()));
1598
1599                                         if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0) && ts->start().ticks != 0) {
1600                                 
1601                                                 /* compute current at the *next* beat,
1602                                                    using the tempo section we just
1603                                                    bumped into.
1604                                                 */
1605                                                 
1606                                                 /* recompute how many frames per
1607                                                  * division using the tempo we've just
1608                                                  * found
1609                                                  */
1610                                                 
1611                                                 double next_beat_frames = meter->frames_per_division (*ts,_frame_rate);                                 
1612                                                 
1613                                                 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
1614                                                                                                (*next_metric)->start(), (*next_metric)->frame(), ts->bar_offset()));
1615                                                 
1616                                                 current -= beat_frames;
1617                                                 current += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
1618
1619                                                 /* avoid resetting current to position
1620                                                    of the next metric section as we
1621                                                    iterate through "metrics"
1622                                                    further on below.
1623                                                 */
1624                                                 
1625                                                 reset_current_to_metric_section = false;
1626                                                 
1627                                         } else if (dynamic_cast<MeterSection*> (*next_metric)) {
1628                                                 
1629                                                 /* we hit a new meter
1630                                                  * section. nothing to do - the
1631                                                  * right thing will happen as
1632                                                  * we move to the next metric
1633                                                  * section down below.
1634                                                  */
1635
1636                                         } else {
1637                                                 
1638                                                 /* we hit a tempo mark that is
1639                                                  * precisely on beat. nothing
1640                                                  * to do here  - the
1641                                                  * right thing will happen as
1642                                                  * we move to the next metric
1643                                                  * section down below.
1644                                                  */
1645                                         }
1646
1647                                 } else {
1648
1649                                         /* we hit either:
1650                                            
1651                                            - the end of the requested range 
1652                                            
1653                                            we'll exit from the outer loop soon.
1654                                         */
1655                                 }
1656
1657                         } else if ((beat > max_divs) || (next_metric != metrics->end() && dynamic_cast<MeterSection*>(*next_metric))) {
1658                                         
1659                                 /* we've arrived at either the end of a bar or
1660                                    a new **meter** marker (not tempo marker).
1661
1662                                    its important to move `current' forward by
1663                                    the actual frames_per_bar, not move it to an
1664                                    integral beat_frame, so that metrics with
1665                                    non-integral beats-per-bar have their bar
1666                                    positions set correctly. consider a metric
1667                                    with 9-1/2 beats-per-bar. the bar we just
1668                                    filled had 10 beat marks, but the bar end is
1669                                    1/2 beat before the last beat mark.  And it
1670                                    is also possible that a tempo change occured
1671                                    in the middle of a bar, so we subtract the
1672                                    possible extra fraction from the current
1673                                 */
1674
1675                                 if (beat > max_divs) {
1676                                         /* next bar goes where the numbers suggest */
1677                                         current -= beat_frames * (max_divs - divisions_per_bar);
1678                                         DEBUG_TRACE (DEBUG::TempoMath, "++ next bar from numbers\n");
1679                                 } else {
1680                                         /* next bar goes where the next meter metric is */
1681                                         current = limit;
1682                                         DEBUG_TRACE (DEBUG::TempoMath, "++ next bar at next metric\n");
1683                                 }
1684
1685                                 bar++;
1686                                 beat = 1;
1687                                 bar_adjusted = true;
1688                         }
1689                 }
1690
1691                 /* if we're done, then we're done */
1692
1693                 if (current >= upper) {
1694                         break;
1695                 }
1696
1697                 /* i is an iterator that refers to the next metric (or none).
1698                    if there is a next metric, move to it, and continue.
1699                 */
1700
1701                 if (next_metric != metrics->end()) {
1702
1703                         if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1704                                 tempo = t;
1705                         } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1706                                 meter = m;
1707
1708                                 if (!bar_adjusted) {
1709                                         /* new MeterSection, beat always returns to 1 */
1710                                         beat = 1;
1711                                 }
1712                         }
1713                         
1714                         if (reset_current_to_metric_section) {
1715                                 current = (*next_metric)->frame ();
1716                         }
1717
1718                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("loop around with current @ %1\n", current));
1719                         
1720                         divisions_per_bar = meter->divisions_per_bar ();
1721                         frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1722                         beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1723
1724                         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 bar = %2 dpb %3 meter %4 tempo %5\n", 
1725                                                                        beat_frames, frames_per_bar, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
1726                         
1727                         ++next_metric;
1728                 }
1729
1730         } while (1);
1731
1732         return points;
1733 }
1734
1735 const TempoSection&
1736 TempoMap::tempo_section_at (framepos_t frame) const
1737 {
1738         Glib::RWLock::ReaderLock lm (lock);
1739         Metrics::const_iterator i;
1740         TempoSection* prev = 0;
1741
1742         for (i = metrics->begin(); i != metrics->end(); ++i) {
1743                 TempoSection* t;
1744
1745                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1746
1747                         if ((*i)->frame() > frame) {
1748                                 break;
1749                         }
1750
1751                         prev = t;
1752                 }
1753         }
1754
1755         if (prev == 0) {
1756                 fatal << endmsg;
1757         }
1758
1759         return *prev;
1760 }
1761
1762 const Tempo&
1763 TempoMap::tempo_at (framepos_t frame) const
1764 {
1765         TempoMetric m (metric_at (frame));
1766         return m.tempo();
1767 }
1768
1769
1770 const Meter&
1771 TempoMap::meter_at (framepos_t frame) const
1772 {
1773         TempoMetric m (metric_at (frame));
1774         return m.meter();
1775 }
1776
1777 XMLNode&
1778 TempoMap::get_state ()
1779 {
1780         Metrics::const_iterator i;
1781         XMLNode *root = new XMLNode ("TempoMap");
1782
1783         {
1784                 Glib::RWLock::ReaderLock lm (lock);
1785                 for (i = metrics->begin(); i != metrics->end(); ++i) {
1786                         root->add_child_nocopy ((*i)->get_state());
1787                 }
1788         }
1789
1790         return *root;
1791 }
1792
1793 int
1794 TempoMap::set_state (const XMLNode& node, int /*version*/)
1795 {
1796         {
1797                 Glib::RWLock::WriterLock lm (lock);
1798
1799                 XMLNodeList nlist;
1800                 XMLNodeConstIterator niter;
1801                 Metrics old_metrics (*metrics);
1802                 MeterSection* last_meter = 0;
1803
1804                 metrics->clear();
1805
1806                 nlist = node.children();
1807                 
1808                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1809                         XMLNode* child = *niter;
1810
1811                         if (child->name() == TempoSection::xml_state_node_name) {
1812
1813                                 try {
1814                                         TempoSection* ts = new TempoSection (*child);
1815                                         metrics->push_back (ts);
1816
1817                                         if (ts->bar_offset() < 0.0) {
1818                                                 if (last_meter) {
1819                                                         ts->update_bar_offset_from_bbt (*last_meter);
1820                                                 } 
1821                                         }
1822                                 }
1823
1824                                 catch (failed_constructor& err){
1825                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1826                                         *metrics = old_metrics;
1827                                         break;
1828                                 }
1829
1830                         } else if (child->name() == MeterSection::xml_state_node_name) {
1831
1832                                 try {
1833                                         MeterSection* ms = new MeterSection (*child);
1834                                         metrics->push_back (ms);
1835                                         last_meter = ms;
1836                                 }
1837
1838                                 catch (failed_constructor& err) {
1839                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1840                                         *metrics = old_metrics;
1841                                         break;
1842                                 }
1843                         }
1844                 }
1845
1846                 if (niter == nlist.end()) {
1847
1848                         MetricSectionSorter cmp;
1849                         metrics->sort (cmp);
1850                         timestamp_metrics (true);
1851                 }
1852         }
1853
1854         PropertyChanged (PropertyChange ());
1855
1856         return 0;
1857 }
1858
1859 void
1860 TempoMap::dump (std::ostream& o) const
1861 {
1862         const MeterSection* m;
1863         const TempoSection* t;
1864
1865         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1866
1867                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1868                         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? "
1869                           << t->movable() << ')' << endl;
1870                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1871                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1872                           << " (movable? " << m->movable() << ')' << endl;
1873                 }
1874         }
1875 }
1876
1877 int
1878 TempoMap::n_tempos() const
1879 {
1880         Glib::RWLock::ReaderLock lm (lock);
1881         int cnt = 0;
1882
1883         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1884                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1885                         cnt++;
1886                 }
1887         }
1888
1889         return cnt;
1890 }
1891
1892 int
1893 TempoMap::n_meters() const
1894 {
1895         Glib::RWLock::ReaderLock lm (lock);
1896         int cnt = 0;
1897
1898         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1899                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1900                         cnt++;
1901                 }
1902         }
1903
1904         return cnt;
1905 }
1906
1907 void
1908 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1909 {
1910         for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1911                 if ((*i)->frame() >= where && (*i)->movable ()) {
1912                         (*i)->set_frame ((*i)->frame() + amount);
1913                 }
1914         }
1915
1916         timestamp_metrics_from_audio_time ();
1917
1918         PropertyChanged (PropertyChange ());
1919 }
1920
1921 BBT_Time
1922 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1923 {
1924         TempoMetric metric =  metric_at (start);
1925         return bbt_add (start, other, metric);
1926 }
1927
1928 /**
1929  * add the BBT interval @param increment to  @param start and return the result
1930  */
1931 BBT_Time
1932 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1933 {
1934         BBT_Time result = start;
1935         BBT_Time op = increment; /* argument is const, but we need to modify it */
1936         uint32_t ticks = result.ticks + op.ticks;
1937
1938         if (ticks >= BBT_Time::ticks_per_bar_division) {
1939                 op.beats++;
1940                 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
1941         } else {
1942                 result.ticks += op.ticks;
1943         }
1944
1945         /* now comes the complicated part. we have to add one beat a time,
1946            checking for a new metric on every beat.
1947         */
1948
1949         /* grab all meter sections */
1950
1951         list<const MeterSection*> meter_sections;
1952
1953         for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1954                 const MeterSection* ms;
1955                 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1956                         meter_sections.push_back (ms);
1957                 }
1958         }
1959
1960         assert (!meter_sections.empty());
1961
1962         list<const MeterSection*>::const_iterator next_meter;
1963         const Meter* meter = 0;
1964
1965         /* go forwards through the meter sections till we get to the one
1966            covering the current value of result. this positions i to point to
1967            the next meter section too, or the end.
1968         */
1969
1970         for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1971
1972                 if (result < (*next_meter)->start()) {
1973                         /* this metric is past the result time. stop looking, we have what we need */
1974                         break;
1975                 }
1976
1977                 if (result == (*next_meter)->start()) {
1978                         /* this meter section starts at result, push i beyond it so that it points
1979                            to the NEXT section, opwise we will get stuck later, and use this meter section.
1980                         */
1981                         meter = *next_meter;
1982                         ++next_meter;
1983                         break;
1984                 }
1985
1986                 meter = *next_meter;
1987         }
1988
1989         assert (meter != 0);
1990
1991         /* OK, now have the meter for the bar start we are on, and i is an iterator
1992            that points to the metric after the one we are currently dealing with
1993            (or to metrics->end(), of course)
1994         */
1995
1996         while (op.beats) {
1997
1998                 /* given the current meter, have we gone past the end of the bar ? */
1999
2000                 if (result.beats >= meter->divisions_per_bar()) {
2001                         /* move to next bar, first beat */
2002                         result.bars++;
2003                         result.beats = 1;
2004                 } else {
2005                         result.beats++;
2006                 }
2007
2008                 /* one down ... */
2009
2010                 op.beats--;
2011
2012                 /* check if we need to use a new meter section: has adding beats to result taken us
2013                    to or after the start of the next meter section? in which case, use it.
2014                 */
2015
2016                 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
2017                         meter = *next_meter;
2018                         ++next_meter;
2019                 }
2020         }
2021
2022         /* finally, add bars */
2023
2024         result.bars += op.bars++;
2025
2026         return result;
2027 }
2028
2029 /**
2030  * subtract the BBT interval @param decrement from @param start and return the result
2031  */
2032 BBT_Time
2033 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
2034 {
2035         BBT_Time result = start;
2036         BBT_Time op = decrement; /* argument is const, but we need to modify it */
2037
2038         if (op.ticks > result.ticks) {
2039                 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
2040                 op.beats++;
2041                 result.ticks = BBT_Time::ticks_per_bar_division - (op.ticks - result.ticks);
2042         } else {
2043                 result.ticks -= op.ticks;
2044         }
2045
2046         /* now comes the complicated part. we have to subtract one beat a time,
2047            checking for a new metric on every beat.
2048         */
2049
2050         /* grab all meter sections */
2051
2052         list<const MeterSection*> meter_sections;
2053
2054         for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
2055                 const MeterSection* ms;
2056                 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
2057                         meter_sections.push_back (ms);
2058                 }
2059                 }
2060
2061         assert (!meter_sections.empty());
2062
2063         /* go backwards through the meter sections till we get to the one
2064            covering the current value of result. this positions i to point to
2065            the next (previous) meter section too, or the end.
2066         */
2067
2068         const MeterSection* meter = 0;
2069         list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
2070                                                                 // support const_reverse_iterator::operator!=()
2071
2072         for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
2073
2074                 /* when we find the first meter section that is before or at result, use it,
2075                    and set next_meter to the previous one
2076                 */
2077
2078                 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
2079                         meter = *next_meter;
2080                         ++next_meter;
2081                         break;
2082                 }
2083         }
2084
2085         assert (meter != 0);
2086
2087         /* OK, now have the meter for the bar start we are on, and i is an iterator
2088            that points to the metric after the one we are currently dealing with
2089            (or to metrics->end(), of course)
2090         */
2091
2092         while (op.beats) {
2093
2094                 /* have we reached the start of the bar? if so, move to the last beat of the previous
2095                    bar. opwise, just step back 1 beat.
2096                 */
2097
2098                 if (result.beats == 1) {
2099
2100                         /* move to previous bar, last beat */
2101
2102                         if (result.bars <= 1) {
2103                                 /* i'm sorry dave, i can't do that */
2104                                 throw std::out_of_range ("illegal BBT subtraction");
2105                         }
2106
2107                         result.bars--;
2108                         result.beats = meter->divisions_per_bar();
2109                 } else {
2110
2111                         /* back one beat */
2112
2113                         result.beats--;
2114                 }
2115
2116                 /* one down ... */
2117                 op.beats--;
2118
2119                 /* check if we need to use a new meter section: has subtracting beats to result taken us
2120                    to before the start of the current meter section? in which case, use the prior one.
2121                 */
2122
2123                 if (result < meter->start() && next_meter != meter_sections.rend()) {
2124                         meter = *next_meter;
2125                         ++next_meter;
2126                 }
2127         }
2128
2129         /* finally, subtract bars */
2130
2131         if (op.bars >= result.bars) {
2132                 /* i'm sorry dave, i can't do that */
2133                 throw std::out_of_range ("illegal BBT subtraction");
2134         }
2135
2136         result.bars -= op.bars;
2137         return result;
2138 }
2139
2140 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2141  *  pos can be -ve, if required.
2142  */
2143 framepos_t
2144 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2145 {
2146         Metrics::const_iterator i;
2147         const TempoSection* tempo;
2148
2149         /* Find the starting tempo */
2150
2151         for (i = metrics->begin(); i != metrics->end(); ++i) {
2152
2153                 /* This is a bit of a hack, but pos could be -ve, and if it is,
2154                    we consider the initial metric changes (at time 0) to actually
2155                    be in effect at pos.
2156                 */
2157                 framepos_t f = (*i)->frame ();
2158                 if (pos < 0 && f == 0) {
2159                         f = pos;
2160                 }
2161
2162                 if (f > pos) {
2163                         break;
2164                 }
2165
2166                 const TempoSection* t;
2167
2168                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2169                         tempo = t;
2170                 }
2171         }
2172
2173         /* We now have:
2174
2175            tempo -> the Tempo for "pos"
2176            i     -> for first new metric after "pos", possibly metrics->end()
2177         */
2178
2179         while (beats) {
2180
2181                 /* Distance to the end of this section in frames */
2182                 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
2183
2184                 /* Distance to the end in beats */
2185                 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2186
2187                 /* Amount to subtract this time */
2188                 double const sub = min (distance_beats, beats);
2189
2190                 /* Update */
2191                 beats -= sub;
2192                 pos += sub * tempo->frames_per_beat (_frame_rate);
2193
2194                 /* Move on if there's anything to move to */
2195                 if (i != metrics->end ()) {
2196                         const TempoSection* t;
2197                         
2198                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2199                                 tempo = t;
2200                         }
2201
2202                         ++i;
2203                 }
2204         }
2205
2206         return pos;
2207 }
2208
2209 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2210 framepos_t
2211 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2212 {
2213         Metrics::const_iterator i;
2214         const TempoSection* tempo = 0;
2215         const TempoSection* t;
2216         
2217         /* Find the starting tempo */
2218
2219         for (i = metrics->begin(); i != metrics->end(); ++i) {
2220
2221                 /* This is a bit of a hack, but pos could be -ve, and if it is,
2222                    we consider the initial metric changes (at time 0) to actually
2223                    be in effect at pos.
2224                 */
2225                 framepos_t f = (*i)->frame ();
2226                 if (pos < 0 && f == 0) {
2227                         f = pos;
2228                 }
2229
2230                 if ((*i)->frame() > pos) {
2231                         break;
2232                 }
2233
2234                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2235                         tempo = t;
2236                 }
2237         }
2238
2239         bool no_more_tempos = false;
2240
2241         /* Move i back to the tempo before "pos" */
2242         if (i != metrics->begin ()) {
2243                 while (i != metrics->begin ()) {
2244                         --i;
2245                         t = dynamic_cast<TempoSection*> (*i);
2246                         if (t) {
2247                                 break;
2248                         }
2249                 }
2250         } else {
2251                 no_more_tempos = true;
2252         }
2253
2254         /* We now have:
2255
2256            tempo -> the Tempo for "pos"
2257            i     -> the first metric before "pos", unless no_more_tempos is true
2258         */
2259
2260         while (beats) {
2261
2262                 /* Distance to the end of this section in frames */
2263                 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2264
2265                 /* Distance to the end in beats */
2266                 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2267
2268                 /* Amount to subtract this time */
2269                 double const sub = min (distance_beats, beats);
2270
2271                 /* Update */
2272                 beats -= sub;
2273                 pos -= sub * tempo->frames_per_beat (_frame_rate);
2274
2275                 /* Move i and tempo back, if there's anything to move to */
2276                 if (i != metrics->begin ()) {
2277                         while (i != metrics->begin ()) {
2278                                 --i;
2279                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2280                                         tempo = t;
2281                                         break;
2282                                 }
2283                         }
2284                 } else {
2285                         no_more_tempos = true;
2286                 }
2287         }
2288
2289         return pos;
2290 }
2291
2292 /** Add the BBT interval op to pos and return the result */
2293 framepos_t
2294 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2295 {
2296         Metrics::const_iterator i;
2297         const MeterSection* meter;
2298         const MeterSection* m;
2299         const TempoSection* tempo;
2300         const TempoSection* t;
2301         double frames_per_beat;
2302
2303         meter = &first_meter ();
2304         tempo = &first_tempo ();
2305
2306         assert (meter);
2307         assert (tempo);
2308
2309         /* find the starting metrics for tempo & meter */
2310
2311         for (i = metrics->begin(); i != metrics->end(); ++i) {
2312
2313                 if ((*i)->frame() > pos) {
2314                         break;
2315                 }
2316
2317                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2318                         tempo = t;
2319                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2320                         meter = m;
2321                 }
2322         }
2323
2324         /* We now have:
2325
2326            meter -> the Meter for "pos"
2327            tempo -> the Tempo for "pos"
2328            i     -> for first new metric after "pos", possibly metrics->end()
2329         */
2330
2331         /* now comes the complicated part. we have to add one beat a time,
2332            checking for a new metric on every beat.
2333         */
2334
2335         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2336
2337         uint64_t bars = 0;
2338
2339         while (op.bars) {
2340
2341                 bars++;
2342                 op.bars--;
2343
2344                 /* check if we need to use a new metric section: has adding frames moved us
2345                    to or after the start of the next metric section? in which case, use it.
2346                 */
2347
2348                 if (i != metrics->end()) {
2349                         if ((*i)->frame() <= pos) {
2350
2351                                 /* about to change tempo or meter, so add the
2352                                  * number of frames for the bars we've just
2353                                  * traversed before we change the
2354                                  * frames_per_beat value.
2355                                  */
2356                                 
2357                                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2358                                 bars = 0;
2359
2360                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2361                                         tempo = t;
2362                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2363                                         meter = m;
2364                                 }
2365                                 ++i;
2366                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2367
2368                         }
2369                 }
2370
2371         }
2372
2373         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2374
2375         uint64_t beats = 0;
2376
2377         while (op.beats) {
2378
2379                 /* given the current meter, have we gone past the end of the bar ? */
2380
2381                 beats++;
2382                 op.beats--;
2383
2384                 /* check if we need to use a new metric section: has adding frames moved us
2385                    to or after the start of the next metric section? in which case, use it.
2386                 */
2387
2388                 if (i != metrics->end()) {
2389                         if ((*i)->frame() <= pos) {
2390
2391                                 /* about to change tempo or meter, so add the
2392                                  * number of frames for the beats we've just
2393                                  * traversed before we change the
2394                                  * frames_per_beat value.
2395                                  */
2396
2397                                 pos += llrint (beats * frames_per_beat);
2398                                 beats = 0;
2399
2400                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2401                                         tempo = t;
2402                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2403                                         meter = m;
2404                                 }
2405                                 ++i;
2406                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2407                         }
2408                 }
2409         }
2410
2411         pos += llrint (beats * frames_per_beat);
2412
2413         if (op.ticks) {
2414                 if (op.ticks >= BBT_Time::ticks_per_bar_division) {
2415                         pos += llrint (frames_per_beat + /* extra beat */
2416                                        (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_bar_division) / 
2417                                                            (double) BBT_Time::ticks_per_bar_division)));
2418                 } else {
2419                         pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_bar_division));
2420                 }
2421         }
2422
2423         return pos;
2424 }
2425
2426 /** Count the number of beats that are equivalent to distance when going forward,
2427     starting at pos.
2428 */
2429 Evoral::MusicalTime
2430 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2431 {
2432         Metrics::const_iterator i;
2433         const TempoSection* tempo;
2434         
2435         /* Find the starting tempo */
2436
2437         for (i = metrics->begin(); i != metrics->end(); ++i) {
2438
2439                 if ((*i)->frame() > pos) {
2440                         break;
2441                 }
2442
2443                 const TempoSection* t;
2444
2445                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2446                         tempo = t;
2447                 }
2448         }
2449
2450         /* We now have:
2451
2452            tempo -> the Tempo for "pos"
2453            i     -> the first metric after "pos", possibly metrics->end()
2454         */
2455
2456         Evoral::MusicalTime beats = 0;
2457
2458         while (distance) {
2459
2460                 /* End of this section */
2461                 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2462
2463                 /* Distance to the end in frames */
2464                 framecnt_t const distance_to_end = end - pos;
2465
2466                 /* Amount to subtract this time */
2467                 double const sub = min (distance, distance_to_end);
2468
2469                 /* Update */
2470                 pos += sub;
2471                 distance -= sub;
2472                 beats += sub / tempo->frames_per_beat (_frame_rate);
2473
2474                 /* Move on if there's anything to move to */
2475                 if (i != metrics->end ()) {
2476                         const TempoSection* t;
2477                         
2478                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2479                                 tempo = t;
2480                         }
2481
2482                         ++i;
2483                 }
2484         }
2485
2486         return beats;
2487 }
2488
2489 /** Compare the time of this with that of another MetricSection.
2490  *  @param with_bbt True to compare using start(), false to use frame().
2491  *  @return -1 for less than, 0 for equal, 1 for greater than.
2492  */
2493
2494 int
2495 MetricSection::compare (const MetricSection& other) const
2496 {
2497         if (start() == other.start()) {
2498                 return 0;
2499         } else if (start() < other.start()) {
2500                 return -1;
2501         } else {
2502                 return 1;
2503         }
2504
2505         /* NOTREACHED */
2506         return 0;
2507 }
2508
2509 bool
2510 MetricSection::operator== (const MetricSection& other) const
2511 {
2512         return compare (other) == 0;
2513 }
2514
2515 bool
2516 MetricSection::operator!= (const MetricSection& other) const
2517 {
2518         return compare (other) != 0;
2519 }
2520
2521 std::ostream& 
2522 operator<< (std::ostream& o, const Meter& m) {
2523         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2524 }
2525
2526 std::ostream& 
2527 operator<< (std::ostream& o, const Tempo& t) {
2528         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2529 }
2530
2531 std::ostream& 
2532 operator<< (std::ostream& o, const MetricSection& section) {
2533
2534         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2535
2536         const TempoSection* ts;
2537         const MeterSection* ms;
2538
2539         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2540                 o << *((Tempo*) ts);
2541         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2542                 o << *((Meter*) ms);
2543         }
2544
2545         return o;
2546 }