Fix more broken whitespace.
[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
1049         } else {
1050                 uint32_t b = bbt.beats;
1051
1052                 /* count beats */
1053                 while( b > when.beats ) {
1054
1055                         result.bars = max(1U,result.bars-- ) ;
1056                         metric = metric_at(result); // maybe there is a meter change
1057                         beats_per_bar = metric.meter().beats_per_bar();
1058                         if (b >= ceil(beats_per_bar)) {
1059
1060                                 b -= (uint32_t) ceil(beats_per_bar);
1061                         } else {
1062                                 b = (uint32_t) ceil(beats_per_bar) - b + when.beats ;
1063                         }
1064                 }
1065                 result.beats = when.beats - b;
1066
1067                 /* count ticks */
1068
1069                 if (bbt.ticks <= when.ticks) {
1070                         result.ticks = when.ticks - bbt.ticks;
1071                 } else {
1072
1073                         uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_beat;
1074                         uint32_t t = bbt.ticks - when.ticks;
1075
1076                         do {
1077
1078                                 if (result.beats == 1) {
1079                                         result.bars = max(1U, result.bars-- ) ;
1080                                         metric = metric_at(result); // maybe there is a meter change
1081                                         beats_per_bar = metric.meter().beats_per_bar();
1082                                         result.beats = (uint32_t) ceil(beats_per_bar);
1083                                         ticks_at_beat = (uint32_t) ((1 - (ceil(beats_per_bar) - beats_per_bar)) * BBT_Time::ticks_per_beat) ;
1084                                 } else {
1085                                         result.beats --;
1086                                         ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
1087                                 }
1088
1089                                 if (t <= ticks_at_beat) {
1090                                         result.ticks = ticks_at_beat - t;
1091                                 } else {
1092                                         t-= ticks_at_beat;
1093                                 }
1094                         } while (t > ticks_at_beat);
1095
1096                 }
1097
1098
1099         }
1100
1101         if (dir < 0 ) {
1102                 frames = count_frames_between( result,when);
1103         } else {
1104                 frames = count_frames_between(when,result);
1105         }
1106
1107         return frames;
1108 }
1109
1110
1111
1112 framepos_t
1113 TempoMap::round_to_bar (framepos_t fr, int dir)
1114 {
1115         {
1116                 Glib::RWLock::ReaderLock lm (lock);
1117                 return round_to_type (fr, dir, Bar);
1118         }
1119 }
1120
1121
1122 framepos_t
1123 TempoMap::round_to_beat (framepos_t fr, int dir)
1124 {
1125         {
1126                 Glib::RWLock::ReaderLock lm (lock);
1127                 return round_to_type (fr, dir, Beat);
1128         }
1129 }
1130
1131 framepos_t
1132 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1133 {
1134         BBT_Time the_beat;
1135         uint32_t ticks_one_half_subdivisions_worth;
1136         uint32_t ticks_one_subdivisions_worth;
1137         uint32_t difference;
1138
1139         bbt_time(fr, the_beat);
1140
1141         ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1142         ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1143
1144         if (dir > 0) {
1145
1146                 /* round to next */
1147
1148                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1149
1150                 if (mod == 0) {
1151                         /* right on the subdivision, so the difference is just the subdivision ticks */
1152                         difference = ticks_one_subdivisions_worth;
1153
1154                 } else {
1155                         /* not on subdivision, compute distance to next subdivision */
1156
1157                         difference = ticks_one_subdivisions_worth - mod;
1158                 }
1159
1160                 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1161
1162         } else if (dir < 0) {
1163
1164                 /* round to previous */
1165
1166                 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1167
1168                 if (mod == 0) {
1169                         /* right on the subdivision, so the difference is just the subdivision ticks */
1170                         difference = ticks_one_subdivisions_worth;
1171                 } else {
1172                         /* not on subdivision, compute distance to previous subdivision, which
1173                            is just the modulus.
1174                         */
1175
1176                         difference = mod;
1177                 }
1178
1179                 try { 
1180                         the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1181                 } catch (...) {
1182                         /* can't go backwards from wherever pos is, so just return it */
1183                         return fr;
1184                 }
1185
1186         } else {
1187                 /* round to nearest */
1188
1189                 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1190                         difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1191                         the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1192                 } else {
1193                         // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1194                         the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1195                 }
1196         }
1197
1198         return frame_time (the_beat);
1199 }
1200
1201 framepos_t
1202 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1203 {
1204         TempoMetric metric = metric_at (frame);
1205         BBT_Time bbt;
1206         BBT_Time start;
1207         BBT_Time one_bar (1,0,0);
1208         BBT_Time one_beat (0,1,0);
1209
1210         bbt_time_with_metric (frame, bbt, metric);
1211
1212         switch (type) {
1213         case Bar:
1214                 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1215
1216                 if (dir < 0) {
1217
1218                         /* find bar position preceding frame */
1219
1220                         try {
1221                                 bbt = bbt_subtract (bbt, one_bar);
1222                         }
1223
1224                         catch (...) {
1225                                 return frame;
1226                         }
1227
1228
1229                 } else if (dir > 0) {
1230
1231                         /* find bar position following frame */
1232
1233                         try {
1234                                 bbt = bbt_add (bbt, one_bar, metric);
1235                         }
1236                         catch (...) {
1237                                 return frame;
1238                         }
1239
1240                 } else {
1241
1242                         /* "true" rounding */
1243
1244                         float midbar_beats;
1245                         float midbar_ticks;
1246
1247                         midbar_beats = metric.meter().beats_per_bar() / 2 + 1;
1248                         midbar_ticks = BBT_Time::ticks_per_beat * fmod (midbar_beats, 1.0f);
1249                         midbar_beats = floor (midbar_beats);
1250                         
1251                         BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1252
1253                         if (bbt < midbar) {
1254                                 /* round down */
1255                                 bbt.beats = 1;
1256                                 bbt.ticks = 0;
1257                         } else {
1258                                 /* round up */
1259                                 bbt.bars++;
1260                                 bbt.beats = 1;
1261                                 bbt.ticks = 0;
1262                         }
1263                 }
1264                 /* force beats & ticks to their values at the start of a bar */
1265                 bbt.beats = 1;
1266                 bbt.ticks = 0;
1267                 break;
1268
1269         case Beat:
1270                 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1271
1272                 if (dir < 0) {
1273
1274                         /* find beat position preceding frame */
1275
1276                         try {
1277                                 bbt = bbt_subtract (bbt, one_beat); 
1278                         }
1279
1280                         catch (...) {
1281                                 return frame;
1282                         }
1283
1284
1285                 } else if (dir > 0) {
1286
1287                         /* find beat position following frame */
1288
1289                         try {
1290                                 bbt = bbt_add (bbt, one_beat, metric);
1291                         }
1292                         catch (...) {
1293                                 return frame;
1294                         }
1295
1296                 } else {
1297
1298                         /* "true" rounding */
1299
1300                         /* round to nearest beat */
1301                         if (bbt.ticks >= (BBT_Time::ticks_per_beat/2)) {
1302
1303                                 try {
1304                                         bbt = bbt_add (bbt, one_beat, metric);
1305                                 }
1306                                 catch (...) {
1307                                         return frame;
1308                                 }
1309                         }
1310                 }
1311                 /* force ticks to the value at the start of a beat */
1312                 bbt.ticks = 0;
1313                 break;
1314
1315         }
1316
1317         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)));
1318         return metric.frame() + count_frames_between (metric.start(), bbt);
1319 }
1320
1321 TempoMap::BBTPointList *
1322 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1323 {
1324
1325         Metrics::const_iterator i;
1326         BBTPointList *points;
1327         double current;
1328         const MeterSection* meter;
1329         const MeterSection* m;
1330         const TempoSection* tempo;
1331         const TempoSection* t;
1332         uint32_t bar;
1333         uint32_t beat;
1334         double beats_per_bar;
1335         double beat_frame;
1336         double beat_frames;
1337         double frames_per_bar;
1338         double delta_bars;
1339         double delta_beats;
1340         double dummy;
1341         framepos_t limit;
1342
1343         meter = &first_meter ();
1344         tempo = &first_tempo ();
1345
1346         /* find the starting point */
1347
1348         for (i = metrics->begin(); i != metrics->end(); ++i) {
1349
1350                 if ((*i)->frame() > lower) {
1351                         break;
1352                 }
1353
1354                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1355                         tempo = t;
1356                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1357                         meter = m;
1358                 }
1359         }
1360
1361         /* We now have:
1362
1363            meter -> the Meter for "lower"
1364            tempo -> the Tempo for "lower"
1365            i     -> for first new metric after "lower", possibly metrics->end()
1366
1367            Now start generating points.
1368         */
1369
1370         beats_per_bar = meter->beats_per_bar ();
1371         frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1372         beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
1373
1374         if (meter->frame() > tempo->frame()) {
1375                 bar = meter->start().bars;
1376                 beat = meter->start().beats;
1377                 current = meter->frame();
1378         } else {
1379                 bar = tempo->start().bars;
1380                 beat = tempo->start().beats;
1381                 current = tempo->frame();
1382         }
1383
1384         /* initialize current to point to the bar/beat just prior to the
1385            lower frame bound passed in.  assumes that current is initialized
1386            above to be on a beat.
1387         */
1388
1389         delta_bars = (lower-current) / frames_per_bar;
1390         delta_beats = modf(delta_bars, &dummy) * beats_per_bar;
1391         current += (floor(delta_bars) * frames_per_bar) +  (floor(delta_beats) * beat_frames);
1392
1393         // adjust bars and beats too
1394         bar += (uint32_t) (floor(delta_bars));
1395         beat += (uint32_t) (floor(delta_beats));
1396
1397         points = new BBTPointList;
1398
1399         do {
1400
1401                 if (i == metrics->end()) {
1402                         limit = upper;
1403                         // cerr << "== limit set to end of request @ " << limit << endl;
1404                 } else {
1405                         // cerr << "== limit set to next metric @ " << (*i)->frame() << endl;
1406                         limit = (*i)->frame();
1407                 }
1408
1409                 limit = min (limit, upper);
1410
1411                 while (current < limit) {
1412
1413                         /* if we're at the start of a bar, add bar point */
1414
1415                         if (beat == 1) {
1416                                 if (current >= lower) {
1417                                         // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
1418                                         points->push_back (BBTPoint (*meter, *tempo,(framepos_t)rint(current), Bar, bar, 1));
1419
1420                                 }
1421                         }
1422
1423                         /* add some beats if we can */
1424
1425                         beat_frame = current;
1426
1427                         while (beat <= ceil( beats_per_bar) && beat_frame < limit) {
1428                                 if (beat_frame >= lower) {
1429                                         // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
1430                                         points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
1431                                 }
1432                                 beat_frame += beat_frames;
1433                                 current+= beat_frames;
1434
1435                                 beat++;
1436                         }
1437
1438                         //  cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
1439                         // << (beat > ceil(beats_per_bar))
1440                         // << endl;
1441
1442                         if (beat > ceil(beats_per_bar) || i != metrics->end()) {
1443
1444                                 /* we walked an entire bar. its
1445                                    important to move `current' forward
1446                                    by the actual frames_per_bar, not move it to
1447                                    an integral beat_frame, so that metrics with
1448                                    non-integral beats-per-bar have
1449                                    their bar positions set
1450                                    correctly. consider a metric with
1451                                    9-1/2 beats-per-bar. the bar we
1452                                    just filled had  10 beat marks,
1453                                    but the bar end is 1/2 beat before
1454                                    the last beat mark.
1455                                    And it is also possible that a tempo
1456                                    change occured in the middle of a bar,
1457                                    so we subtract the possible extra fraction from the current
1458                                 */
1459
1460                                 if (beat > ceil (beats_per_bar)) {
1461                                         /* next bar goes where the numbers suggest */
1462                                         current -=  beat_frames * (ceil(beats_per_bar)-beats_per_bar);
1463                                         // cerr << "++ next bar from numbers\n";
1464                                 } else {
1465                                         /* next bar goes where the next metric is */
1466                                         current = limit;
1467                                         // cerr << "++ next bar at next metric\n";
1468                                 }
1469                                 bar++;
1470                                 beat = 1;
1471                         }
1472
1473                 }
1474
1475                 /* if we're done, then we're done */
1476
1477                 if (current >= upper) {
1478                         break;
1479                 }
1480
1481                 /* i is an iterator that refers to the next metric (or none).
1482                    if there is a next metric, move to it, and continue.
1483                 */
1484
1485                 if (i != metrics->end()) {
1486
1487                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1488                                 tempo = t;
1489                         } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1490                                 meter = m;
1491                                 /* new MeterSection, beat always returns to 1 */
1492                                 beat = 1;
1493                         }
1494
1495                         current = (*i)->frame ();
1496                         // cerr << "loop around with current @ " << current << endl;
1497
1498                         beats_per_bar = meter->beats_per_bar ();
1499                         frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1500                         beat_frames = tempo->frames_per_beat (_frame_rate, *meter);
1501
1502                         ++i;
1503                 }
1504
1505         } while (1);
1506
1507         return points;
1508 }
1509
1510 const TempoSection&
1511 TempoMap::tempo_section_at (framepos_t frame) const
1512 {
1513         Glib::RWLock::ReaderLock lm (lock);
1514         Metrics::const_iterator i;
1515         TempoSection* prev = 0;
1516
1517         for (i = metrics->begin(); i != metrics->end(); ++i) {
1518                 TempoSection* t;
1519
1520                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1521
1522                         if ((*i)->frame() > frame) {
1523                                 break;
1524                         }
1525
1526                         prev = t;
1527                 }
1528         }
1529
1530         if (prev == 0) {
1531                 fatal << endmsg;
1532         }
1533
1534         return *prev;
1535 }
1536
1537 const Tempo&
1538 TempoMap::tempo_at (framepos_t frame) const
1539 {
1540         TempoMetric m (metric_at (frame));
1541         return m.tempo();
1542 }
1543
1544
1545 const Meter&
1546 TempoMap::meter_at (framepos_t frame) const
1547 {
1548         TempoMetric m (metric_at (frame));
1549         return m.meter();
1550 }
1551
1552 XMLNode&
1553 TempoMap::get_state ()
1554 {
1555         Metrics::const_iterator i;
1556         XMLNode *root = new XMLNode ("TempoMap");
1557
1558         {
1559                 Glib::RWLock::ReaderLock lm (lock);
1560                 for (i = metrics->begin(); i != metrics->end(); ++i) {
1561                         root->add_child_nocopy ((*i)->get_state());
1562                 }
1563         }
1564
1565         return *root;
1566 }
1567
1568 int
1569 TempoMap::set_state (const XMLNode& node, int /*version*/)
1570 {
1571         {
1572                 Glib::RWLock::WriterLock lm (lock);
1573
1574                 XMLNodeList nlist;
1575                 XMLNodeConstIterator niter;
1576                 Metrics old_metrics (*metrics);
1577
1578                 metrics->clear();
1579
1580                 nlist = node.children();
1581
1582                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1583                         XMLNode* child = *niter;
1584
1585                         if (child->name() == TempoSection::xml_state_node_name) {
1586
1587                                 try {
1588                                         metrics->push_back (new TempoSection (*child));
1589                                 }
1590
1591                                 catch (failed_constructor& err){
1592                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1593                                         *metrics = old_metrics;
1594                                         break;
1595                                 }
1596
1597                         } else if (child->name() == MeterSection::xml_state_node_name) {
1598
1599                                 try {
1600                                         metrics->push_back (new MeterSection (*child));
1601                                 }
1602
1603                                 catch (failed_constructor& err) {
1604                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1605                                         *metrics = old_metrics;
1606                                         break;
1607                                 }
1608                         }
1609                 }
1610
1611                 if (niter == nlist.end()) {
1612
1613                         MetricSectionSorter cmp;
1614                         metrics->sort (cmp);
1615                         timestamp_metrics (true);
1616                 }
1617         }
1618
1619         PropertyChanged (PropertyChange ());
1620
1621         return 0;
1622 }
1623
1624 void
1625 TempoMap::dump (std::ostream& o) const
1626 {
1627         const MeterSection* m;
1628         const TempoSection* t;
1629
1630         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1631
1632                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1633                         o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
1634                           << t->movable() << ')' << endl;
1635                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1636                         o << "Meter @ " << *i << ' ' << m->beats_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1637                           << " (move? " << m->movable() << ')' << endl;
1638                 }
1639         }
1640 }
1641
1642 int
1643 TempoMap::n_tempos() const
1644 {
1645         Glib::RWLock::ReaderLock lm (lock);
1646         int cnt = 0;
1647
1648         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1649                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1650                         cnt++;
1651                 }
1652         }
1653
1654         return cnt;
1655 }
1656
1657 int
1658 TempoMap::n_meters() const
1659 {
1660         Glib::RWLock::ReaderLock lm (lock);
1661         int cnt = 0;
1662
1663         for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1664                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1665                         cnt++;
1666                 }
1667         }
1668
1669         return cnt;
1670 }
1671
1672 void
1673 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1674 {
1675         for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1676                 if ((*i)->frame() >= where) {
1677                         (*i)->set_frame ((*i)->frame() + amount);
1678                 }
1679         }
1680
1681         timestamp_metrics (false);
1682
1683         PropertyChanged (PropertyChange ());
1684 }
1685
1686 BBT_Time
1687 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1688 {
1689         TempoMetric metric =  metric_at (start);
1690         return bbt_add (start, other, metric);
1691 }
1692
1693 /**
1694  * add the BBT interval @param increment to  @param start and return the result
1695  */
1696 BBT_Time
1697 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1698 {
1699         BBT_Time result = start;
1700         BBT_Time op = increment; /* argument is const, but we need to modify it */
1701         uint32_t ticks = result.ticks + op.ticks;
1702
1703         if (ticks >= BBT_Time::ticks_per_beat) {
1704                 op.beats++;
1705                 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_beat;
1706         } else {
1707                 result.ticks += op.ticks;
1708         }
1709
1710         /* now comes the complicated part. we have to add one beat a time,
1711            checking for a new metric on every beat.
1712         */
1713         
1714         /* grab all meter sections */
1715         
1716         list<const MeterSection*> meter_sections;
1717         
1718         for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1719                 const MeterSection* ms;
1720                 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1721                         meter_sections.push_back (ms);
1722                 }
1723         }
1724         
1725         assert (!meter_sections.empty());
1726         
1727         list<const MeterSection*>::const_iterator next_meter;
1728         const Meter* meter = 0;
1729         
1730         /* go forwards through the meter sections till we get to the one
1731            covering the current value of result. this positions i to point to 
1732            the next meter section too, or the end.
1733         */
1734         
1735         for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1736                 
1737                 if (result < (*next_meter)->start()) {
1738                         /* this metric is past the result time. stop looking, we have what we need */
1739                         break;
1740                 }
1741
1742                 if (result == (*next_meter)->start()) {
1743                         /* this meter section starts at result, push i beyond it so that it points
1744                            to the NEXT section, opwise we will get stuck later, and use this meter section.
1745                         */
1746                         meter = *next_meter;
1747                         ++next_meter;
1748                         break;
1749                 }
1750                 
1751                 meter = *next_meter;
1752         }
1753         
1754         assert (meter != 0);
1755                 
1756         /* OK, now have the meter for the bar start we are on, and i is an iterator 
1757            that points to the metric after the one we are currently dealing with 
1758            (or to metrics->end(), of course) 
1759         */
1760         
1761         while (op.beats) {
1762                 
1763                 /* given the current meter, have we gone past the end of the bar ? */
1764                 
1765                 if (result.beats >= meter->beats_per_bar()) {
1766                         /* move to next bar, first beat */
1767                         result.bars++;
1768                         result.beats = 1;
1769                 } else {
1770                         result.beats++;
1771                 }
1772                 
1773                 /* one down ... */
1774                 
1775                 op.beats--;
1776                 
1777                 /* check if we need to use a new meter section: has adding beats to result taken us 
1778                    to or after the start of the next meter section? in which case, use it.
1779                 */
1780
1781                 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1782                         meter = *next_meter;
1783                         ++next_meter;
1784                 }
1785         }
1786
1787         /* finally, add bars */
1788
1789         result.bars += op.bars++;
1790
1791         return result;
1792 }
1793
1794 /**
1795  * subtract the BBT interval @param decrement from @param start and return the result
1796  */
1797 BBT_Time
1798 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1799 {
1800         BBT_Time result = start;
1801         BBT_Time op = decrement; /* argument is const, but we need to modify it */
1802
1803         if (op.ticks > result.ticks) {
1804                 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
1805                 op.beats++;
1806                 result.ticks = BBT_Time::ticks_per_beat - (op.ticks - result.ticks);
1807         } else {
1808                 result.ticks -= op.ticks;
1809         }
1810
1811         /* now comes the complicated part. we have to subtract one beat a time,
1812            checking for a new metric on every beat.
1813         */
1814         
1815         /* grab all meter sections */
1816         
1817         list<const MeterSection*> meter_sections;
1818         
1819         for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1820                 const MeterSection* ms;
1821                 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1822                         meter_sections.push_back (ms);
1823                 }
1824                 }
1825         
1826         assert (!meter_sections.empty());
1827         
1828         /* go backwards through the meter sections till we get to the one
1829            covering the current value of result. this positions i to point to 
1830            the next (previous) meter section too, or the end.
1831         */
1832         
1833         const MeterSection* meter = 0;
1834         list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't 
1835                                                                 // support const_reverse_iterator::operator!=()
1836         
1837         for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
1838                 
1839                 /* when we find the first meter section that is before or at result, use it,
1840                    and set next_meter to the previous one 
1841                 */
1842                 
1843                 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
1844                         meter = *next_meter;
1845                         ++next_meter;
1846                         break;
1847                 }
1848         }
1849
1850         assert (meter != 0);
1851         
1852         /* OK, now have the meter for the bar start we are on, and i is an iterator 
1853            that points to the metric after the one we are currently dealing with 
1854            (or to metrics->end(), of course) 
1855         */
1856         
1857         while (op.beats) {
1858
1859                 /* have we reached the start of the bar? if so, move to the last beat of the previous
1860                    bar. opwise, just step back 1 beat.
1861                 */
1862                 
1863                 if (result.beats == 1) {
1864                         
1865                         /* move to previous bar, last beat */
1866                         
1867                         if (result.bars <= 1) {
1868                                 /* i'm sorry dave, i can't do that */
1869                                 throw std::out_of_range ("illegal BBT subtraction");
1870                         }
1871                         
1872                         result.bars--;
1873                         result.beats = meter->beats_per_bar();
1874                 } else {
1875
1876                         /* back one beat */
1877
1878                         result.beats--;
1879                 }
1880                 
1881                 /* one down ... */
1882                 op.beats--;
1883                 
1884                 /* check if we need to use a new meter section: has subtracting beats to result taken us 
1885                    to before the start of the current meter section? in which case, use the prior one.
1886                 */
1887
1888                 if (result < meter->start() && next_meter != meter_sections.rend()) {
1889                         meter = *next_meter;
1890                         ++next_meter;
1891                 }
1892         }
1893
1894         /* finally, subtract bars */
1895
1896         if (op.bars >= result.bars) {
1897                 /* i'm sorry dave, i can't do that */
1898                 throw std::out_of_range ("illegal BBT subtraction");
1899         }
1900
1901         result.bars -= op.bars;
1902         return result;
1903 }
1904
1905 /** Add the BBT interval op to pos and return the result */
1906 framepos_t
1907 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
1908 {
1909         /* XXX: this is a little inaccurate as small errors are introduced
1910            every time a probably-fractional product of something and
1911            frames_per_beat is rounded.  Other errors can be introduced
1912            by op.ticks' integer nature.
1913         */
1914         
1915         Metrics::const_iterator i;
1916         const MeterSection* meter;
1917         const MeterSection* m;
1918         const TempoSection* tempo;
1919         const TempoSection* t;
1920         framecnt_t frames_per_beat;
1921
1922         meter = &first_meter ();
1923         tempo = &first_tempo ();
1924
1925         assert (meter);
1926         assert (tempo);
1927
1928         /* find the starting metrics for tempo & meter */
1929
1930         for (i = metrics->begin(); i != metrics->end(); ++i) {
1931
1932                 if ((*i)->frame() > pos) {
1933                         break;
1934                 }
1935
1936                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1937                         tempo = t;
1938                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1939                         meter = m;
1940                 }
1941         }
1942
1943         /* We now have:
1944
1945            meter -> the Meter for "pos"
1946            tempo -> the Tempo for "pos"
1947            i     -> for first new metric after "pos", possibly metrics->end()
1948         */
1949
1950         /* now comes the complicated part. we have to add one beat a time,
1951            checking for a new metric on every beat.
1952         */
1953         
1954         frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
1955
1956         while (op.bars) {
1957
1958                 pos += llrint (frames_per_beat * meter->beats_per_bar());
1959                 op.bars--;
1960                 
1961                 /* check if we need to use a new metric section: has adding frames moved us
1962                    to or after the start of the next metric section? in which case, use it.
1963                 */
1964
1965                 if (i != metrics->end()) {
1966                         if ((*i)->frame() <= pos) {
1967
1968                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1969                                         tempo = t;
1970                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1971                                         meter = m;
1972                                 }
1973                                 ++i;
1974                                 frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
1975
1976                         }
1977                 }
1978
1979         }
1980
1981         while (op.beats) {
1982                 
1983                 /* given the current meter, have we gone past the end of the bar ? */
1984
1985                 pos += frames_per_beat;
1986                 op.beats--;
1987                 
1988                 /* check if we need to use a new metric section: has adding frames moved us
1989                    to or after the start of the next metric section? in which case, use it.
1990                 */
1991
1992                 if (i != metrics->end()) {
1993                         if ((*i)->frame() <= pos) {
1994
1995                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1996                                         tempo = t;
1997                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1998                                         meter = m;
1999                                 }
2000                                 ++i;
2001                                 frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter); 
2002                         }
2003                 }
2004         }
2005
2006         if (op.ticks) {
2007                 if (op.ticks >= BBT_Time::ticks_per_beat) {
2008                         pos += frames_per_beat;
2009                         pos += llrint (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) / (double) BBT_Time::ticks_per_beat));
2010                 } else {
2011                         pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2012                 }
2013         }
2014
2015         return pos;
2016 }
2017
2018 /** Count the number of beats that are equivalent to distance when starting at pos */
2019 double
2020 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2021 {
2022         Metrics::const_iterator i;
2023         double beats = 0;
2024         const MeterSection* meter;
2025         const MeterSection* m;
2026         const TempoSection* tempo;
2027         const TempoSection* t;
2028         double frames_per_beat;
2029
2030         double ddist = distance;
2031         double dpos = pos;
2032
2033         meter = &first_meter ();
2034         tempo = &first_tempo ();
2035
2036         assert (meter);
2037         assert (tempo);
2038
2039         /* find the starting metrics for tempo & meter */
2040
2041         for (i = metrics->begin(); i != metrics->end(); ++i) {
2042
2043                 if ((*i)->frame() > pos) {
2044                         break;
2045                 }
2046
2047                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2048                         tempo = t;
2049                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2050                         meter = m;
2051                 }
2052         }
2053
2054         /* We now have:
2055
2056            meter -> the Meter for "pos"
2057            tempo -> the Tempo for "pos"
2058            i     -> for first new metric after "pos", possibly metrics->end()
2059         */
2060
2061         /* now comes the complicated part. we have to add one beat a time,
2062            checking for a new metric on every beat.
2063         */
2064         
2065         frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
2066
2067         while (ddist > 0) {
2068
2069                 /* if we're nearly at the end, but have a fractional beat left,
2070                    compute the fraction and then its all over
2071                 */
2072
2073                 if (ddist < frames_per_beat) {
2074                         beats += ddist / frames_per_beat;
2075                         break;
2076                 }
2077
2078                 /* walk one beat */
2079
2080                 ddist -= frames_per_beat;
2081                 dpos += frames_per_beat;
2082                 beats += 1.0;
2083
2084                 /* check if we need to use a new metric section: has adding frames moved us
2085                    to or after the start of the next metric section? in which case, use it.
2086                 */
2087
2088                 if (i != metrics->end()) {
2089                         if ((*i)->frame() <= (framepos_t) dpos) {
2090
2091                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2092                                         tempo = t;
2093                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2094                                         meter = m;
2095                                 }
2096                                 ++i;
2097                                 frames_per_beat = tempo->frames_per_beat (_frame_rate, *meter);
2098                         }
2099                 }
2100
2101         }
2102
2103         return beats;
2104 }
2105
2106
2107 /** Compare the time of this with that of another MetricSection.
2108  *  @param with_bbt True to compare using ::start(), false to use ::frame().
2109  *  @return -1 for less than, 0 for equal, 1 for greater than.
2110  */
2111
2112 int
2113 MetricSection::compare (MetricSection* other, bool with_bbt) const
2114 {
2115         if (with_bbt) {
2116                 if (start() == other->start()) {
2117                         return 0;
2118                 } else if (start() < other->start()) {
2119                         return -1;
2120                 } else {
2121                         return 1;
2122                 }
2123         } else {
2124                 if (frame() == other->frame()) {
2125                         return 0;
2126                 } else if (frame() < other->frame()) {
2127                         return -1;
2128                 } else {
2129                         return 1;
2130                 }
2131         }
2132
2133         /* NOTREACHED */
2134         return 0;
2135 }