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