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