update position of tempo map metrics when a meter marker is removed
[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_bar (const Tempo& tempo, framecnt_t sr) const
58 {
59         return (60.0 * sr * _divisions_per_bar) / tempo.beats_per_minute();
60 }
61
62 double 
63 Meter::frames_per_division (const Tempo& tempo, framecnt_t sr) const
64 {
65         return (60.0 * sr) / (tempo.beats_per_minute() * _note_type/tempo.note_type());
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         framecnt_t frame_diff;
866
867         const double divisions_per_bar = metric.meter().divisions_per_bar();
868         const double ticks_per_frame = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
869
870         // cerr << "*** Compute BBT time for " << frame 
871         // <<  " from metric at " << metric.frame() << " tempo = " << metric.tempo().beats_per_minute () << " meter " 
872         // << metric.meter().divisions_per_bar() << '/' << metric.meter().note_divisor() 
873         // << endl; 
874
875         /* now compute how far beyond that point we actually are. */
876
877         frame_diff = frame - metric.frame();
878
879         bbt.ticks = metric.start().ticks + (uint32_t)round((double)frame_diff / ticks_per_frame);
880         uint32_t xtra_beats = bbt.ticks / (uint32_t)BBT_Time::ticks_per_beat;
881         bbt.ticks %= (uint32_t)BBT_Time::ticks_per_beat;
882
883         bbt.beats = metric.start().beats + xtra_beats - 1; // correction for 1-based counting, see below for matching operation.
884         bbt.bars = metric.start().bars + (uint32_t)floor((double)bbt.beats / divisions_per_bar);
885         bbt.beats = (uint32_t)fmod((double)bbt.beats, divisions_per_bar);
886
887         /* if we have a fractional number of beats per bar, we see if
888            we're in the last beat (the fractional one).  if so, we
889            round ticks appropriately and bump to the next bar. 
890         */
891         double beat_fraction = divisions_per_bar - floor(divisions_per_bar);
892
893         /* XXX one problem here is that I'm not sure how to handle
894            fractional beats that don't evenly divide ticks_per_beat.
895            If they aren't handled consistently, I would guess we'll
896            continue to have strange discrepancies occuring.  Perhaps
897            this will also behave badly in the case of meters like
898            0.1/4, but I can't be bothered to test that.
899         */
900         uint32_t ticks_on_last_beat = (uint32_t)floor(BBT_Time::ticks_per_beat * beat_fraction);
901
902         if (bbt.beats > (uint32_t)floor(divisions_per_bar) && bbt.ticks >= ticks_on_last_beat) {
903                 bbt.ticks -= ticks_on_last_beat;
904                 bbt.beats = 0;
905                 bbt.bars++;
906         }
907
908         bbt.beats++; // correction for 1-based counting, see above for matching operation.
909
910         // cerr << "-----\t RETURN " << bbt << endl;
911 }
912
913 framecnt_t
914 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
915 {
916         /* for this to work with fractional measure types, start and end have to be
917            "legal" BBT types, that means that the beats and ticks should be inside
918            a bar
919         */
920
921         framecnt_t frames = 0;
922         framepos_t start_frame = 0;
923         framepos_t end_frame = 0;
924
925         TempoMetric m = metric_at (start);
926
927         uint32_t bar_offset = start.bars - m.start().bars;
928
929         double  beat_offset = bar_offset*m.meter().divisions_per_bar() - (m.start().beats-1) + (start.beats -1)
930                 + start.ticks/BBT_Time::ticks_per_beat;
931
932         start_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
933
934         // cerr << "from start " << start << " compute frame = " << start_frame 
935         // <<  " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter " 
936         // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor() 
937         // << endl;
938
939         m =  metric_at(end);
940
941         bar_offset = end.bars - m.start().bars;
942
943         beat_offset = bar_offset * m.meter().divisions_per_bar() - (m.start().beats -1) + (end.beats - 1)
944                 + end.ticks/BBT_Time::ticks_per_beat;
945
946         end_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
947
948         // cerr << "from end " << end << " compute frame = " << end_frame 
949         // <<  " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter " 
950         // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor() 
951         // << endl;
952
953         frames = end_frame - start_frame;
954
955         return frames;
956
957 }
958
959 framecnt_t
960 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
961 {
962         /* this is used in timestamping the metrics by actually counting the beats */
963
964         framecnt_t frames = 0;
965         uint32_t bar = start.bars;
966         double beat = (double) start.beats;
967         double divisions_counted = 0;
968         double divisions_per_bar = 0;
969         double division_frames = 0;
970
971         divisions_per_bar = meter.divisions_per_bar();
972         division_frames = meter.frames_per_division (tempo, _frame_rate);
973
974         frames = 0;
975
976         while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
977
978                 if (beat >= divisions_per_bar) {
979                         beat = 1;
980                         ++bar;
981                         ++divisions_counted;
982
983                         if (beat > divisions_per_bar) {
984
985                                 /* this is a fractional beat at the end of a fractional bar
986                                    so it should only count for the fraction
987                                 */
988
989                                 divisions_counted -= (ceil(divisions_per_bar) - divisions_per_bar);
990                         }
991
992                 } else {
993                         ++beat;
994                         ++divisions_counted;
995                 }
996         }
997
998         // cerr << "Counted " << beats_counted << " from " << start << " to " << end
999         // << " bpb were " << divisions_per_bar
1000         // << " fpb was " << beat_frames
1001         // << endl;
1002
1003         frames = (framecnt_t) llrint (floor (divisions_counted * division_frames));
1004
1005         return frames;
1006
1007 }
1008
1009 framepos_t
1010 TempoMap::frame_time (const BBT_Time& bbt) const
1011 {
1012         BBT_Time start ; /* 1|1|0 */
1013
1014         return count_frames_between (start, bbt);
1015 }
1016
1017 framecnt_t
1018 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1019 {
1020         framecnt_t frames = 0;
1021
1022         BBT_Time when;
1023         bbt_time(pos, when);
1024
1025         {
1026                 Glib::RWLock::ReaderLock lm (lock);
1027                 frames = bbt_duration_at_unlocked (when, bbt,dir);
1028         }
1029
1030         return frames;
1031 }
1032
1033 framecnt_t
1034 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1035 {
1036         framecnt_t frames = 0;
1037
1038         double divisions_per_bar;
1039         BBT_Time result;
1040
1041         result.bars = max(1U, when.bars + dir * bbt.bars) ;
1042         result.beats = 1;
1043         result.ticks = 0;
1044
1045         TempoMetric     metric = metric_at(result);
1046         divisions_per_bar = metric.meter().divisions_per_bar();
1047
1048         /* Reduce things to legal bbt values we have to handle possible
1049           fractional=shorter beats at the end of measures and things like 0|11|9000
1050           as a duration in a 4.5/4 measure the musical decision is that the
1051           fractional beat is also a beat , although a shorter one
1052         */
1053
1054         if (dir >= 0) {
1055                 result.beats = when.beats +  bbt.beats;
1056                 result.ticks = when.ticks +  bbt.ticks;
1057
1058                 while (result.beats >= (divisions_per_bar + 1)) {
1059                         result.bars++;
1060                         result.beats -=  (uint32_t) ceil(divisions_per_bar);
1061                         metric = metric_at(result); // maybe there is a meter change
1062                         divisions_per_bar = metric.meter().divisions_per_bar();
1063
1064                 }
1065
1066                 /* We now counted the beats and landed in the target measure, now deal
1067                   with ticks this seems complicated, but we want to deal with the
1068                   corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1069                   with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1070                   ticks
1071                 */
1072
1073                 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1074                  */
1075
1076                 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1077                                         (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_beat
1078                                            : BBT_Time::ticks_per_beat );
1079
1080                 while (result.ticks >= ticks_at_beat) {
1081                         result.beats++;
1082                         result.ticks -= ticks_at_beat;
1083                         if  (result.beats >= (divisions_per_bar + 1)) {
1084                                 result.bars++;
1085                                 result.beats = 1;
1086                                 metric = metric_at(result); // maybe there is a meter change
1087                                 divisions_per_bar = metric.meter().divisions_per_bar();
1088                         }
1089                         ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1090                                        (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_beat
1091                                        : BBT_Time::ticks_per_beat);
1092                 }
1093
1094
1095         } else {
1096                 uint32_t b = bbt.beats;
1097
1098                 /* count beats */
1099                 while (b > when.beats) {
1100                         --result.bars;
1101                         result.bars = max(1U, result.bars);
1102                         metric = metric_at(result); // maybe there is a meter change
1103                         divisions_per_bar = metric.meter().divisions_per_bar();
1104                         if (b >= ceil(divisions_per_bar)) {
1105                                 b -= (uint32_t) ceil(divisions_per_bar);
1106                         } else {
1107                                 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1108                         }
1109                 }
1110                 result.beats = when.beats - b;
1111
1112                 /* count ticks */
1113
1114                 if (bbt.ticks <= when.ticks) {
1115                         result.ticks = when.ticks - bbt.ticks;
1116                 } else {
1117
1118                         uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_beat;
1119                         uint32_t t = bbt.ticks - when.ticks;
1120
1121                         do {
1122
1123                                 if (result.beats == 1) {
1124                                         --result.bars;
1125                                         result.bars = max(1U, result.bars) ;
1126                                         metric = metric_at(result); // maybe there is a meter change
1127                                         divisions_per_bar = metric.meter().divisions_per_bar();
1128                                         result.beats = (uint32_t) ceil(divisions_per_bar);
1129                                         ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_beat) ;
1130                                 } else {
1131                                         --result.beats;
1132                                         ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
1133                                 }
1134
1135                                 if (t <= ticks_at_beat) {
1136                                         result.ticks = ticks_at_beat - t;
1137                                 } else {
1138                                         t-= ticks_at_beat;
1139                                 }
1140                         } while (t > ticks_at_beat);
1141
1142                 }
1143
1144
1145         }
1146
1147         if (dir < 0) {
1148                 frames = count_frames_between(result, when);
1149         } else {
1150                 frames = count_frames_between(when,result);
1151         }
1152
1153         return frames;
1154 }
1155
1156
1157
1158 framepos_t
1159 TempoMap::round_to_bar (framepos_t fr, int dir)
1160 {
1161         {
1162                 Glib::RWLock::ReaderLock lm (lock);
1163                 return round_to_type (fr, dir, Bar);
1164         }
1165 }
1166
1167
1168 framepos_t
1169 TempoMap::round_to_beat (framepos_t fr, int dir)
1170 {
1171         {
1172                 Glib::RWLock::ReaderLock lm (lock);
1173                 return round_to_type (fr, dir, Beat);
1174         }
1175 }
1176
1177 framepos_t
1178 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1179 {
1180         BBT_Time the_beat;
1181         uint32_t ticks_one_half_subdivisions_worth;
1182         uint32_t ticks_one_subdivisions_worth;
1183         uint32_t difference;
1184
1185         bbt_time(fr, the_beat);
1186
1187         ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1188         ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1189
1190         if (dir > 0) {
1191
1192                 /* round to next */
1193
1194                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1195
1196                 if (mod == 0) {
1197                         /* right on the subdivision, so the difference is just the subdivision ticks */
1198                         difference = ticks_one_subdivisions_worth;
1199
1200                 } else {
1201                         /* not on subdivision, compute distance to next subdivision */
1202
1203                         difference = ticks_one_subdivisions_worth - mod;
1204                 }
1205
1206                 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1207
1208         } else if (dir < 0) {
1209
1210                 /* round to previous */
1211
1212                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1213
1214                 if (mod == 0) {
1215                         /* right on the subdivision, so the difference is just the subdivision ticks */
1216                         difference = ticks_one_subdivisions_worth;
1217                 } else {
1218                         /* not on subdivision, compute distance to previous subdivision, which
1219                            is just the modulus.
1220                         */
1221
1222                         difference = mod;
1223                 }
1224
1225                 try {
1226                         the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1227                 } catch (...) {
1228                         /* can't go backwards from wherever pos is, so just return it */
1229                         return fr;
1230                 }
1231
1232         } else {
1233                 /* round to nearest */
1234
1235                 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1236                         difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1237                         the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1238                 } else {
1239                         // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1240                         the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1241                 }
1242         }
1243
1244         return frame_time (the_beat);
1245 }
1246
1247 framepos_t
1248 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1249 {
1250         TempoMetric metric = metric_at (frame);
1251         BBT_Time bbt;
1252         BBT_Time start;
1253         BBT_Time one_bar (1,0,0);
1254         BBT_Time one_beat (0,1,0);
1255
1256         bbt_time_with_metric (frame, bbt, metric);
1257
1258         switch (type) {
1259         case Bar:
1260                 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1261
1262                 if (dir < 0) {
1263
1264                         /* find bar position preceding frame */
1265
1266                         try {
1267                                 bbt = bbt_subtract (bbt, one_bar);
1268                         }
1269
1270                         catch (...) {
1271                                 return frame;
1272                         }
1273
1274
1275                 } else if (dir > 0) {
1276
1277                         /* find bar position following frame */
1278
1279                         try {
1280                                 bbt = bbt_add (bbt, one_bar, metric);
1281                         }
1282                         catch (...) {
1283                                 return frame;
1284                         }
1285
1286                 } else {
1287
1288                         /* "true" rounding */
1289
1290                         float midbar_beats;
1291                         float midbar_ticks;
1292
1293                         midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1294                         midbar_ticks = BBT_Time::ticks_per_beat * fmod (midbar_beats, 1.0f);
1295                         midbar_beats = floor (midbar_beats);
1296
1297                         BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1298
1299                         if (bbt < midbar) {
1300                                 /* round down */
1301                                 bbt.beats = 1;
1302                                 bbt.ticks = 0;
1303                         } else {
1304                                 /* round up */
1305                                 bbt.bars++;
1306                                 bbt.beats = 1;
1307                                 bbt.ticks = 0;
1308                         }
1309                 }
1310                 /* force beats & ticks to their values at the start of a bar */
1311                 bbt.beats = 1;
1312                 bbt.ticks = 0;
1313                 break;
1314
1315         case Beat:
1316                 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1317
1318                 if (dir < 0) {
1319
1320                         /* find beat position preceding frame */
1321
1322                         try {
1323                                 bbt = bbt_subtract (bbt, one_beat);
1324                         }
1325
1326                         catch (...) {
1327                                 return frame;
1328                         }
1329
1330
1331                 } else if (dir > 0) {
1332
1333                         /* find beat position following frame */
1334
1335                         try {
1336                                 bbt = bbt_add (bbt, one_beat, metric);
1337                         }
1338                         catch (...) {
1339                                 return frame;
1340                         }
1341
1342                 } else {
1343
1344                         /* "true" rounding */
1345
1346                         /* round to nearest beat */
1347                         if (bbt.ticks >= (BBT_Time::ticks_per_beat/2)) {
1348
1349                                 try {
1350                                         bbt = bbt_add (bbt, one_beat, metric);
1351                                 }
1352                                 catch (...) {
1353                                         return frame;
1354                                 }
1355                         }
1356                 }
1357                 /* force ticks to the value at the start of a beat */
1358                 bbt.ticks = 0;
1359                 break;
1360
1361         }
1362
1363         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)));
1364         return metric.frame() + count_frames_between (metric.start(), bbt);
1365 }
1366
1367 TempoMap::BBTPointList *
1368 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1369 {
1370
1371         Metrics::const_iterator i;
1372         BBTPointList *points;
1373         double current;
1374         const MeterSection* meter;
1375         const MeterSection* m;
1376         const TempoSection* tempo;
1377         const TempoSection* t;
1378         uint32_t bar;
1379         uint32_t beat;
1380         double divisions_per_bar;
1381         double beat_frame;
1382         double beat_frames;
1383         double frames_per_bar;
1384         double delta_bars;
1385         double delta_beats;
1386         double dummy;
1387         framepos_t limit;
1388
1389         meter = &first_meter ();
1390         tempo = &first_tempo ();
1391
1392         /* find the starting point */
1393
1394         for (i = metrics->begin(); i != metrics->end(); ++i) {
1395
1396                 if ((*i)->frame() > lower) {
1397                         break;
1398                 }
1399
1400                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1401                         tempo = t;
1402                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1403                         meter = m;
1404                 }
1405         }
1406
1407         /* We now have:
1408
1409            meter -> the Meter for "lower"
1410            tempo -> the Tempo for "lower"
1411            i     -> for first new metric after "lower", possibly metrics->end()
1412
1413            Now start generating points.
1414         */
1415
1416         divisions_per_bar = meter->divisions_per_bar ();
1417         frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1418         beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1419
1420         if (meter->frame() > tempo->frame()) {
1421                 bar = meter->start().bars;
1422                 beat = meter->start().beats;
1423                 current = meter->frame();
1424         } else {
1425                 bar = tempo->start().bars;
1426                 beat = tempo->start().beats;
1427                 current = tempo->frame();
1428         }
1429
1430         /* initialize current to point to the bar/beat just prior to the
1431            lower frame bound passed in.  assumes that current is initialized
1432            above to be on a beat.
1433         */
1434
1435         delta_bars = (lower-current) / frames_per_bar;
1436         delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1437         current += (floor(delta_bars) * frames_per_bar) +  (floor(delta_beats) * beat_frames);
1438
1439         // adjust bars and beats too
1440         bar += (uint32_t) (floor(delta_bars));
1441         beat += (uint32_t) (floor(delta_beats));
1442
1443         points = new BBTPointList;
1444
1445         do {
1446
1447                 if (i == metrics->end()) {
1448                         limit = upper;
1449                         // cerr << "== limit set to end of request @ " << limit << endl;
1450                 } else {
1451                         // cerr << "== limit set to next metric @ " << (*i)->frame() << endl;
1452                         limit = (*i)->frame();
1453                 }
1454
1455                 limit = min (limit, upper);
1456
1457                 while (current < limit) {
1458
1459                         /* if we're at the start of a bar, add bar point */
1460
1461                         if (beat == 1) {
1462                                 if (current >= lower) {
1463                                         // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
1464                                         points->push_back (BBTPoint (*meter, *tempo,(framepos_t)rint(current), Bar, bar, 1));
1465
1466                                 }
1467                         }
1468
1469                         /* add some beats if we can */
1470
1471                         beat_frame = current;
1472
1473                         while (beat <= ceil(divisions_per_bar) && beat_frame < limit) {
1474                                 if (beat_frame >= lower) {
1475                                         // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
1476                                         points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
1477                                 }
1478                                 beat_frame += beat_frames;
1479                                 current+= beat_frames;
1480
1481                                 beat++;
1482                         }
1483
1484                         // cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
1485                         // << (beat > ceil(divisions_per_bar))
1486                         // << " beat frame @ " << beat_frame << " vs. " << limit
1487                         // << endl;
1488
1489                         if (beat > ceil(divisions_per_bar) || i != metrics->end()) {
1490
1491                                 /* we walked an entire bar. its
1492                                    important to move `current' forward
1493                                    by the actual frames_per_bar, not move it to
1494                                    an integral beat_frame, so that metrics with
1495                                    non-integral beats-per-bar have
1496                                    their bar positions set
1497                                    correctly. consider a metric with
1498                                    9-1/2 beats-per-bar. the bar we
1499                                    just filled had  10 beat marks,
1500                                    but the bar end is 1/2 beat before
1501                                    the last beat mark.
1502                                    And it is also possible that a tempo
1503                                    change occured in the middle of a bar,
1504                                    so we subtract the possible extra fraction from the current
1505                                 */
1506
1507                                 if (beat > ceil (divisions_per_bar)) {
1508                                         /* next bar goes where the numbers suggest */
1509                                         current -=  beat_frames * (ceil(divisions_per_bar)-divisions_per_bar);
1510                                         // cerr << "++ next bar from numbers\n";
1511                                 } else {
1512                                         /* next bar goes where the next metric is */
1513                                         current = limit;
1514                                         // cerr << "++ next bar at next metric\n";
1515                                 }
1516                                 bar++;
1517                                 beat = 1;
1518                         }
1519
1520                 }
1521
1522                 /* if we're done, then we're done */
1523
1524                 if (current >= upper) {
1525                         break;
1526                 }
1527
1528                 /* i is an iterator that refers to the next metric (or none).
1529                    if there is a next metric, move to it, and continue.
1530                 */
1531
1532                 if (i != metrics->end()) {
1533
1534                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1535                                 tempo = t;
1536                         } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1537                                 meter = m;
1538                                 /* new MeterSection, beat always returns to 1 */
1539                                 beat = 1;
1540                         }
1541                         
1542                         current = (*i)->frame ();
1543                         // cerr << "loop around with current @ " << current << endl;
1544
1545                         divisions_per_bar = meter->divisions_per_bar ();
1546                         frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1547                         beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1548
1549                         ++i;
1550                 }
1551
1552         } while (1);
1553
1554         return points;
1555 }
1556
1557 const TempoSection&
1558 TempoMap::tempo_section_at (framepos_t frame) const
1559 {
1560         Glib::RWLock::ReaderLock lm (lock);
1561         Metrics::const_iterator i;
1562         TempoSection* prev = 0;
1563
1564         for (i = metrics->begin(); i != metrics->end(); ++i) {
1565                 TempoSection* t;
1566
1567                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1568
1569                         if ((*i)->frame() > frame) {
1570                                 break;
1571                         }
1572
1573                         prev = t;
1574                 }
1575         }
1576
1577         if (prev == 0) {
1578                 fatal << endmsg;
1579         }
1580
1581         return *prev;
1582 }
1583
1584 const Tempo&
1585 TempoMap::tempo_at (framepos_t frame) const
1586 {
1587         TempoMetric m (metric_at (frame));
1588         return m.tempo();
1589 }
1590
1591
1592 const Meter&
1593 TempoMap::meter_at (framepos_t frame) const
1594 {
1595         TempoMetric m (metric_at (frame));
1596         return m.meter();
1597 }
1598
1599 XMLNode&
1600 TempoMap::get_state ()
1601 {
1602         Metrics::const_iterator i;
1603         XMLNode *root = new XMLNode ("TempoMap");
1604
1605         {
1606                 Glib::RWLock::ReaderLock lm (lock);
1607                 for (i = metrics->begin(); i != metrics->end(); ++i) {
1608                         root->add_child_nocopy ((*i)->get_state());
1609                 }
1610         }
1611
1612         return *root;
1613 }
1614
1615 int
1616 TempoMap::set_state (const XMLNode& node, int /*version*/)
1617 {
1618         {
1619                 Glib::RWLock::WriterLock lm (lock);
1620
1621                 XMLNodeList nlist;
1622                 XMLNodeConstIterator niter;
1623                 Metrics old_metrics (*metrics);
1624
1625                 metrics->clear();
1626
1627                 nlist = node.children();
1628
1629                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1630                         XMLNode* child = *niter;
1631
1632                         if (child->name() == TempoSection::xml_state_node_name) {
1633
1634                                 try {
1635                                         metrics->push_back (new TempoSection (*child));
1636                                 }
1637
1638                                 catch (failed_constructor& err){
1639                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1640                                         *metrics = old_metrics;
1641                                         break;
1642                                 }
1643
1644                         } else if (child->name() == MeterSection::xml_state_node_name) {
1645
1646                                 try {
1647                                         metrics->push_back (new MeterSection (*child));
1648                                 }
1649
1650                                 catch (failed_constructor& err) {
1651                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1652                                         *metrics = old_metrics;
1653                                         break;
1654                                 }
1655                         }
1656                 }
1657
1658                 if (niter == nlist.end()) {
1659
1660                         MetricSectionSorter cmp;
1661                         metrics->sort (cmp);
1662                         timestamp_metrics (true);
1663                 }
1664         }
1665
1666         PropertyChanged (PropertyChange ());
1667
1668         return 0;
1669 }
1670
1671 void
1672 TempoMap::dump (std::ostream& o) const
1673 {
1674         const MeterSection* m;
1675         const TempoSection* t;
1676
1677         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1678
1679                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1680                         o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
1681                           << t->movable() << ')' << endl;
1682                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1683                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1684                           << " (move? " << m->movable() << ')' << endl;
1685                 }
1686         }
1687 }
1688
1689 int
1690 TempoMap::n_tempos() const
1691 {
1692         Glib::RWLock::ReaderLock lm (lock);
1693         int cnt = 0;
1694
1695         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1696                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1697                         cnt++;
1698                 }
1699         }
1700
1701         return cnt;
1702 }
1703
1704 int
1705 TempoMap::n_meters() const
1706 {
1707         Glib::RWLock::ReaderLock lm (lock);
1708         int cnt = 0;
1709
1710         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1711                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1712                         cnt++;
1713                 }
1714         }
1715
1716         return cnt;
1717 }
1718
1719 void
1720 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1721 {
1722         for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1723                 if ((*i)->frame() >= where && (*i)->movable ()) {
1724                         (*i)->set_frame ((*i)->frame() + amount);
1725                 }
1726         }
1727
1728         timestamp_metrics (false);
1729
1730         PropertyChanged (PropertyChange ());
1731 }
1732
1733 BBT_Time
1734 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1735 {
1736         TempoMetric metric =  metric_at (start);
1737         return bbt_add (start, other, metric);
1738 }
1739
1740 /**
1741  * add the BBT interval @param increment to  @param start and return the result
1742  */
1743 BBT_Time
1744 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1745 {
1746         BBT_Time result = start;
1747         BBT_Time op = increment; /* argument is const, but we need to modify it */
1748         uint32_t ticks = result.ticks + op.ticks;
1749
1750         if (ticks >= BBT_Time::ticks_per_beat) {
1751                 op.beats++;
1752                 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_beat;
1753         } else {
1754                 result.ticks += op.ticks;
1755         }
1756
1757         /* now comes the complicated part. we have to add one beat a time,
1758            checking for a new metric on every beat.
1759         */
1760
1761         /* grab all meter sections */
1762
1763         list<const MeterSection*> meter_sections;
1764
1765         for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1766                 const MeterSection* ms;
1767                 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1768                         meter_sections.push_back (ms);
1769                 }
1770         }
1771
1772         assert (!meter_sections.empty());
1773
1774         list<const MeterSection*>::const_iterator next_meter;
1775         const Meter* meter = 0;
1776
1777         /* go forwards through the meter sections till we get to the one
1778            covering the current value of result. this positions i to point to
1779            the next meter section too, or the end.
1780         */
1781
1782         for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1783
1784                 if (result < (*next_meter)->start()) {
1785                         /* this metric is past the result time. stop looking, we have what we need */
1786                         break;
1787                 }
1788
1789                 if (result == (*next_meter)->start()) {
1790                         /* this meter section starts at result, push i beyond it so that it points
1791                            to the NEXT section, opwise we will get stuck later, and use this meter section.
1792                         */
1793                         meter = *next_meter;
1794                         ++next_meter;
1795                         break;
1796                 }
1797
1798                 meter = *next_meter;
1799         }
1800
1801         assert (meter != 0);
1802
1803         /* OK, now have the meter for the bar start we are on, and i is an iterator
1804            that points to the metric after the one we are currently dealing with
1805            (or to metrics->end(), of course)
1806         */
1807
1808         while (op.beats) {
1809
1810                 /* given the current meter, have we gone past the end of the bar ? */
1811
1812                 if (result.beats >= meter->divisions_per_bar()) {
1813                         /* move to next bar, first beat */
1814                         result.bars++;
1815                         result.beats = 1;
1816                 } else {
1817                         result.beats++;
1818                 }
1819
1820                 /* one down ... */
1821
1822                 op.beats--;
1823
1824                 /* check if we need to use a new meter section: has adding beats to result taken us
1825                    to or after the start of the next meter section? in which case, use it.
1826                 */
1827
1828                 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1829                         meter = *next_meter;
1830                         ++next_meter;
1831                 }
1832         }
1833
1834         /* finally, add bars */
1835
1836         result.bars += op.bars++;
1837
1838         return result;
1839 }
1840
1841 /**
1842  * subtract the BBT interval @param decrement from @param start and return the result
1843  */
1844 BBT_Time
1845 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1846 {
1847         BBT_Time result = start;
1848         BBT_Time op = decrement; /* argument is const, but we need to modify it */
1849
1850         if (op.ticks > result.ticks) {
1851                 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
1852                 op.beats++;
1853                 result.ticks = BBT_Time::ticks_per_beat - (op.ticks - result.ticks);
1854         } else {
1855                 result.ticks -= op.ticks;
1856         }
1857
1858         /* now comes the complicated part. we have to subtract one beat a time,
1859            checking for a new metric on every beat.
1860         */
1861
1862         /* grab all meter sections */
1863
1864         list<const MeterSection*> meter_sections;
1865
1866         for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1867                 const MeterSection* ms;
1868                 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1869                         meter_sections.push_back (ms);
1870                 }
1871                 }
1872
1873         assert (!meter_sections.empty());
1874
1875         /* go backwards through the meter sections till we get to the one
1876            covering the current value of result. this positions i to point to
1877            the next (previous) meter section too, or the end.
1878         */
1879
1880         const MeterSection* meter = 0;
1881         list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
1882                                                                 // support const_reverse_iterator::operator!=()
1883
1884         for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
1885
1886                 /* when we find the first meter section that is before or at result, use it,
1887                    and set next_meter to the previous one
1888                 */
1889
1890                 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
1891                         meter = *next_meter;
1892                         ++next_meter;
1893                         break;
1894                 }
1895         }
1896
1897         assert (meter != 0);
1898
1899         /* OK, now have the meter for the bar start we are on, and i is an iterator
1900            that points to the metric after the one we are currently dealing with
1901            (or to metrics->end(), of course)
1902         */
1903
1904         while (op.beats) {
1905
1906                 /* have we reached the start of the bar? if so, move to the last beat of the previous
1907                    bar. opwise, just step back 1 beat.
1908                 */
1909
1910                 if (result.beats == 1) {
1911
1912                         /* move to previous bar, last beat */
1913
1914                         if (result.bars <= 1) {
1915                                 /* i'm sorry dave, i can't do that */
1916                                 throw std::out_of_range ("illegal BBT subtraction");
1917                         }
1918
1919                         result.bars--;
1920                         result.beats = meter->divisions_per_bar();
1921                 } else {
1922
1923                         /* back one beat */
1924
1925                         result.beats--;
1926                 }
1927
1928                 /* one down ... */
1929                 op.beats--;
1930
1931                 /* check if we need to use a new meter section: has subtracting beats to result taken us
1932                    to before the start of the current meter section? in which case, use the prior one.
1933                 */
1934
1935                 if (result < meter->start() && next_meter != meter_sections.rend()) {
1936                         meter = *next_meter;
1937                         ++next_meter;
1938                 }
1939         }
1940
1941         /* finally, subtract bars */
1942
1943         if (op.bars >= result.bars) {
1944                 /* i'm sorry dave, i can't do that */
1945                 throw std::out_of_range ("illegal BBT subtraction");
1946         }
1947
1948         result.bars -= op.bars;
1949         return result;
1950 }
1951
1952 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1953  *  pos can be -ve, if required.
1954  */
1955 framepos_t
1956 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
1957 {
1958         Metrics::const_iterator i;
1959         const TempoSection* tempo;
1960
1961         /* Find the starting tempo */
1962
1963         for (i = metrics->begin(); i != metrics->end(); ++i) {
1964
1965                 /* This is a bit of a hack, but pos could be -ve, and if it is,
1966                    we consider the initial metric changes (at time 0) to actually
1967                    be in effect at pos.
1968                 */
1969                 framepos_t f = (*i)->frame ();
1970                 if (pos < 0 && f == 0) {
1971                         f = pos;
1972                 }
1973
1974                 if (f > pos) {
1975                         break;
1976                 }
1977
1978                 const TempoSection* t;
1979
1980                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1981                         tempo = t;
1982                 }
1983         }
1984
1985         /* We now have:
1986
1987            tempo -> the Tempo for "pos"
1988            i     -> for first new metric after "pos", possibly metrics->end()
1989         */
1990
1991         while (beats) {
1992
1993                 /* Distance to the end of this section in frames */
1994                 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
1995
1996                 /* Distance to the end in beats */
1997                 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
1998
1999                 /* Amount to subtract this time */
2000                 double const sub = min (distance_beats, beats);
2001
2002                 /* Update */
2003                 beats -= sub;
2004                 pos += sub * tempo->frames_per_beat (_frame_rate);
2005
2006                 /* Move on if there's anything to move to */
2007                 if (i != metrics->end ()) {
2008                         const TempoSection* t;
2009                         
2010                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2011                                 tempo = t;
2012                         }
2013
2014                         ++i;
2015                 }
2016         }
2017
2018         return pos;
2019 }
2020
2021 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2022 framepos_t
2023 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2024 {
2025         Metrics::const_iterator i;
2026         const TempoSection* tempo = 0;
2027         const TempoSection* t;
2028         
2029         /* Find the starting tempo */
2030
2031         for (i = metrics->begin(); i != metrics->end(); ++i) {
2032
2033                 /* This is a bit of a hack, but pos could be -ve, and if it is,
2034                    we consider the initial metric changes (at time 0) to actually
2035                    be in effect at pos.
2036                 */
2037                 framepos_t f = (*i)->frame ();
2038                 if (pos < 0 && f == 0) {
2039                         f = pos;
2040                 }
2041
2042                 if ((*i)->frame() > pos) {
2043                         break;
2044                 }
2045
2046                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2047                         tempo = t;
2048                 }
2049         }
2050
2051         bool no_more_tempos = false;
2052
2053         /* Move i back to the tempo before "pos" */
2054         if (i != metrics->begin ()) {
2055                 while (i != metrics->begin ()) {
2056                         --i;
2057                         t = dynamic_cast<TempoSection*> (*i);
2058                         if (t) {
2059                                 break;
2060                         }
2061                 }
2062         } else {
2063                 no_more_tempos = true;
2064         }
2065
2066         /* We now have:
2067
2068            tempo -> the Tempo for "pos"
2069            i     -> the first metric before "pos", unless no_more_tempos is true
2070         */
2071
2072         while (beats) {
2073
2074                 /* Distance to the end of this section in frames */
2075                 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2076
2077                 /* Distance to the end in beats */
2078                 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2079
2080                 /* Amount to subtract this time */
2081                 double const sub = min (distance_beats, beats);
2082
2083                 /* Update */
2084                 beats -= sub;
2085                 pos -= sub * tempo->frames_per_beat (_frame_rate);
2086
2087                 /* Move i and tempo back, if there's anything to move to */
2088                 if (i != metrics->begin ()) {
2089                         while (i != metrics->begin ()) {
2090                                 --i;
2091                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2092                                         tempo = t;
2093                                         break;
2094                                 }
2095                         }
2096                 } else {
2097                         no_more_tempos = true;
2098                 }
2099         }
2100
2101         return pos;
2102 }
2103
2104 /** Add the BBT interval op to pos and return the result */
2105 framepos_t
2106 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2107 {
2108         Metrics::const_iterator i;
2109         const MeterSection* meter;
2110         const MeterSection* m;
2111         const TempoSection* tempo;
2112         const TempoSection* t;
2113         double frames_per_beat;
2114
2115         meter = &first_meter ();
2116         tempo = &first_tempo ();
2117
2118         assert (meter);
2119         assert (tempo);
2120
2121         /* find the starting metrics for tempo & meter */
2122
2123         for (i = metrics->begin(); i != metrics->end(); ++i) {
2124
2125                 if ((*i)->frame() > pos) {
2126                         break;
2127                 }
2128
2129                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2130                         tempo = t;
2131                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2132                         meter = m;
2133                 }
2134         }
2135
2136         /* We now have:
2137
2138            meter -> the Meter for "pos"
2139            tempo -> the Tempo for "pos"
2140            i     -> for first new metric after "pos", possibly metrics->end()
2141         */
2142
2143         /* now comes the complicated part. we have to add one beat a time,
2144            checking for a new metric on every beat.
2145         */
2146
2147         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2148
2149         uint64_t bars = 0;
2150
2151         while (op.bars) {
2152
2153                 bars++;
2154                 op.bars--;
2155
2156                 /* check if we need to use a new metric section: has adding frames moved us
2157                    to or after the start of the next metric section? in which case, use it.
2158                 */
2159
2160                 if (i != metrics->end()) {
2161                         if ((*i)->frame() <= pos) {
2162
2163                                 /* about to change tempo or meter, so add the
2164                                  * number of frames for the bars we've just
2165                                  * traversed before we change the
2166                                  * frames_per_beat value.
2167                                  */
2168                                 
2169                                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2170                                 bars = 0;
2171
2172                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2173                                         tempo = t;
2174                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2175                                         meter = m;
2176                                 }
2177                                 ++i;
2178                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2179
2180                         }
2181                 }
2182
2183         }
2184
2185         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2186
2187         uint64_t beats = 0;
2188
2189         while (op.beats) {
2190
2191                 /* given the current meter, have we gone past the end of the bar ? */
2192
2193                 beats++;
2194                 op.beats--;
2195
2196                 /* check if we need to use a new metric section: has adding frames moved us
2197                    to or after the start of the next metric section? in which case, use it.
2198                 */
2199
2200                 if (i != metrics->end()) {
2201                         if ((*i)->frame() <= pos) {
2202
2203                                 /* about to change tempo or meter, so add the
2204                                  * number of frames for the beats we've just
2205                                  * traversed before we change the
2206                                  * frames_per_beat value.
2207                                  */
2208
2209                                 pos += llrint (beats * frames_per_beat);
2210                                 beats = 0;
2211
2212                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2213                                         tempo = t;
2214                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2215                                         meter = m;
2216                                 }
2217                                 ++i;
2218                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2219                         }
2220                 }
2221         }
2222
2223         pos += llrint (beats * frames_per_beat);
2224
2225         if (op.ticks) {
2226                 if (op.ticks >= BBT_Time::ticks_per_beat) {
2227                         pos += llrint (frames_per_beat + /* extra beat */
2228                                        (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) / 
2229                                                            (double) BBT_Time::ticks_per_beat)));
2230                 } else {
2231                         pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2232                 }
2233         }
2234
2235         return pos;
2236 }
2237
2238 /** Count the number of beats that are equivalent to distance when going forward,
2239     starting at pos.
2240 */
2241 Evoral::MusicalTime
2242 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2243 {
2244         Metrics::const_iterator i;
2245         const TempoSection* tempo;
2246         
2247         /* Find the starting tempo */
2248
2249         for (i = metrics->begin(); i != metrics->end(); ++i) {
2250
2251                 if ((*i)->frame() > pos) {
2252                         break;
2253                 }
2254
2255                 const TempoSection* t;
2256
2257                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2258                         tempo = t;
2259                 }
2260         }
2261
2262         /* We now have:
2263
2264            tempo -> the Tempo for "pos"
2265            i     -> the first metric after "pos", possibly metrics->end()
2266         */
2267
2268         Evoral::MusicalTime beats = 0;
2269
2270         while (distance) {
2271
2272                 /* End of this section */
2273                 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2274
2275                 /* Distance to the end in frames */
2276                 framecnt_t const distance_to_end = end - pos;
2277
2278                 /* Amount to subtract this time */
2279                 double const sub = min (distance, distance_to_end);
2280
2281                 /* Update */
2282                 pos += sub;
2283                 distance -= sub;
2284                 beats += sub / tempo->frames_per_beat (_frame_rate);
2285
2286                 /* Move on if there's anything to move to */
2287                 if (i != metrics->end ()) {
2288                         const TempoSection* t;
2289                         
2290                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2291                                 tempo = t;
2292                         }
2293
2294                         ++i;
2295                 }
2296         }
2297
2298         return beats;
2299 }
2300
2301 /** Compare the time of this with that of another MetricSection.
2302  *  @param with_bbt True to compare using start(), false to use frame().
2303  *  @return -1 for less than, 0 for equal, 1 for greater than.
2304  */
2305
2306 int
2307 MetricSection::compare (MetricSection* other, bool with_bbt) const
2308 {
2309         if (with_bbt) {
2310                 if (start() == other->start()) {
2311                         return 0;
2312                 } else if (start() < other->start()) {
2313                         return -1;
2314                 } else {
2315                         return 1;
2316                 }
2317         } else {
2318                 if (frame() == other->frame()) {
2319                         return 0;
2320                 } else if (frame() < other->frame()) {
2321                         return -1;
2322                 } else {
2323                         return 1;
2324                 }
2325         }
2326
2327         /* NOTREACHED */
2328         return 0;
2329 }
2330
2331 std::ostream& 
2332 operator<< (std::ostream& o, const Meter& m) {
2333         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2334 }
2335 std::ostream& 
2336 operator<< (std::ostream& o, const Tempo& t) {
2337         return o << t.beats_per_minute() << " (1/" << t.note_type() << " per minute)" << endl;
2338 }
2339 std::ostream& 
2340 operator<< (std::ostream& o, const MetricSection& section) {
2341
2342         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2343
2344         const TempoSection* ts;
2345         const MeterSection* ms;
2346
2347         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2348                 o << *((Tempo*) ts);
2349         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2350                 o << *((Meter*) ms);
2351         }
2352
2353         return o;
2354 }