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