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