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