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