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