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