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