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