Tempo ramps - use consistent naming for _locked methods, use enum_2_string for TempoS...
[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 #include <cmath>
23
24 #include <unistd.h>
25
26 #include <glibmm/threads.h>
27
28 #include "pbd/enumwriter.h"
29 #include "pbd/xml++.h"
30 #include "evoral/Beats.hpp"
31
32 #include "ardour/debug.h"
33 #include "ardour/lmath.h"
34 #include "ardour/tempo.h"
35
36 #include "i18n.h"
37 #include <locale.h>
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace PBD;
42
43 using Timecode::BBT_Time;
44
45 /* _default tempo is 4/4 qtr=120 */
46
47 Meter    TempoMap::_default_meter (4.0, 4.0);
48 Tempo    TempoMap::_default_tempo (120.0);
49
50 /***********************************************************************/
51
52 double
53 Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
54 {
55         /* This is tempo- and meter-sensitive. The number it returns
56            is based on the interval between any two lines in the
57            grid that is constructed from tempo and meter sections.
58
59            The return value IS NOT interpretable in terms of "beats".
60         */
61
62         return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
63 }
64
65 double
66 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
67 {
68         return frames_per_grid (tempo, sr) * _divisions_per_bar;
69 }
70
71
72 /***********************************************************************/
73
74 const string TempoSection::xml_state_node_name = "Tempo";
75
76 TempoSection::TempoSection (const XMLNode& node)
77         : MetricSection (0.0), Tempo (TempoMap::default_tempo())
78 {
79         const XMLProperty *prop;
80         LocaleGuard lg;
81         BBT_Time bbt;
82         double beat;
83
84         if ((prop = node.property ("start")) != 0) {
85                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
86                             &bbt.bars,
87                             &bbt.beats,
88                             &bbt.ticks) == 3) {
89                         /* legacy session - start used to be in bbt*/
90                         _legacy_bbt = bbt;
91                         beat = -1.0;
92                         set_beat (beat);
93                 }
94         } else {
95                 warning << _("TempoSection XML node has no \"start\" property") << endmsg;
96         }
97
98
99         if ((prop = node.property ("beat")) != 0) {
100                 if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) {
101                         error << _("TempoSection XML node has an illegal \"beat\" value") << endmsg;
102                 } else {
103                         set_beat (beat);
104                 }
105         } else {
106                 error << _("TempoSection XML node has no \"beat\" property") << endmsg;
107         }
108
109
110         if ((prop = node.property ("beats-per-minute")) == 0) {
111                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
112                 throw failed_constructor();
113         }
114
115         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
116                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
117                 throw failed_constructor();
118         }
119
120         if ((prop = node.property ("note-type")) == 0) {
121                 /* older session, make note type be quarter by default */
122                 _note_type = 4.0;
123         } else {
124                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
125                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
126                         throw failed_constructor();
127                 }
128         }
129
130         if ((prop = node.property ("movable")) == 0) {
131                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
132                 throw failed_constructor();
133         }
134
135         set_movable (string_is_affirmative (prop->value()));
136
137         if ((prop = node.property ("bar-offset")) == 0) {
138                 _bar_offset = -1.0;
139         } else {
140                 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
141                         error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
142                         throw failed_constructor();
143                 }
144         }
145
146         if ((prop = node.property ("tempo-type")) == 0) {
147                 _type = Constant;
148         } else {
149                 _type = Type (string_2_enum (prop->value(), _type));
150         }
151 }
152
153 XMLNode&
154 TempoSection::get_state() const
155 {
156         XMLNode *root = new XMLNode (xml_state_node_name);
157         char buf[256];
158         LocaleGuard lg;
159
160         snprintf (buf, sizeof (buf), "%f", beat());
161         root->add_property ("beat", buf);
162         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
163         root->add_property ("beats-per-minute", buf);
164         snprintf (buf, sizeof (buf), "%f", _note_type);
165         root->add_property ("note-type", buf);
166         // snprintf (buf, sizeof (buf), "%f", _bar_offset);
167         // root->add_property ("bar-offset", buf);
168         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
169         root->add_property ("movable", buf);
170         root->add_property ("tempo-type", enum_2_string (_type));
171
172         return *root;
173 }
174
175 void
176
177 TempoSection::update_bar_offset_from_bbt (const Meter& m)
178 {
179         _bar_offset = (beat() * BBT_Time::ticks_per_beat) /
180                 (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
181
182         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, beat(), m.divisions_per_bar()));
183 }
184
185 void
186 TempoSection::set_type (Type type)
187 {
188         _type = type;
189 }
190
191 /** returns the tempo at the zero-based (relative to tempo section) frame.
192 */
193 double
194 TempoSection::tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
195 {
196
197         if (_type == Constant) {
198                 return beats_per_minute();
199         }
200
201         return tick_tempo_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)) / BBT_Time::ticks_per_beat;
202 }
203
204 /** returns the zero-based frame (relative to tempo section)
205    where the tempo occurs.
206 */
207 framepos_t
208 TempoSection::frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
209 {
210         if (_type == Constant) {
211                 return 0;
212         }
213
214         return minute_to_frame (time_at_tick_tempo (tempo *  BBT_Time::ticks_per_beat,  end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
215 }
216
217 /** returns the zero-based tick (relative to tempo section)
218    where the zero-based frame (relative to tempo section)
219    lies.
220 */
221 double
222 TempoSection::tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
223 {
224         if (_type == Constant) {
225                 return (frame / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat;
226         }
227
228         return tick_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate));
229 }
230
231 /** returns the zero-based frame (relative to tempo section)
232    where the zero-based tick (relative to tempo section)
233    falls.
234 */
235 framepos_t
236 TempoSection::frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
237 {
238         if (_type == Constant) {
239                 return (framepos_t) floor ((tick  / BBT_Time::ticks_per_beat) * frames_per_beat (frame_rate));
240         }
241
242         return minute_to_frame (time_at_tick (tick, end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
243 }
244
245 /** returns the zero-based beat (relative to tempo section)
246    where the zero-based frame (relative to tempo section)
247    lies.
248 */
249 double
250 TempoSection::beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
251 {
252         return tick_at_frame (frame, end_bpm, end_frame, frame_rate) / BBT_Time::ticks_per_beat;
253 }
254
255 /** returns the zero-based frame (relative to tempo section start frame)
256    where the zero-based beat (relative to tempo section start)
257    falls.
258 */
259
260 framepos_t
261 TempoSection::frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
262 {
263         return frame_at_tick (beat * BBT_Time::ticks_per_beat, end_bpm, end_frame, frame_rate);
264 }
265
266 framecnt_t
267 TempoSection::minute_to_frame (double time, framecnt_t frame_rate) const
268 {
269         return time * 60.0 * frame_rate;
270 }
271
272 double
273 TempoSection::frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const
274 {
275         return (frame / (double) frame_rate) / 60.0;
276 }
277
278 /* position function */
279 double
280 TempoSection::a_func (double end_tpm, double c_func) const
281 {
282         return log (end_tpm / ticks_per_minute()) /  c_func;
283 }
284
285 /*function constant*/
286 double
287 TempoSection::c_func (double end_tpm, double end_time) const
288 {
289         return log (end_tpm / ticks_per_minute()) /  end_time;
290 }
291
292 /* tempo in tpm at time in minutes */
293 double
294 TempoSection::tick_tempo_at_time (double time, double end_tpm, double end_time) const
295 {
296         return exp (c_func (end_tpm, end_time) * time) * ticks_per_minute();
297 }
298
299 /* time in minutes at tempo in tpm */
300 double
301 TempoSection::time_at_tick_tempo (double tick_tempo, double end_tpm, double end_time) const
302 {
303         return log (tick_tempo / ticks_per_minute()) / c_func (end_tpm, end_time);
304 }
305
306 /* tick at time in minutes */
307 double
308 TempoSection::tick_at_time (double time, double end_tpm, double end_time) const
309 {
310         return ((exp (c_func (end_tpm, end_time) * time)) - 1) * ticks_per_minute() / c_func (end_tpm, end_time);
311 }
312
313 /* time in minutes at tick */
314 double
315 TempoSection::time_at_tick (double tick, double end_tpm, double end_time) const
316 {
317         return log (((c_func (end_tpm, end_time) * tick) / ticks_per_minute()) + 1) / c_func (end_tpm, end_time);
318 }
319
320 /* beat at time in minutes */
321 double
322 TempoSection::beat_at_time (double time, double end_tpm, double end_time) const
323 {
324         return tick_at_time (time, end_tpm, end_time) / BBT_Time::ticks_per_beat;
325 }
326
327 /* time in munutes at beat */
328 double
329 TempoSection::time_at_beat (double beat, double end_tpm, double end_time) const
330 {
331         return time_at_tick (beat * BBT_Time::ticks_per_beat, end_tpm, end_time);
332 }
333
334 void
335 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
336 {
337         double new_beat;
338
339         if (_bar_offset < 0.0) {
340                 /* not set yet */
341                 return;
342         }
343
344         new_beat = beat();
345
346         double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
347         new_beat = ticks / BBT_Time::ticks_per_beat;
348
349         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
350                                                        _bar_offset, meter.divisions_per_bar(), ticks, new_beat, new_beat));
351
352         set_beat (new_beat);
353 }
354
355 /***********************************************************************/
356
357 const string MeterSection::xml_state_node_name = "Meter";
358
359 MeterSection::MeterSection (const XMLNode& node)
360         : MetricSection (0.0), Meter (TempoMap::default_meter())
361 {
362         XMLProperty const * prop;
363         BBT_Time start;
364         LocaleGuard lg;
365         const XMLProperty *prop;
366         BBT_Time bbt;
367         double beat = 0.0;
368         pair<double, BBT_Time> start;
369
370         if ((prop = node.property ("start")) != 0) {
371                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
372                     &bbt.bars,
373                     &bbt.beats,
374                     &bbt.ticks) < 3) {
375                         error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
376                 } else {
377                         /* legacy session - start used to be in bbt*/
378                         beat = -1.0;
379                 }
380         } else {
381                 error << _("MeterSection XML node has no \"start\" property") << endmsg;
382         }
383
384         if ((prop = node.property ("beat")) != 0) {
385                 if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) {
386                         error << _("MeterSection XML node has an illegal \"beat\" value") << endmsg;
387                 }
388         } else {
389                 error << _("MeterSection XML node has no \"beat\" property") << endmsg;
390         }
391
392         start.first = beat;
393
394         if ((prop = node.property ("bbt")) == 0) {
395                 error << _("MeterSection XML node has no \"bbt\" property") << endmsg;
396         } else if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
397                     &bbt.bars,
398                     &bbt.beats,
399                     &bbt.ticks) < 3) {
400                 error << _("MeterSection XML node has an illegal \"bbt\" value") << endmsg;
401                 throw failed_constructor();
402         }
403
404         start.second = bbt;
405
406         set_beat (start);
407
408         /* beats-per-bar is old; divisions-per-bar is new */
409
410         if ((prop = node.property ("divisions-per-bar")) == 0) {
411                 if ((prop = node.property ("beats-per-bar")) == 0) {
412                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
413                         throw failed_constructor();
414                 }
415         }
416
417         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
418                 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
419                 throw failed_constructor();
420         }
421
422         if ((prop = node.property ("note-type")) == 0) {
423                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
424                 throw failed_constructor();
425         }
426
427         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
428                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
429                 throw failed_constructor();
430         }
431
432         if ((prop = node.property ("movable")) == 0) {
433                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
434                 throw failed_constructor();
435         }
436
437         set_movable (string_is_affirmative (prop->value()));
438 }
439
440 XMLNode&
441 MeterSection::get_state() const
442 {
443         XMLNode *root = new XMLNode (xml_state_node_name);
444         char buf[256];
445         LocaleGuard lg;
446
447         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
448                   bbt().bars,
449                   bbt().beats,
450                   bbt().ticks);
451         root->add_property ("bbt", buf);
452         snprintf (buf, sizeof (buf), "%lf", beat());
453         root->add_property ("beat", buf);
454         snprintf (buf, sizeof (buf), "%f", _note_type);
455         root->add_property ("note-type", buf);
456         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
457         root->add_property ("divisions-per-bar", buf);
458         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
459         root->add_property ("movable", buf);
460
461         return *root;
462 }
463
464 /***********************************************************************/
465
466 struct MetricSectionSorter {
467     bool operator() (const MetricSection* a, const MetricSection* b) {
468             return a->beat() < b->beat();
469     }
470 };
471
472 struct MetricSectionFrameSorter {
473     bool operator() (const MetricSection* a, const MetricSection* b) {
474             return a->frame() < b->frame();
475     }
476 };
477
478 TempoMap::TempoMap (framecnt_t fr)
479 {
480         _frame_rate = fr;
481         BBT_Time start;
482
483         start.bars = 1;
484         start.beats = 1;
485         start.ticks = 0;
486
487         TempoSection *t = new TempoSection (0.0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Constant);
488         MeterSection *m = new MeterSection (0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
489
490         t->set_movable (false);
491         m->set_movable (false);
492
493         /* note: frame time is correct (zero) for both of these */
494
495         metrics.push_back (t);
496         metrics.push_back (m);
497
498 }
499
500 TempoMap::~TempoMap ()
501 {
502 }
503
504 void
505 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
506 {
507         bool removed = false;
508
509         {
510                 Glib::Threads::RWLock::WriterLock lm (lock);
511                 if ((removed = remove_tempo_locked (tempo))) {
512                         if (complete_operation) {
513                                 recompute_map (true);
514                         }
515                 }
516         }
517
518         if (removed && complete_operation) {
519                 PropertyChanged (PropertyChange ());
520         }
521 }
522
523 bool
524 TempoMap::remove_tempo_locked (const TempoSection& tempo)
525 {
526         Metrics::iterator i;
527
528         for (i = metrics.begin(); i != metrics.end(); ++i) {
529                 if (dynamic_cast<TempoSection*> (*i) != 0) {
530                         if (tempo.frame() == (*i)->frame()) {
531                                 if ((*i)->movable()) {
532                                         metrics.erase (i);
533                                         return true;
534                                 }
535                         }
536                 }
537         }
538
539         return false;
540 }
541
542 void
543 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
544 {
545         bool removed = false;
546
547         {
548                 Glib::Threads::RWLock::WriterLock lm (lock);
549                 if ((removed = remove_meter_locked (tempo))) {
550                         if (complete_operation) {
551                                 recompute_map (true);
552                         }
553                 }
554         }
555
556         if (removed && complete_operation) {
557                 PropertyChanged (PropertyChange ());
558         }
559 }
560
561 bool
562 TempoMap::remove_meter_locked (const MeterSection& tempo)
563 {
564         Metrics::iterator i;
565
566         for (i = metrics.begin(); i != metrics.end(); ++i) {
567                 if (dynamic_cast<MeterSection*> (*i) != 0) {
568                         if (tempo.frame() == (*i)->frame()) {
569                                 if ((*i)->movable()) {
570                                         metrics.erase (i);
571                                         return true;
572                                 }
573                         }
574                 }
575         }
576
577         return false;
578 }
579
580 void
581 TempoMap::do_insert (MetricSection* section)
582 {
583         bool need_add = true;
584
585         /* we only allow new meters to be inserted on beat 1 of an existing
586          * measure.
587          */
588         MeterSection* m = 0;
589         if ((m = dynamic_cast<MeterSection*>(section)) != 0) {
590                 assert (m->bbt().ticks == 0);
591
592                 /* we need to (potentially) update the BBT times of tempo
593                    sections based on this new meter.
594                 */
595
596                 if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
597
598                         pair<double, BBT_Time> corrected = make_pair (m->beat(), m->bbt());
599                         corrected.second.beats = 1;
600                         corrected.second.ticks = 0;
601                         corrected.first = bbt_to_beats_locked (corrected.second);
602                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
603                                                    m->bbt(), corrected.second) << endmsg;
604                         m->set_beat (corrected);
605                 }
606         }
607
608
609
610         /* Look for any existing MetricSection that is of the same type and
611            in the same bar as the new one, and remove it before adding
612            the new one. Note that this means that if we find a matching,
613            existing section, we can break out of the loop since we're
614            guaranteed that there is only one such match.
615         */
616
617         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
618
619                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
620                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
621
622                 if (tempo && insert_tempo) {
623
624                         /* Tempo sections */
625
626                         if (tempo->beat() == insert_tempo->beat()) {
627
628                                 if (!tempo->movable()) {
629
630                                         /* can't (re)move this section, so overwrite
631                                          * its data content (but not its properties as
632                                          * a section).
633                                          */
634
635                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo));
636                                         need_add = false;
637                                 } else {
638                                         metrics.erase (i);
639                                 }
640                                 break;
641                         }
642
643                 } else if (!tempo && !insert_tempo) {
644
645                         /* Meter Sections */
646                         MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
647                         MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
648                         if (meter->beat() == insert_meter->beat()) {
649
650                                 if (!meter->movable()) {
651
652                                         /* can't (re)move this section, so overwrite
653                                          * its data content (but not its properties as
654                                          * a section
655                                          */
656
657                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
658                                         need_add = false;
659                                 } else {
660                                         metrics.erase (i);
661
662                                 }
663
664                                 break;
665                         }
666                 } else {
667                         /* non-matching types, so we don't care */
668                 }
669         }
670
671         /* Add the given MetricSection, if we didn't just reset an existing
672          * one above
673          */
674
675         if (need_add) {
676                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
677                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
678
679                 Metrics::iterator i;
680                 if (insert_meter) {
681                         for (i = metrics.begin(); i != metrics.end(); ++i) {
682                                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
683
684                                 if (meter && meter->beat() > insert_meter->beat()) {
685                                         break;
686                                 }
687                         }
688                 } else if (insert_tempo) {
689                         for (i = metrics.begin(); i != metrics.end(); ++i) {
690                                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
691
692                                 if (tempo) {
693                                         if (tempo->beat() > insert_tempo->beat()) {
694                                                 break;
695                                         }
696                                 }
697                         }
698                 }
699
700                 metrics.insert (i, section);
701         }
702 }
703
704 void
705 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& where, TempoSection::Type type)
706 {
707         {
708                 Glib::Threads::RWLock::WriterLock lm (lock);
709                 TempoSection& first (first_tempo());
710
711                 if (ts.beat() != first.beat()) {
712                         remove_tempo_locked (ts);
713                         add_tempo_locked (tempo, where, true, type);
714                 } else {
715                         first.set_type (type);
716                         {
717                                 /* cannot move the first tempo section */
718                                 *static_cast<Tempo*>(&first) = tempo;
719                                 recompute_map (false);
720                         }
721                 }
722         }
723
724         PropertyChanged (PropertyChange ());
725 }
726
727 void
728 TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame, double  beat_where)
729 {
730         {
731                 Glib::Threads::RWLock::WriterLock lm (lock);
732
733                 /* currently this is always done in audio time */
734                 //if (ts.position_lock_style() == MusicTime) {
735                 if (0) {
736                         /* MusicTime */
737                         ts.set_beat (beat_where);
738                         MetricSectionSorter cmp;
739                         metrics.sort (cmp);
740                 } else {
741                         /*AudioTime*/
742                         ts.set_frame (frame);
743
744                         MetricSectionFrameSorter fcmp;
745                         metrics.sort (fcmp);
746
747                         Metrics::const_iterator i;
748                         TempoSection* prev_ts = 0;
749                         TempoSection* next_ts = 0;
750
751                         for (i = metrics.begin(); i != metrics.end(); ++i) {
752                                 TempoSection* t;
753                                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
754
755                                         if (t->frame() >= frame) {
756                                                 break;
757                                         }
758
759                                         prev_ts = t;
760                                 }
761                         }
762
763                         for (i = metrics.begin(); i != metrics.end(); ++i) {
764                                 TempoSection* t;
765                                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
766
767                                         if (t->frame() > frame) {
768                                                 next_ts = t;
769                                                 break;
770                                         }
771                                 }
772                         }
773
774                         if (prev_ts) {
775                                 /* set the start beat */
776                                 double beats_to_ts = prev_ts->beat_at_frame (frame - prev_ts->frame(), ts.beats_per_minute(), frame - prev_ts->frame(), _frame_rate);
777                                 double beats = beats_to_ts + prev_ts->beat();
778
779                                 if (next_ts) {
780                                         if (next_ts->beat() < beats) {
781                                                 /* with frame-based editing, it is possible to get in a
782                                                    situation where if the tempo was placed at the mouse pointer frame,
783                                                    the following music-based tempo would jump to an earlier frame,
784                                                    changing the beat beat of the moved tempo.
785                                                    in this case, we have to do some beat-based comparison TODO
786                                                 */
787                                         } else if (prev_ts->beat() > beats) {
788                                                 ts.set_beat (prev_ts->beat());
789                                         } else {
790                                                 ts.set_beat (beats);
791                                         }
792                                 } else {
793                                         ts.set_beat (beats);
794                                 }
795                                 MetricSectionSorter cmp;
796                                 metrics.sort (cmp);
797                         }
798                 }
799
800                 recompute_map (false);
801         }
802
803         MetricPositionChanged (); // Emit Signal
804 }
805
806 void
807 TempoMap::add_tempo (const Tempo& tempo, double where, ARDOUR::TempoSection::Type type)
808 {
809         {
810                 Glib::Threads::RWLock::WriterLock lm (lock);
811                 add_tempo_locked (tempo, where, true, type);
812         }
813
814
815         PropertyChanged (PropertyChange ());
816 }
817
818 void
819 TempoMap::add_tempo_locked (const Tempo& tempo, double where, bool recompute, ARDOUR::TempoSection::Type type)
820 {
821         TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
822
823         do_insert (ts);
824
825         if (recompute) {
826                 recompute_map (false);
827         }
828 }
829
830 void
831 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
832 {
833         {
834                 Glib::Threads::RWLock::WriterLock lm (lock);
835                 MeterSection& first (first_meter());
836                 if (ms.beat() != first.beat()) {
837                         remove_meter_locked (ms);
838                         add_meter_locked (meter, bbt_to_beats_locked (where), where, true);
839                 } else {
840                         /* cannot move the first meter section */
841                         *static_cast<Meter*>(&first) = meter;
842                         recompute_map (true);
843                 }
844         }
845
846         PropertyChanged (PropertyChange ());
847 }
848
849 void
850 TempoMap::add_meter (const Meter& meter, double beat, BBT_Time where)
851 {
852         {
853                 Glib::Threads::RWLock::WriterLock lm (lock);
854                 add_meter_locked (meter, beat, where, true);
855         }
856
857
858 #ifndef NDEBUG
859         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
860                 dump (std::cerr);
861         }
862 #endif
863
864         PropertyChanged (PropertyChange ());
865 }
866
867 void
868 TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, bool recompute)
869 {
870         /* a new meter always starts a new bar on the first beat. so
871            round the start time appropriately. remember that
872            `where' is based on the existing tempo map, not
873            the result after we insert the new meter.
874
875         */
876
877         if (where.beats != 1) {
878                 where.beats = 1;
879                 where.bars++;
880         }
881
882         /* new meters *always* start on a beat. */
883         where.ticks = 0;
884
885         do_insert (new MeterSection (beat, where, meter.divisions_per_bar(), meter.note_divisor()));
886
887         if (recompute) {
888                 recompute_map (true);
889         }
890
891 }
892
893 void
894 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
895 {
896         Tempo newtempo (beats_per_minute, note_type);
897         TempoSection* t;
898
899         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
900                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
901                         {
902                                 Glib::Threads::RWLock::WriterLock lm (lock);
903                                 *((Tempo*) t) = newtempo;
904                                 recompute_map (false);
905                         }
906                         PropertyChanged (PropertyChange ());
907                         break;
908                 }
909         }
910 }
911
912 void
913 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
914 {
915         Tempo newtempo (beats_per_minute, note_type);
916
917         TempoSection* prev;
918         TempoSection* first;
919         Metrics::iterator i;
920
921         /* find the TempoSection immediately preceding "where"
922          */
923
924         for (first = 0, i = metrics.begin(), prev = 0; i != metrics.end(); ++i) {
925
926                 if ((*i)->frame() > where) {
927                         break;
928                 }
929
930                 TempoSection* t;
931
932                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
933                         if (!first) {
934                                 first = t;
935                         }
936                         prev = t;
937                 }
938         }
939
940         if (!prev) {
941                 if (!first) {
942                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
943                         return;
944                 }
945
946                 prev = first;
947         }
948
949         /* reset */
950
951         {
952                 Glib::Threads::RWLock::WriterLock lm (lock);
953                 /* cannot move the first tempo section */
954                 *((Tempo*)prev) = newtempo;
955                 recompute_map (false);
956         }
957
958         PropertyChanged (PropertyChange ());
959 }
960
961 const MeterSection&
962 TempoMap::first_meter () const
963 {
964         const MeterSection *m = 0;
965
966         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
967                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
968                         return *m;
969                 }
970         }
971
972         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
973         abort(); /*NOTREACHED*/
974         return *m;
975 }
976
977 MeterSection&
978 TempoMap::first_meter ()
979 {
980         MeterSection *m = 0;
981
982         /* CALLER MUST HOLD LOCK */
983
984         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
985                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
986                         return *m;
987                 }
988         }
989
990         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
991         abort(); /*NOTREACHED*/
992         return *m;
993 }
994
995 const TempoSection&
996 TempoMap::first_tempo () const
997 {
998         const TempoSection *t = 0;
999
1000         /* CALLER MUST HOLD LOCK */
1001
1002         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1003                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1004                         return *t;
1005                 }
1006         }
1007
1008         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1009         abort(); /*NOTREACHED*/
1010         return *t;
1011 }
1012
1013 TempoSection&
1014 TempoMap::first_tempo ()
1015 {
1016         TempoSection *t = 0;
1017
1018         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1019                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1020                         return *t;
1021                 }
1022         }
1023
1024         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1025         abort(); /*NOTREACHED*/
1026         return *t;
1027 }
1028
1029 void
1030 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
1031 {
1032         /* CALLER MUST HOLD WRITE LOCK */
1033
1034         if (end < 0) {
1035
1036                 /* we will actually stop once we hit
1037                    the last metric.
1038                 */
1039                 end = max_framepos;
1040
1041         }
1042
1043         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1044
1045         if (end == 0) {
1046                 /* silly call from Session::process() during startup
1047                  */
1048                 return;
1049         }
1050
1051         Metrics::const_iterator i;
1052
1053         TempoSection* prev_ts = 0;
1054
1055         for (i = metrics.begin(); i != metrics.end(); ++i) {
1056                 TempoSection* t;
1057
1058                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1059
1060                         if (prev_ts) {
1061                                 double const beats_relative_to_prev_ts = t->beat() - prev_ts->beat();
1062                                 double const ticks_relative_to_prev_ts = beats_relative_to_prev_ts * BBT_Time::ticks_per_beat;
1063
1064                                 /* assume (falsely) that the target tempo is constant */
1065                                 double const t_fpb = t->frames_per_beat (_frame_rate);
1066                                 double const av_fpb = (prev_ts->frames_per_beat (_frame_rate) + t_fpb) / 2.0;
1067                                 /* this walk shouldn't be needed as given c, time a = log (Ta / T0) / c. what to do? */
1068                                 double length_estimate = beats_relative_to_prev_ts * av_fpb;
1069
1070                                 if (prev_ts->type() == TempoSection::Constant) {
1071                                         length_estimate = beats_relative_to_prev_ts * prev_ts->frames_per_beat (_frame_rate);
1072                                 }
1073
1074                                 double const system_precision_at_target_tempo = (_frame_rate / t->ticks_per_minute()) * 1.5;
1075                                 double tick_error = system_precision_at_target_tempo + 1.0; // sorry for the wtf
1076
1077                                 while (fabs (tick_error) > system_precision_at_target_tempo) {
1078
1079                                         double const actual_ticks = prev_ts->tick_at_frame (length_estimate, t->beats_per_minute(),
1080                                                                                             (framepos_t) length_estimate, _frame_rate);
1081                                         tick_error = ticks_relative_to_prev_ts - actual_ticks;
1082                                         length_estimate += tick_error * (t->ticks_per_minute() / _frame_rate);
1083                                 }
1084
1085                                 t->set_frame (length_estimate + prev_ts->frame());
1086                         }
1087                         prev_ts = t;
1088                 }
1089         }
1090
1091         Metrics::const_iterator mi;
1092         MeterSection* meter = 0;
1093
1094         for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
1095                 /* we can do this beacuse we have the tempo section frames set */
1096                 if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
1097                         meter->set_frame (frame_at_tick (meter->beat() * BBT_Time::ticks_per_beat));
1098                 }
1099         }
1100 }
1101
1102
1103 TempoMetric
1104 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1105 {
1106         Glib::Threads::RWLock::ReaderLock lm (lock);
1107         TempoMetric m (first_meter(), first_tempo());
1108
1109         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1110            at something, because we insert the default tempo and meter during
1111            TempoMap construction.
1112
1113            now see if we can find better candidates.
1114         */
1115
1116         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1117
1118                 if ((*i)->frame() > frame) {
1119                         break;
1120                 }
1121
1122                 m.set_metric(*i);
1123
1124                 if (last) {
1125                         *last = i;
1126                 }
1127         }
1128
1129         return m;
1130 }
1131 /* XX meters only */
1132 TempoMetric
1133 TempoMap::metric_at (BBT_Time bbt) const
1134 {
1135         Glib::Threads::RWLock::ReaderLock lm (lock);
1136         TempoMetric m (first_meter(), first_tempo());
1137
1138         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1139            at something, because we insert the default tempo and meter during
1140            TempoMap construction.
1141
1142            now see if we can find better candidates.
1143         */
1144
1145         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1146                 MeterSection* mw;
1147                 if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
1148                         BBT_Time section_start (mw->bbt());
1149
1150                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1151                                 break;
1152                         }
1153
1154                         m.set_metric (*i);
1155                 }
1156         }
1157
1158         return m;
1159 }
1160
1161 void
1162 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1163 {
1164         Glib::Threads::RWLock::ReaderLock lm (lock);
1165
1166         if (frame < 0) {
1167                 bbt.bars = 1;
1168                 bbt.beats = 1;
1169                 bbt.ticks = 0;
1170                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1171                 return;
1172         }
1173         bbt = beats_to_bbt_locked (beat_at_frame (frame));
1174 }
1175
1176 double
1177 TempoMap::bbt_to_beats (Timecode::BBT_Time bbt)
1178 {
1179         Glib::Threads::RWLock::ReaderLock lm (lock);
1180         return bbt_to_beats_locked (bbt);
1181 }
1182
1183 double
1184 TempoMap::bbt_to_beats_locked (Timecode::BBT_Time bbt)
1185 {
1186         /* CALLER HOLDS READ LOCK */
1187
1188         double accumulated_beats = 0.0;
1189         double accumulated_bars = 0.0;
1190         MeterSection* prev_ms = 0;
1191
1192         Metrics::const_iterator i;
1193
1194         for (i = metrics.begin(); i != metrics.end(); ++i) {
1195                 MeterSection* m;
1196                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1197                         double bars_to_m = 0.0;
1198                         if (prev_ms) {
1199                                 bars_to_m = (m->beat() - prev_ms->beat()) / prev_ms->divisions_per_bar();
1200                         }
1201                         if ((bars_to_m + accumulated_bars) > (bbt.bars - 1)) {
1202                                 break;
1203                         }
1204                         if (prev_ms) {
1205                                 accumulated_beats += m->beat() - prev_ms->beat();
1206                                 accumulated_bars += bars_to_m;
1207                         }
1208                         prev_ms = m;
1209                 }
1210         }
1211
1212         double const remaining_bars = (bbt.bars - 1) - accumulated_bars;
1213         double const remaining_bars_in_beats = remaining_bars * prev_ms->divisions_per_bar();
1214         double const ret = remaining_bars_in_beats + accumulated_beats + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1215         return ret;
1216 }
1217
1218 Timecode::BBT_Time
1219 TempoMap::beats_to_bbt (double beats)
1220 {
1221         Glib::Threads::RWLock::ReaderLock lm (lock);
1222         return beats_to_bbt_locked (beats);
1223 }
1224
1225 Timecode::BBT_Time
1226 TempoMap::beats_to_bbt_locked (double beats)
1227 {
1228         /* CALLER HOLDS READ LOCK */
1229
1230         MeterSection* prev_ms = 0;
1231         uint32_t accumulated_bars = 0;
1232
1233         Metrics::const_iterator i;
1234
1235         for (i = metrics.begin(); i != metrics.end(); ++i) {
1236                 MeterSection* m = 0;
1237
1238                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1239
1240                         if (beats < m->beat()) {
1241                                 /* this is the meter after the one our beat is on*/
1242                                 break;
1243                         }
1244
1245                         if (prev_ms) {
1246                                 /* we need a whole number of bars. */
1247                                 accumulated_bars += ((m->beat() - prev_ms->beat()) + 1) / prev_ms->divisions_per_bar();
1248                         }
1249
1250                         prev_ms = m;
1251                 }
1252         }
1253
1254         double const beats_in_ms = beats - prev_ms->beat();
1255         uint32_t const bars_in_ms = (uint32_t) floor (beats_in_ms / prev_ms->divisions_per_bar());
1256         uint32_t const total_bars = bars_in_ms + accumulated_bars;
1257         double const remaining_beats = beats_in_ms - (bars_in_ms * prev_ms->divisions_per_bar());
1258         double const remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1259
1260         BBT_Time ret;
1261
1262         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1263         ret.beats = (uint32_t) floor (remaining_beats);
1264         ret.bars = total_bars;
1265
1266         /* 0 0 0 to 1 1 0 - based mapping*/
1267         ++ret.bars;
1268         ++ret.beats;
1269
1270         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1271                 ++ret.beats;
1272                 ret.ticks -= BBT_Time::ticks_per_beat;
1273         }
1274
1275         if (ret.beats > prev_ms->divisions_per_bar()) {
1276                 ++ret.bars;
1277                 ret.beats = 1;
1278         }
1279
1280         return ret;
1281 }
1282
1283 double
1284 TempoMap::tick_at_frame (framecnt_t frame) const
1285 {
1286         /* HOLD (at least) THE READER LOCK */
1287
1288         Metrics::const_iterator i;
1289         TempoSection* prev_ts = 0;
1290         double accumulated_ticks = 0.0;
1291
1292         for (i = metrics.begin(); i != metrics.end(); ++i) {
1293                 TempoSection* t;
1294
1295                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1296
1297                         if ((prev_ts) && frame < t->frame()) {
1298                                 /*the previous ts is the one containing the frame */
1299
1300                                 framepos_t const time = frame - prev_ts->frame();
1301                                 framepos_t const last_frame = t->frame() - prev_ts->frame();
1302                                 double const last_beats_per_minute = t->beats_per_minute();
1303
1304                                 return prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate) + accumulated_ticks;
1305                         }
1306
1307                         if (prev_ts && t->frame() > prev_ts->frame()) {
1308                                 accumulated_ticks = t->beat() * BBT_Time::ticks_per_beat;
1309                         }
1310
1311                         prev_ts = t;
1312                 }
1313         }
1314
1315         /* treated as constant for this ts */
1316         framecnt_t const frames_in_section = frame - prev_ts->frame();
1317         double const ticks_in_section = (frames_in_section / prev_ts->frames_per_beat (_frame_rate)) * Timecode::BBT_Time::ticks_per_beat;
1318
1319         return ticks_in_section + accumulated_ticks;
1320
1321 }
1322
1323 framecnt_t
1324 TempoMap::frame_at_tick (double tick) const
1325 {
1326         /* HOLD THE READER LOCK */
1327
1328         double accumulated_ticks = 0.0;
1329         double accumulated_ticks_to_prev = 0.0;
1330         const TempoSection* prev_ts = 0;
1331
1332         Metrics::const_iterator i;
1333
1334         for (i = metrics.begin(); i != metrics.end(); ++i) {
1335                 TempoSection* t;
1336                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1337
1338                         if (prev_ts && t->frame() > prev_ts->frame()) {
1339                                 accumulated_ticks = t->beat() * BBT_Time::ticks_per_beat;
1340                         }
1341
1342                         if (prev_ts && tick < accumulated_ticks) {
1343                                 /* prev_ts is the one affecting us. */
1344
1345                                 double const ticks_in_section = tick - accumulated_ticks_to_prev;
1346                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1347                                 double const last_beats_per_minute = t->beats_per_minute();
1348
1349                                 return prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + prev_ts->frame();
1350                         }
1351                         accumulated_ticks_to_prev = accumulated_ticks;
1352                         prev_ts = t;
1353                 }
1354         }
1355         /* must be treated as constant, irrespective of _type */
1356         double const ticks_in_section = tick - accumulated_ticks_to_prev;
1357         double const dtime = (ticks_in_section / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
1358
1359         framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1360
1361         return ret;
1362 }
1363
1364 double
1365 TempoMap::beat_at_frame (framecnt_t frame) const
1366 {
1367         Glib::Threads::RWLock::ReaderLock lm (lock);
1368
1369         return tick_at_frame (frame) / BBT_Time::ticks_per_beat;
1370 }
1371
1372 framecnt_t
1373 TempoMap::frame_at_beat (double beat) const
1374 {
1375         Glib::Threads::RWLock::ReaderLock lm (lock);
1376
1377         return frame_at_tick (beat * BBT_Time::ticks_per_beat);
1378 }
1379
1380 framepos_t
1381 TempoMap::frame_time (const BBT_Time& bbt)
1382 {
1383         if (bbt.bars < 1) {
1384                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1385                 return 0;
1386         }
1387
1388         if (bbt.beats < 1) {
1389                 throw std::logic_error ("beats are counted from one");
1390         }
1391         Glib::Threads::RWLock::ReaderLock lm (lock);
1392
1393         framepos_t const ret = frame_at_beat (bbt_to_beats_locked (bbt));
1394
1395         return ret;
1396 }
1397
1398
1399 framecnt_t
1400 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1401 {
1402
1403         Glib::Threads::RWLock::ReaderLock lm (lock);
1404
1405         Metrics::const_iterator i;
1406         TempoSection* first = 0;
1407         TempoSection* second = 0;
1408
1409         for (i = metrics.begin(); i != metrics.end(); ++i) {
1410                 TempoSection* t;
1411
1412                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1413
1414                         if ((*i)->frame() > pos) {
1415                                 second = t;
1416                                 break;
1417                         }
1418
1419                         first = t;
1420                 }
1421         }
1422         if (first && second) {
1423                 framepos_t const last_time = second->frame() - first->frame();
1424                 double const last_beats_per_minute = second->beats_per_minute();
1425
1426                 framepos_t const time = pos - first->frame();
1427                 double const tick_at_time = first->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1428                 double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1429
1430                 double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, last_beats_per_minute, last_time, _frame_rate);
1431
1432                 return time_at_bbt - time;
1433         }
1434
1435         double const ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1436         return (framecnt_t) floor ((ticks / BBT_Time::ticks_per_beat) * first->frames_per_beat(_frame_rate));
1437 }
1438
1439 framepos_t
1440 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
1441 {
1442         return round_to_type (fr, dir, Bar);
1443 }
1444
1445 framepos_t
1446 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
1447 {
1448         return round_to_type (fr, dir, Beat);
1449 }
1450
1451 framepos_t
1452 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
1453 {
1454         Glib::Threads::RWLock::ReaderLock lm (lock);
1455
1456         uint32_t ticks = (uint32_t) floor (tick_at_frame (fr) + 0.5);
1457         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
1458         uint32_t ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1459
1460         ticks -= beats * BBT_Time::ticks_per_beat;
1461
1462         if (dir > 0) {
1463                 /* round to next (or same iff dir == RoundUpMaybe) */
1464
1465                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
1466
1467                 if (mod == 0 && dir == RoundUpMaybe) {
1468                         /* right on the subdivision, which is fine, so do nothing */
1469
1470                 } else if (mod == 0) {
1471                         /* right on the subdivision, so the difference is just the subdivision ticks */
1472                         ticks += ticks_one_subdivisions_worth;
1473
1474                 } else {
1475                         /* not on subdivision, compute distance to next subdivision */
1476
1477                         ticks += ticks_one_subdivisions_worth - mod;
1478                 }
1479
1480                 if (ticks >= BBT_Time::ticks_per_beat) {
1481                         ticks -= BBT_Time::ticks_per_beat;
1482                 }
1483         } else if (dir < 0) {
1484
1485                 /* round to previous (or same iff dir == RoundDownMaybe) */
1486
1487                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
1488
1489                 if (difference == 0 && dir == RoundDownAlways) {
1490                         /* right on the subdivision, but force-rounding down,
1491                            so the difference is just the subdivision ticks */
1492                         difference = ticks_one_subdivisions_worth;
1493                 }
1494
1495                 if (ticks < difference) {
1496                         ticks = BBT_Time::ticks_per_beat - ticks;
1497                 } else {
1498                         ticks -= difference;
1499                 }
1500
1501         } else {
1502                 /* round to nearest */
1503                 double rem;
1504
1505                 /* compute the distance to the previous and next subdivision */
1506
1507                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1508
1509                         /* closer to the next subdivision, so shift forward */
1510
1511                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
1512
1513                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
1514
1515                         if (ticks > BBT_Time::ticks_per_beat) {
1516                                 ++beats;
1517                                 ticks -= BBT_Time::ticks_per_beat;
1518                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
1519                         }
1520
1521                 } else if (rem > 0) {
1522
1523                         /* closer to previous subdivision, so shift backward */
1524
1525                         if (rem > ticks) {
1526                                 if (beats == 0) {
1527                                         /* can't go backwards past zero, so ... */
1528                                         return 0;
1529                                 }
1530                                 /* step back to previous beat */
1531                                 --beats;
1532                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
1533                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
1534                         } else {
1535                                 ticks = lrint (ticks - rem);
1536                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
1537                         }
1538                 } else {
1539                         /* on the subdivision, do nothing */
1540                 }
1541         }
1542         return frame_at_tick ((beats * BBT_Time::ticks_per_beat) + ticks);
1543 }
1544
1545 framepos_t
1546 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
1547 {
1548         Glib::Threads::RWLock::ReaderLock lm (lock);
1549
1550         double const beat_at_framepos = beat_at_frame (frame);
1551
1552         BBT_Time bbt (beats_to_bbt_locked (beat_at_framepos));
1553
1554         switch (type) {
1555         case Bar:
1556                 if (dir < 0) {
1557                         /* find bar previous to 'frame' */
1558                         bbt.beats = 1;
1559                         bbt.ticks = 0;
1560                         return frame_time (bbt);
1561
1562                 } else if (dir > 0) {
1563                         /* find bar following 'frame' */
1564                         ++bbt.bars;
1565                         bbt.beats = 1;
1566                         bbt.ticks = 0;
1567                         return frame_time (bbt);
1568                 } else {
1569                         /* true rounding: find nearest bar */
1570                         framepos_t raw_ft = frame_time (bbt);
1571                         bbt.beats = 1;
1572                         bbt.ticks = 0;
1573                         framepos_t prev_ft = frame_time (bbt);
1574                         ++bbt.bars;
1575                         framepos_t next_ft = frame_time (bbt);
1576
1577                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
1578                                 return next_ft;
1579                         } else {
1580                                 return prev_ft;
1581                         }
1582                 }
1583
1584                 break;
1585
1586         case Beat:
1587                 if (dir < 0) {
1588                         return frame_at_beat (floor (beat_at_framepos));
1589                 } else if (dir > 0) {
1590                         return frame_at_beat (ceil (beat_at_framepos));
1591                 } else {
1592                         return frame_at_beat (floor (beat_at_framepos + 0.5));
1593                 }
1594                 break;
1595         }
1596
1597         return 0;
1598 }
1599
1600 void
1601 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
1602                     framepos_t lower, framepos_t upper)
1603 {
1604         Glib::Threads::RWLock::ReaderLock lm (lock);
1605         uint32_t const upper_beat = (uint32_t) floor (beat_at_frame (upper));
1606         uint32_t cnt = (uint32_t) ceil (beat_at_frame (lower));
1607
1608         while (cnt <= upper_beat) {
1609                 framecnt_t const pos = frame_at_beat (cnt);
1610                 MeterSection const meter = meter_section_at (pos);
1611                 Tempo const tempo = tempo_at (pos);
1612                 BBT_Time const bbt = beats_to_bbt_locked ((double) cnt);
1613
1614                 points.push_back (BBTPoint (meter, tempo, pos, bbt.bars, bbt.beats));
1615                 ++cnt;
1616         }
1617 }
1618
1619 const TempoSection&
1620 TempoMap::tempo_section_at (framepos_t frame) const
1621 {
1622         Glib::Threads::RWLock::ReaderLock lm (lock);
1623
1624         Metrics::const_iterator i;
1625         TempoSection* prev = 0;
1626
1627         for (i = metrics.begin(); i != metrics.end(); ++i) {
1628                 TempoSection* t;
1629
1630                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1631
1632                         if ((*i)->frame() > frame) {
1633                                 break;
1634                         }
1635
1636                         prev = t;
1637                 }
1638         }
1639
1640         if (prev == 0) {
1641                 fatal << endmsg;
1642                 abort(); /*NOTREACHED*/
1643         }
1644
1645         return *prev;
1646 }
1647
1648 /* don't use this to calculate length (the tempo is only correct for this frame).
1649    do that stuff based on the beat_at_frame and frame_at_beat api
1650 */
1651 double
1652 TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const
1653 {
1654         Glib::Threads::RWLock::ReaderLock lm (lock);
1655
1656         const TempoSection* ts_at = &tempo_section_at (frame);
1657         const TempoSection* ts_after = 0;
1658         Metrics::const_iterator i;
1659
1660         for (i = metrics.begin(); i != metrics.end(); ++i) {
1661                 TempoSection* t;
1662
1663                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1664
1665                         if ((*i)->frame() > frame) {
1666                                 ts_after = t;
1667                                 break;
1668                         }
1669                 }
1670         }
1671
1672         if (ts_after) {
1673                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate));
1674         }
1675         /* must be treated as constant tempo */
1676         return ts_at->frames_per_beat (_frame_rate);
1677 }
1678
1679 const Tempo
1680 TempoMap::tempo_at (framepos_t frame) const
1681 {
1682         Glib::Threads::RWLock::ReaderLock lm (lock);
1683
1684         TempoMetric m (metric_at (frame));
1685         TempoSection* prev_ts = 0;
1686
1687         Metrics::const_iterator i;
1688
1689         for (i = metrics.begin(); i != metrics.end(); ++i) {
1690                 TempoSection* t;
1691                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1692                         if ((prev_ts) && t->frame() > frame) {
1693                                 /* this is the one past frame */
1694                                 framepos_t const time = frame - prev_ts->frame();
1695                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1696                                 double const last_beats_per_minute = t->beats_per_minute();
1697                                 double const ret = prev_ts->tempo_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1698                                 Tempo const ret_tempo (ret, m.tempo().note_type ());
1699                                 return ret_tempo;
1700                         }
1701                         prev_ts = t;
1702                 }
1703         }
1704
1705         return m.tempo();
1706
1707 }
1708
1709 const MeterSection&
1710 TempoMap::meter_section_at (framepos_t frame) const
1711 {
1712         Glib::Threads::RWLock::ReaderLock lm (lock);
1713         Metrics::const_iterator i;
1714         MeterSection* prev = 0;
1715
1716         for (i = metrics.begin(); i != metrics.end(); ++i) {
1717                 MeterSection* t;
1718
1719                 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1720
1721                         if ((*i)->frame() > frame) {
1722                                 break;
1723                         }
1724
1725                         prev = t;
1726                 }
1727         }
1728
1729         if (prev == 0) {
1730                 fatal << endmsg;
1731                 abort(); /*NOTREACHED*/
1732         }
1733
1734         return *prev;
1735 }
1736
1737 const Meter&
1738 TempoMap::meter_at (framepos_t frame) const
1739 {
1740         TempoMetric m (metric_at (frame));
1741         return m.meter();
1742 }
1743
1744 XMLNode&
1745 TempoMap::get_state ()
1746 {
1747         Metrics::const_iterator i;
1748         XMLNode *root = new XMLNode ("TempoMap");
1749
1750         {
1751                 Glib::Threads::RWLock::ReaderLock lm (lock);
1752                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1753                         root->add_child_nocopy ((*i)->get_state());
1754                 }
1755         }
1756
1757         return *root;
1758 }
1759
1760 int
1761 TempoMap::set_state (const XMLNode& node, int /*version*/)
1762 {
1763         {
1764                 Glib::Threads::RWLock::WriterLock lm (lock);
1765
1766                 XMLNodeList nlist;
1767                 XMLNodeConstIterator niter;
1768                 Metrics old_metrics (metrics);
1769                 MeterSection* last_meter = 0;
1770                 metrics.clear();
1771
1772                 nlist = node.children();
1773
1774                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1775                         XMLNode* child = *niter;
1776
1777                         if (child->name() == TempoSection::xml_state_node_name) {
1778
1779                                 try {
1780                                         TempoSection* ts = new TempoSection (*child);
1781                                         metrics.push_back (ts);
1782
1783                                         if (ts->bar_offset() < 0.0) {
1784                                                 if (last_meter) {
1785                                                         //ts->update_bar_offset_from_bbt (*last_meter);
1786                                                 }
1787                                         }
1788                                 }
1789
1790                                 catch (failed_constructor& err){
1791                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1792                                         metrics = old_metrics;
1793                                         break;
1794                                 }
1795
1796                         } else if (child->name() == MeterSection::xml_state_node_name) {
1797
1798                                 try {
1799                                         MeterSection* ms = new MeterSection (*child);
1800                                         metrics.push_back (ms);
1801                                         last_meter = ms;
1802                                 }
1803
1804                                 catch (failed_constructor& err) {
1805                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1806                                         metrics = old_metrics;
1807                                         break;
1808                                 }
1809                         }
1810                 }
1811
1812                 if (niter == nlist.end()) {
1813                         MetricSectionSorter cmp;
1814                         metrics.sort (cmp);
1815                 }
1816                 /* check for legacy sessions where bbt was the base musical unit for tempo */
1817                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1818                         MeterSection* prev_ms;
1819                         TempoSection* prev_ts;
1820                         if ((prev_ms = dynamic_cast<MeterSection*>(*i)) != 0) {
1821                                 if (prev_ms->beat() < 0.0) {
1822                                         /*XX we cannot possibly make this work??. */
1823                                         pair<double, BBT_Time> start = make_pair (((prev_ms->bbt().bars - 1) * 4.0) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat), prev_ms->bbt());
1824                                         prev_ms->set_beat (start);
1825                                 }
1826                         } else if ((prev_ts = dynamic_cast<TempoSection*>(*i)) != 0) {
1827                                 if (prev_ts->beat() < 0.0) {
1828                                         double const start = ((prev_ts->legacy_bbt().bars - 1) * 4.0) + (prev_ts->legacy_bbt().beats - 1) + (prev_ts->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
1829                                         prev_ts->set_beat (start);
1830
1831                                 }
1832                         }
1833                 }
1834                 /* check for multiple tempo/meters at the same location, which
1835                    ardour2 somehow allowed.
1836                 */
1837
1838                 Metrics::iterator prev = metrics.end();
1839                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1840                         if (prev != metrics.end()) {
1841                                 MeterSection* ms;
1842                                 MeterSection* prev_ms;
1843                                 TempoSection* ts;
1844                                 TempoSection* prev_ts;
1845                                 if ((prev_ms = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
1846                                         if (prev_ms->beat() == ms->beat()) {
1847                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_ms->beat()) << endmsg;
1848                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_ms->beat()) << endmsg;
1849                                                 return -1;
1850                                         }
1851                                 } else if ((prev_ts = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
1852                                         if (prev_ts->beat() == ts->beat()) {
1853                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->beat()) << endmsg;
1854                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->beat()) << endmsg;
1855                                                 return -1;
1856                                         }
1857                                 }
1858                         }
1859                         prev = i;
1860                 }
1861
1862                 recompute_map (true, -1);
1863         }
1864
1865         PropertyChanged (PropertyChange ());
1866
1867         return 0;
1868 }
1869
1870 void
1871 TempoMap::dump (std::ostream& o) const
1872 {
1873         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1874         const MeterSection* m;
1875         const TempoSection* t;
1876
1877         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1878
1879                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1880                         o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->beat() << " frame= " << t->frame() << " (movable? "
1881                           << t->movable() << ')' << endl;
1882                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1883                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
1884                           << " (movable? " << m->movable() << ')' << endl;
1885                 }
1886         }
1887 }
1888
1889 int
1890 TempoMap::n_tempos() const
1891 {
1892         Glib::Threads::RWLock::ReaderLock lm (lock);
1893         int cnt = 0;
1894
1895         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1896                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1897                         cnt++;
1898                 }
1899         }
1900
1901         return cnt;
1902 }
1903
1904 int
1905 TempoMap::n_meters() const
1906 {
1907         Glib::Threads::RWLock::ReaderLock lm (lock);
1908         int cnt = 0;
1909
1910         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1911                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1912                         cnt++;
1913                 }
1914         }
1915
1916         return cnt;
1917 }
1918
1919 void
1920 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1921 {
1922         {
1923                 Glib::Threads::RWLock::WriterLock lm (lock);
1924                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1925                         if ((*i)->frame() >= where && (*i)->movable ()) {
1926                                 (*i)->set_frame ((*i)->frame() + amount);
1927                         }
1928                 }
1929
1930                 /* now reset the BBT time of all metrics, based on their new
1931                  * audio time. This is the only place where we do this reverse
1932                  * timestamp.
1933                  */
1934
1935                 Metrics::iterator i;
1936                 const MeterSection* meter;
1937                 const TempoSection* tempo;
1938                 MeterSection *m;
1939                 TempoSection *t;
1940
1941                 meter = &first_meter ();
1942                 tempo = &first_tempo ();
1943
1944                 BBT_Time start;
1945                 BBT_Time end;
1946
1947                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
1948
1949                 bool first = true;
1950                 MetricSection* prev = 0;
1951
1952                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1953
1954                         BBT_Time bbt;
1955                         //TempoMetric metric (*meter, *tempo);
1956                         MeterSection* ms = const_cast<MeterSection*>(meter);
1957                         TempoSection* ts = const_cast<TempoSection*>(tempo);
1958                         if (prev) {
1959                                 if (ts){
1960                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
1961                                                 ts->set_beat (t->beat());
1962                                         }
1963                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
1964                                                 ts->set_beat (m->beat());
1965                                         }
1966                                         ts->set_frame (prev->frame());
1967
1968                                 }
1969                                 if (ms) {
1970                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
1971                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
1972                                                 ms->set_beat (start);
1973                                         }
1974                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
1975                                                 pair<double, BBT_Time> start = make_pair (t->beat(), beats_to_bbt_locked (t->beat()));
1976                                                 ms->set_beat (start);
1977                                         }
1978                                         ms->set_frame (prev->frame());
1979                                 }
1980
1981                         } else {
1982                                 // metric will be at frames=0 bbt=1|1|0 by default
1983                                 // which is correct for our purpose
1984                         }
1985
1986                         // cerr << bbt << endl;
1987
1988                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1989                                 t->set_beat (beat_at_frame (m->frame()));
1990                                 tempo = t;
1991                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->beat() <<endl;
1992                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
1993                                 bbt_time (m->frame(), bbt);
1994
1995                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
1996
1997                                 if (first) {
1998                                         first = false;
1999                                 } else {
2000
2001                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
2002                                                 /* round up to next beat */
2003                                                 bbt.beats += 1;
2004                                         }
2005
2006                                         bbt.ticks = 0;
2007
2008                                         if (bbt.beats != 1) {
2009                                                 /* round up to next bar */
2010                                                 bbt.bars += 1;
2011                                                 bbt.beats = 1;
2012                                         }
2013                                 }
2014                                 pair<double, BBT_Time> start = make_pair (beat_at_frame (m->frame()), bbt);
2015                                 m->set_beat (start);
2016                                 meter = m;
2017                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->beat() <<endl;
2018                         } else {
2019                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
2020                                 abort(); /*NOTREACHED*/
2021                         }
2022
2023                         prev = (*i);
2024                 }
2025
2026                 recompute_map (true);
2027         }
2028
2029
2030         PropertyChanged (PropertyChange ());
2031 }
2032 bool
2033 TempoMap::remove_time (framepos_t where, framecnt_t amount)
2034 {
2035         bool moved = false;
2036
2037         std::list<MetricSection*> metric_kill_list;
2038
2039         TempoSection* last_tempo = NULL;
2040         MeterSection* last_meter = NULL;
2041         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
2042         bool meter_after = false; // is there a meter marker likewise?
2043         {
2044                 Glib::Threads::RWLock::WriterLock lm (lock);
2045                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2046                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
2047                                 metric_kill_list.push_back(*i);
2048                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
2049                                 if (lt)
2050                                         last_tempo = lt;
2051                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
2052                                 if (lm)
2053                                         last_meter = lm;
2054                         }
2055                         else if ((*i)->frame() >= where) {
2056                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
2057                                 (*i)->set_frame ((*i)->frame() - amount);
2058                                 if ((*i)->frame() == where) {
2059                                         // marker was immediately after end of range
2060                                         tempo_after = dynamic_cast<TempoSection*> (*i);
2061                                         meter_after = dynamic_cast<MeterSection*> (*i);
2062                                 }
2063                                 moved = true;
2064                         }
2065                 }
2066
2067                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
2068                 if (last_tempo && !tempo_after) {
2069                         metric_kill_list.remove(last_tempo);
2070                         last_tempo->set_frame(where);
2071                         moved = true;
2072                 }
2073                 if (last_meter && !meter_after) {
2074                         metric_kill_list.remove(last_meter);
2075                         last_meter->set_frame(where);
2076                         moved = true;
2077                 }
2078
2079                 //remove all the remaining metrics
2080                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
2081                         metrics.remove(*i);
2082                         moved = true;
2083                 }
2084
2085                 if (moved) {
2086                         recompute_map (true);
2087                 }
2088         }
2089         PropertyChanged (PropertyChange ());
2090         return moved;
2091 }
2092
2093 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2094  *  pos can be -ve, if required.
2095  */
2096 framepos_t
2097 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
2098 {
2099         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
2100 }
2101
2102 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2103 framepos_t
2104 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2105 {
2106         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
2107 }
2108
2109 /** Add the BBT interval op to pos and return the result */
2110 framepos_t
2111 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2112 {
2113         cerr << "framepos_plus_bbt - untested" << endl;
2114         Glib::Threads::RWLock::ReaderLock lm (lock);
2115
2116         Metrics::const_iterator i;
2117         const MeterSection* meter;
2118         const MeterSection* m;
2119         const TempoSection* tempo;
2120         const TempoSection* next_tempo = 0;
2121         const TempoSection* t;
2122         double frames_per_beat;
2123         framepos_t effective_pos = max (pos, (framepos_t) 0);
2124
2125         meter = &first_meter ();
2126         tempo = &first_tempo ();
2127
2128         assert (meter);
2129         assert (tempo);
2130
2131         /* find the starting metrics for tempo & meter */
2132
2133         for (i = metrics.begin(); i != metrics.end(); ++i) {
2134
2135                 if ((*i)->frame() > effective_pos) {
2136                         break;
2137                 }
2138
2139                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2140                         tempo = t;
2141                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2142                         meter = m;
2143                 }
2144         }
2145
2146         for (i = metrics.begin(); i != metrics.end(); ++i) {
2147                 if ((*i)->frame() > effective_pos) {
2148                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2149                                 next_tempo = t;
2150                         }
2151                         break;
2152                 }
2153         }
2154
2155         /* We now have:
2156
2157            meter -> the Meter for "pos"
2158            tempo -> the Tempo for "pos"
2159            next_tempo -> the Tempo after "pos" or 0
2160            i     -> for first new metric after "pos", possibly metrics.end()
2161         */
2162
2163         /* now comes the complicated part. we have to add one beat a time,
2164            checking for a new metric on every beat.
2165         */
2166
2167         uint64_t bars = 0;
2168         /* fpb is used for constant tempo */
2169         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2170
2171         while (op.bars) {
2172
2173                 bars++;
2174                 op.bars--;
2175
2176                 /* check if we need to use a new metric section: has adding frames moved us
2177                    to or after the start of the next metric section? in which case, use it.
2178                 */
2179
2180                 if (i != metrics.end()) {
2181                         if ((*i)->frame() <= pos) {
2182
2183                                 /* about to change tempo or meter, so add the
2184                                  * number of frames for the bars we've just
2185                                  * traversed before we change the
2186                                  * frames_per_beat value.
2187                                  */
2188
2189                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2190                                         next_tempo = t;
2191                                 }
2192
2193                                 if (next_tempo) {
2194                                         pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2195                                 } else {
2196                                         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2197                                 }
2198
2199                                 bars = 0;
2200
2201                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2202                                         tempo = t;
2203                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2204                                         meter = m;
2205                                 }
2206                                 ++i;
2207                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2208                         }
2209                 }
2210
2211         }
2212
2213         if (next_tempo) {
2214                 pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2215         } else {
2216                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2217         }
2218
2219         uint64_t beats = 0;
2220
2221         while (op.beats) {
2222
2223                 /* given the current meter, have we gone past the end of the bar ? */
2224
2225                 beats++;
2226                 op.beats--;
2227
2228                 /* check if we need to use a new metric section: has adding frames moved us
2229                    to or after the start of the next metric section? in which case, use it.
2230                 */
2231
2232                 if (i != metrics.end()) {
2233                         if ((*i)->frame() <= pos) {
2234
2235                                 /* about to change tempo or meter, so add the
2236                                  * number of frames for the beats we've just
2237                                  * traversed before we change the
2238                                  * frames_per_beat value.
2239                                  */
2240
2241                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2242                                         next_tempo = t;
2243                                 }
2244
2245                                 if (next_tempo) {
2246                                         pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2247                                 } else {
2248                                         pos += llrint (beats * frames_per_beat);
2249                                 }
2250
2251                                 beats = 0;
2252
2253                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2254                                         tempo = t;
2255                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2256                                         meter = m;
2257                                 }
2258                                 ++i;
2259                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2260                         }
2261                 }
2262         }
2263
2264         if (next_tempo) {
2265                 pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2266         } else {
2267                 pos += llrint (beats * frames_per_beat);
2268         }
2269
2270         if (op.ticks) {
2271                 pos += tempo->frame_at_tick (op.ticks, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2272         }
2273
2274         return pos;
2275
2276 }
2277
2278 /** Count the number of beats that are equivalent to distance when going forward,
2279     starting at pos.
2280 */
2281 Evoral::Beats
2282 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2283 {
2284         return Evoral::Beats(beat_at_frame (pos + distance) - beat_at_frame (pos));
2285 }
2286
2287 struct bbtcmp {
2288     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2289             return a < b;
2290     }
2291 };
2292
2293 std::ostream&
2294 operator<< (std::ostream& o, const Meter& m) {
2295         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2296 }
2297
2298 std::ostream&
2299 operator<< (std::ostream& o, const Tempo& t) {
2300         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2301 }
2302
2303 std::ostream&
2304 operator<< (std::ostream& o, const MetricSection& section) {
2305
2306         o << "MetricSection @ " << section.frame() << ' ';
2307
2308         const TempoSection* ts;
2309         const MeterSection* ms;
2310
2311         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2312                 o << *((const Tempo*) ts);
2313         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2314                 //o << *((const Meter*) ms);
2315         }
2316
2317         return o;
2318 }