Tempo ramps - more code cleanup, fix cross-marker jumping using tempo dialog bbt
[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         bool solved = false;
2009
2010         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2011                 MeterSection* m;
2012                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2013                         if (m == section){
2014                                 if (prev_m && section->movable()) {
2015                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2016                                         if (beats + prev_m->beat() < section->beat()) {
2017                                                 /* set the frame/pulse corresponding to its musical position,
2018                                                  * as an earlier time than this has been requested.
2019                                                 */
2020
2021                                                 TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2022                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2023                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2024                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2025                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2026                                                         meter_locked_tempo->set_pulse (new_pulse);
2027                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2028                                                         section->set_frame (smallest_frame);
2029                                                         section->set_pulse (new_pulse);
2030                                                 } else {
2031                                                         solved = false;
2032                                                 }
2033
2034                                                 Metrics::const_iterator d = future_map.begin();
2035                                                 while (d != future_map.end()) {
2036                                                         delete (*d);
2037                                                         ++d;
2038                                                 }
2039
2040                                                 if (!solved) {
2041                                                         return false;
2042                                                 }
2043                                         } else {
2044
2045                                                 TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_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                                         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2072
2073                                         tempo_copy->set_frame (frame);
2074                                         tempo_copy->set_pulse (0.0);
2075
2076                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2077                                                 section->set_frame (frame);
2078                                                 meter_locked_tempo->set_frame (frame);
2079                                                 meter_locked_tempo->set_pulse (0.0);
2080                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2081                                         } else {
2082                                                 solved = false;
2083                                         }
2084
2085                                         Metrics::const_iterator d = future_map.begin();
2086                                         while (d != future_map.end()) {
2087                                                 delete (*d);
2088                                                 ++d;
2089                                         }
2090
2091                                         if (!solved) {
2092                                                 return false;
2093                                         }
2094
2095                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2096                                         section->set_beat (b_bbt);
2097                                         section->set_pulse (0.0);
2098
2099                                 }
2100                                 break;
2101                         }
2102
2103                         prev_m = m;
2104                 }
2105         }
2106
2107         MetricSectionFrameSorter fcmp;
2108         imaginary.sort (fcmp);
2109
2110         recompute_meters (imaginary);
2111
2112         return true;
2113 }
2114
2115 bool
2116 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2117 {
2118         /* disallow setting section to an existing meter's bbt */
2119         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2120                 MeterSection* m;
2121                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2122                         if (m != section && m->bbt().bars == when.bars) {
2123                                 return false;
2124                         }
2125                 }
2126         }
2127
2128         MeterSection* prev_m = 0;
2129         MeterSection* section_prev = 0;
2130
2131         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2132                 MeterSection* m;
2133                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2134                         pair<double, BBT_Time> b_bbt;
2135                         double new_pulse = 0.0;
2136
2137                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2138                                 section_prev = prev_m;
2139                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2140                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2141                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2142
2143                                 section->set_beat (b_bbt);
2144                                 section->set_pulse (pulse);
2145                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2146                                 prev_m = section;
2147                                 continue;
2148                         }
2149
2150                         if (m->position_lock_style() == AudioTime) {
2151                                 TempoSection* meter_locked_tempo = 0;
2152                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2153                                         TempoSection* t;
2154                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2155                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2156                                                         meter_locked_tempo = t;
2157                                                         break;
2158                                                 }
2159                                         }
2160                                 }
2161
2162                                 if (prev_m) {
2163                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2164
2165                                         if (beats + prev_m->beat() != m->beat()) {
2166                                                 /* tempo/ meter change caused a change in beat (bar). */
2167                                                 b_bbt = make_pair (beats + prev_m->beat()
2168                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2169                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2170                                         } else if (m->movable()) {
2171                                                 b_bbt = make_pair (m->beat(), m->bbt());
2172                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2173                                         }
2174                                 } else {
2175                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2176                                 }
2177                                 if (meter_locked_tempo) {
2178                                         meter_locked_tempo->set_pulse (new_pulse);
2179                                         recompute_tempos (imaginary);
2180                                 }
2181                                 m->set_beat (b_bbt);
2182                                 m->set_pulse (new_pulse);
2183
2184                         } else {
2185                                 /* MusicTime */
2186                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2187                                 if (beats + prev_m->beat() != m->beat()) {
2188                                         /* tempo/ meter change caused a change in beat (bar). */
2189                                         b_bbt = make_pair (beats + prev_m->beat()
2190                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2191                                 } else {
2192                                         b_bbt = make_pair (beats + prev_m->beat()
2193                                                            , m->bbt());
2194                                 }
2195                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2196                                 m->set_beat (b_bbt);
2197                                 m->set_pulse (new_pulse);
2198                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2199                         }
2200
2201                         prev_m = m;
2202                 }
2203         }
2204
2205         if (!section_prev) {
2206
2207                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2208                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2209                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2210
2211                 section->set_beat (b_bbt);
2212                 section->set_pulse (pulse);
2213                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2214         }
2215
2216         MetricSectionSorter cmp;
2217         imaginary.sort (cmp);
2218
2219         recompute_meters (imaginary);
2220
2221         return true;
2222 }
2223
2224 /** places a copy of _metrics into copy and returns a pointer
2225  *  to section's equivalent in copy.
2226  */
2227 TempoSection*
2228 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2229 {
2230         TempoSection* ret = 0;
2231
2232         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2233                 TempoSection* t;
2234                 MeterSection* m;
2235                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2236                         if (t == section) {
2237                                 ret = new TempoSection (*t);
2238                                 copy.push_back (ret);
2239                                 continue;
2240                         }
2241
2242                         TempoSection* cp = new TempoSection (*t);
2243                         copy.push_back (cp);
2244                 }
2245                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2246                         MeterSection* cp = new MeterSection (*m);
2247                         copy.push_back (cp);
2248                 }
2249         }
2250
2251         return ret;
2252 }
2253
2254 MeterSection*
2255 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2256 {
2257         MeterSection* ret = 0;
2258
2259         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2260                 TempoSection* t;
2261                 MeterSection* m;
2262                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2263                         TempoSection* cp = new TempoSection (*t);
2264                         copy.push_back (cp);
2265                 }
2266
2267                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2268                         if (m == section) {
2269                                 ret = new MeterSection (*m);
2270                                 copy.push_back (ret);
2271                                 continue;
2272                         }
2273                         MeterSection* cp = new MeterSection (*m);
2274                         copy.push_back (cp);
2275                 }
2276         }
2277
2278         return ret;
2279 }
2280
2281 bool
2282 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2283 {
2284         Metrics copy;
2285         TempoSection* tempo_copy = 0;
2286
2287         {
2288                 Glib::Threads::RWLock::ReaderLock lm (lock);
2289                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2290                 if (!tempo_copy) {
2291                         return false;
2292                 }
2293         }
2294
2295         const double beat = bbt_to_beats_locked (copy, bbt);
2296         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_beat_locked (copy, beat));
2297
2298         Metrics::const_iterator d = copy.begin();
2299         while (d != copy.end()) {
2300                 delete (*d);
2301                 ++d;
2302         }
2303
2304         return ret;
2305 }
2306
2307 /**
2308 * 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,
2309 * taking any possible reordering as a consequence of this into account.
2310 * @param section - the section to be altered
2311 * @param bpm - the new Tempo
2312 * @param bbt - the bbt where the altered tempo will fall
2313 * @return returns - the position in frames where the new tempo section will lie.
2314 */
2315 framepos_t
2316 TempoMap::predict_tempo_frame (TempoSection* section, const BBT_Time& bbt)
2317 {
2318         Glib::Threads::RWLock::ReaderLock lm (lock);
2319         Metrics future_map;
2320         framepos_t ret = 0;
2321         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2322         if (!tempo_copy) {
2323                 return 0;
2324         }
2325         const double beat = bbt_to_beats_locked (future_map, bbt);
2326
2327         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2328                 ret = tempo_copy->frame();
2329         } else {
2330                 ret = section->frame();
2331         }
2332
2333         Metrics::const_iterator d = future_map.begin();
2334         while (d != future_map.end()) {
2335                 delete (*d);
2336                 ++d;
2337         }
2338         return ret;
2339 }
2340
2341 double
2342 TempoMap::predict_tempo_pulse (TempoSection* section, const BBT_Time& bbt)
2343 {
2344         Glib::Threads::RWLock::ReaderLock lm (lock);
2345         Metrics future_map;
2346         double ret = 0.0;
2347         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2348         const double beat = bbt_to_beats_locked (future_map, bbt);
2349
2350         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2351                 ret = tempo_copy->pulse();
2352         } else {
2353                 ret = section->pulse();
2354         }
2355
2356         Metrics::const_iterator d = future_map.begin();
2357         while (d != future_map.end()) {
2358                 delete (*d);
2359                 ++d;
2360         }
2361         return ret;
2362 }
2363
2364 void
2365 TempoMap::gui_move_tempo_frame (TempoSection* ts, const framepos_t& frame)
2366 {
2367         Metrics future_map;
2368         {
2369                 Glib::Threads::RWLock::WriterLock lm (lock);
2370                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2371                 if (solve_map_frame (future_map, tempo_copy, frame)) {
2372                         solve_map_frame (_metrics, ts, frame);
2373                         recompute_meters (_metrics);
2374                 }
2375         }
2376
2377         Metrics::const_iterator d = future_map.begin();
2378         while (d != future_map.end()) {
2379                 delete (*d);
2380                 ++d;
2381         }
2382
2383         MetricPositionChanged (); // Emit Signal
2384 }
2385
2386 void
2387 TempoMap::gui_move_tempo_beat (TempoSection* ts, const double& beat)
2388 {
2389         Metrics future_map;
2390         {
2391                 Glib::Threads::RWLock::WriterLock lm (lock);
2392                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2393                 if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2394                         solve_map_pulse (_metrics, ts, pulse_at_beat_locked (_metrics, beat));
2395                         recompute_meters (_metrics);
2396                 }
2397         }
2398
2399         Metrics::const_iterator d = future_map.begin();
2400         while (d != future_map.end()) {
2401                 delete (*d);
2402                 ++d;
2403         }
2404
2405         MetricPositionChanged (); // Emit Signal
2406 }
2407
2408 void
2409 TempoMap::gui_move_meter_frame (MeterSection* ms, const framepos_t&  frame)
2410 {
2411         Metrics future_map;
2412         {
2413                 Glib::Threads::RWLock::WriterLock lm (lock);
2414                 MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2415                 if (solve_map_frame (future_map, copy, frame)) {
2416                         solve_map_frame (_metrics, ms, frame);
2417                         recompute_tempos (_metrics);
2418                 }
2419         }
2420
2421         Metrics::const_iterator d = future_map.begin();
2422         while (d != future_map.end()) {
2423                 delete (*d);
2424                 ++d;
2425         }
2426
2427         MetricPositionChanged (); // Emit Signal
2428 }
2429
2430 void
2431 TempoMap::gui_move_meter_bbt (MeterSection* ms, const Timecode::BBT_Time& bbt)
2432 {
2433         Metrics future_map;
2434         {
2435                 Glib::Threads::RWLock::WriterLock lm (lock);
2436                 MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2437                 if (solve_map_bbt (future_map, copy, bbt)) {
2438                         solve_map_bbt (_metrics, ms, bbt);
2439                         recompute_tempos (_metrics);
2440                 }
2441         }
2442
2443         Metrics::const_iterator d = future_map.begin();
2444         while (d != future_map.end()) {
2445                 delete (*d);
2446                 ++d;
2447         }
2448
2449         MetricPositionChanged (); // Emit Signal
2450 }
2451
2452 bool
2453 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2454 {
2455         Metrics future_map;
2456         bool can_solve = false;
2457         {
2458                 Glib::Threads::RWLock::WriterLock lm (lock);
2459                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2460                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2461                 recompute_tempos (future_map);
2462
2463                 if (check_solved (future_map)) {
2464                         ts->set_beats_per_minute (bpm.beats_per_minute());
2465                         recompute_map (_metrics);
2466                         can_solve = true;
2467                 }
2468         }
2469
2470         Metrics::const_iterator d = future_map.begin();
2471         while (d != future_map.end()) {
2472                 delete (*d);
2473                 ++d;
2474         }
2475         if (can_solve) {
2476                 MetricPositionChanged (); // Emit Signal
2477         }
2478         return can_solve;
2479 }
2480
2481 void
2482 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2483 {
2484         /*
2485           Ts (future prev_t)   Tnext
2486           |                    |
2487           |     [drag^]        |
2488           |----------|----------
2489                 e_f  pulse(frame)
2490         */
2491
2492         Metrics future_map;
2493
2494         {
2495                 Glib::Threads::RWLock::WriterLock lm (lock);
2496
2497                 if (!ts) {
2498                         return;
2499                 }
2500
2501                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2502                 TempoSection* prev_to_prev_t = 0;
2503                 const frameoffset_t fr_off = end_frame - frame;
2504
2505                 if (prev_t && prev_t->pulse() > 0.0) {
2506                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
2507                 }
2508
2509                 TempoSection* next_t = 0;
2510                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2511                         TempoSection* t = 0;
2512                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2513                                 if (t->frame() > ts->frame()) {
2514                                         next_t = t;
2515                                         break;
2516                                 }
2517                         }
2518                 }
2519
2520                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2521                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2522                 */
2523                 double contribution = 0.0;
2524                 double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2525
2526                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2527                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2528                 }
2529
2530                 frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2531                 double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2532                 double new_bpm;
2533
2534                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2535
2536                         if (prev_t->position_lock_style() == MusicTime) {
2537                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2538
2539                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2540                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2541
2542                                 } else {
2543                                         /* prev to prev is irrelevant */
2544
2545                                         if (start_pulse != prev_t->pulse()) {
2546                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2547                                         } else {
2548                                                 new_bpm = prev_t->beats_per_minute();
2549                                         }
2550                                 }
2551                         } else {
2552                                 /* AudioTime */
2553                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2554                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
2555                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
2556                                 } else {
2557                                         /* prev_to_prev_t is irrelevant */
2558
2559                                         if (end_frame != prev_t->frame()) {
2560                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2561                                         } else {
2562                                                 new_bpm = prev_t->beats_per_minute();
2563                                         }
2564                                 }
2565                         }
2566                 } else {
2567
2568                         double frame_ratio;
2569                         double pulse_ratio;
2570                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2571
2572                         if (prev_to_prev_t) {
2573
2574                                 frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2575                                 pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2576                         } else {
2577
2578                                 frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2579                                 pulse_ratio = (start_pulse / end_pulse);
2580                         }
2581                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2582                 }
2583
2584                 prev_t->set_beats_per_minute (new_bpm);
2585                 recompute_tempos (future_map);
2586                 recompute_meters (future_map);
2587
2588                 if (check_solved (future_map)) {
2589                         ts->set_beats_per_minute (new_bpm);
2590                         recompute_tempos (_metrics);
2591                         recompute_meters (_metrics);
2592                 }
2593         }
2594
2595         Metrics::const_iterator d = future_map.begin();
2596         while (d != future_map.end()) {
2597                 delete (*d);
2598                 ++d;
2599         }
2600
2601         MetricPositionChanged (); // Emit Signal
2602 }
2603
2604 framecnt_t
2605 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2606 {
2607         Glib::Threads::RWLock::ReaderLock lm (lock);
2608
2609         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2610         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2611         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2612
2613         return frame_at_beat_locked (_metrics, total_beats);
2614 }
2615
2616 framepos_t
2617 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2618 {
2619         return round_to_type (fr, dir, Bar);
2620 }
2621
2622 framepos_t
2623 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2624 {
2625         return round_to_type (fr, dir, Beat);
2626 }
2627
2628 framepos_t
2629 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2630 {
2631         Glib::Threads::RWLock::ReaderLock lm (lock);
2632         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2633         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2634         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2635
2636         ticks -= beats * BBT_Time::ticks_per_beat;
2637
2638         if (dir > 0) {
2639                 /* round to next (or same iff dir == RoundUpMaybe) */
2640
2641                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2642
2643                 if (mod == 0 && dir == RoundUpMaybe) {
2644                         /* right on the subdivision, which is fine, so do nothing */
2645
2646                 } else if (mod == 0) {
2647                         /* right on the subdivision, so the difference is just the subdivision ticks */
2648                         ticks += ticks_one_subdivisions_worth;
2649
2650                 } else {
2651                         /* not on subdivision, compute distance to next subdivision */
2652
2653                         ticks += ticks_one_subdivisions_worth - mod;
2654                 }
2655
2656                 if (ticks >= BBT_Time::ticks_per_beat) {
2657                         ticks -= BBT_Time::ticks_per_beat;
2658                 }
2659         } else if (dir < 0) {
2660
2661                 /* round to previous (or same iff dir == RoundDownMaybe) */
2662
2663                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2664
2665                 if (difference == 0 && dir == RoundDownAlways) {
2666                         /* right on the subdivision, but force-rounding down,
2667                            so the difference is just the subdivision ticks */
2668                         difference = ticks_one_subdivisions_worth;
2669                 }
2670
2671                 if (ticks < difference) {
2672                         ticks = BBT_Time::ticks_per_beat - ticks;
2673                 } else {
2674                         ticks -= difference;
2675                 }
2676
2677         } else {
2678                 /* round to nearest */
2679                 double rem;
2680
2681                 /* compute the distance to the previous and next subdivision */
2682
2683                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2684
2685                         /* closer to the next subdivision, so shift forward */
2686
2687                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2688
2689                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2690
2691                         if (ticks > BBT_Time::ticks_per_beat) {
2692                                 ++beats;
2693                                 ticks -= BBT_Time::ticks_per_beat;
2694                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2695                         }
2696
2697                 } else if (rem > 0) {
2698
2699                         /* closer to previous subdivision, so shift backward */
2700
2701                         if (rem > ticks) {
2702                                 if (beats == 0) {
2703                                         /* can't go backwards past zero, so ... */
2704                                         return 0;
2705                                 }
2706                                 /* step back to previous beat */
2707                                 --beats;
2708                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2709                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2710                         } else {
2711                                 ticks = lrint (ticks - rem);
2712                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2713                         }
2714                 } else {
2715                         /* on the subdivision, do nothing */
2716                 }
2717         }
2718
2719         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2720
2721         return ret_frame;
2722 }
2723
2724 void
2725 TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
2726 {
2727         if (sub_num == -1) {
2728                 if (dir > 0) {
2729                         ++when.bars;
2730                         when.beats = 1;
2731                         when.ticks = 0;
2732                 } else if (dir < 0) {
2733                         when.beats = 1;
2734                         when.ticks = 0;
2735                 } else {
2736                         const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
2737                         if ((double) when.beats > bpb / 2.0) {
2738                                 ++when.bars;
2739                         }
2740                         when.beats = 1;
2741                         when.ticks = 0;
2742                 }
2743
2744                 return;
2745
2746         } else if (sub_num == 0) {
2747                 const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
2748                 if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
2749                         ++when.beats;
2750                         while ((double) when.beats > bpb) {
2751                                 ++when.bars;
2752                                 when.beats -= (uint32_t) floor (bpb);
2753                         }
2754                 }
2755                 when.ticks = 0;
2756
2757                 return;
2758         }
2759
2760         const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
2761
2762         if (dir > 0) {
2763                 /* round to next (or same iff dir == RoundUpMaybe) */
2764
2765                 uint32_t mod = when.ticks % ticks_one_subdivisions_worth;
2766
2767                 if (mod == 0 && dir == RoundUpMaybe) {
2768                         /* right on the subdivision, which is fine, so do nothing */
2769
2770                 } else if (mod == 0) {
2771                         /* right on the subdivision, so the difference is just the subdivision ticks */
2772                         when.ticks += ticks_one_subdivisions_worth;
2773
2774                 } else {
2775                         /* not on subdivision, compute distance to next subdivision */
2776
2777                         when.ticks += ticks_one_subdivisions_worth - mod;
2778                 }
2779
2780                 if (when.ticks >= BBT_Time::ticks_per_beat) {
2781                         when.ticks -= BBT_Time::ticks_per_beat;
2782                 }
2783
2784         } else if (dir < 0) {
2785                 /* round to previous (or same iff dir == RoundDownMaybe) */
2786
2787                 uint32_t difference = when.ticks % ticks_one_subdivisions_worth;
2788
2789                 if (difference == 0 && dir == RoundDownAlways) {
2790                         /* right on the subdivision, but force-rounding down,
2791                            so the difference is just the subdivision ticks */
2792                         difference = ticks_one_subdivisions_worth;
2793                 }
2794
2795                 if (when.ticks < difference) {
2796                         when.ticks = BBT_Time::ticks_per_beat - when.ticks;
2797                 } else {
2798                         when.ticks -= difference;
2799                 }
2800
2801         } else {
2802                 /* round to nearest */  double rem;
2803                 if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
2804                         /* closer to the next subdivision, so shift forward */
2805
2806                         when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
2807
2808                         if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
2809                                 ++when.beats;
2810                                 when.ticks -= Timecode::BBT_Time::ticks_per_beat;
2811                         }
2812
2813                 } else if (rem > 0) {
2814                         /* closer to previous subdivision, so shift backward */
2815
2816                         if (rem > when.ticks) {
2817                                 if (when.beats == 0) {
2818                                         /* can't go backwards past zero, so ... */
2819                                 }
2820                                 /* step back to previous beat */
2821                                 --when.beats;
2822                                 when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
2823                         } else {
2824                                 when.ticks = when.ticks - rem;
2825                         }
2826                 }
2827         }
2828 }
2829
2830 framepos_t
2831 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2832 {
2833         Glib::Threads::RWLock::ReaderLock lm (lock);
2834
2835         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2836         BBT_Time bbt (beats_to_bbt_locked (_metrics, beat_at_framepos));
2837
2838         switch (type) {
2839         case Bar:
2840                 if (dir < 0) {
2841                         /* find bar previous to 'frame' */
2842                         bbt.beats = 1;
2843                         bbt.ticks = 0;
2844                         return frame_time_locked (_metrics, bbt);
2845
2846                 } else if (dir > 0) {
2847                         /* find bar following 'frame' */
2848                         ++bbt.bars;
2849                         bbt.beats = 1;
2850                         bbt.ticks = 0;
2851                         return frame_time_locked (_metrics, bbt);
2852                 } else {
2853                         /* true rounding: find nearest bar */
2854                         framepos_t raw_ft = frame_time_locked (_metrics, bbt);
2855                         bbt.beats = 1;
2856                         bbt.ticks = 0;
2857                         framepos_t prev_ft = frame_time_locked (_metrics, bbt);
2858                         ++bbt.bars;
2859                         framepos_t next_ft = frame_time_locked (_metrics, bbt);
2860
2861                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2862                                 return next_ft;
2863                         } else {
2864                                 return prev_ft;
2865                         }
2866                 }
2867
2868                 break;
2869
2870         case Beat:
2871                 if (dir < 0) {
2872                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2873                 } else if (dir > 0) {
2874                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2875                 } else {
2876                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2877                 }
2878                 break;
2879         }
2880
2881         return 0;
2882 }
2883
2884 void
2885 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2886                     framepos_t lower, framepos_t upper)
2887 {
2888         Glib::Threads::RWLock::ReaderLock lm (lock);
2889         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
2890         framecnt_t pos = 0;
2891         /* although the map handles negative beats, bbt doesn't. */
2892         if (cnt < 0.0) {
2893                 cnt = 0.0;
2894         }
2895         while (pos < upper) {
2896                 pos = frame_at_beat_locked (_metrics, cnt);
2897                 const TempoSection tempo = tempo_section_at_locked (_metrics, pos);
2898                 const MeterSection meter = meter_section_at_locked (_metrics, pos);
2899                 const BBT_Time bbt = beats_to_bbt (cnt);
2900                 points.push_back (BBTPoint (meter, tempo_at_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
2901                 ++cnt;
2902         }
2903 }
2904
2905 const TempoSection&
2906 TempoMap::tempo_section_at (framepos_t frame) const
2907 {
2908         Glib::Threads::RWLock::ReaderLock lm (lock);
2909         return tempo_section_at_locked (_metrics, frame);
2910 }
2911
2912 const TempoSection&
2913 TempoMap::tempo_section_at_locked (const Metrics& metrics, framepos_t frame) const
2914 {
2915         Metrics::const_iterator i;
2916         TempoSection* prev = 0;
2917
2918         for (i = metrics.begin(); i != metrics.end(); ++i) {
2919                 TempoSection* t;
2920
2921                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2922                         if (!t->active()) {
2923                                 continue;
2924                         }
2925                         if (prev && t->frame() > frame) {
2926                                 break;
2927                         }
2928
2929                         prev = t;
2930                 }
2931         }
2932
2933         if (prev == 0) {
2934                 fatal << endmsg;
2935                 abort(); /*NOTREACHED*/
2936         }
2937
2938         return *prev;
2939 }
2940
2941 const TempoSection&
2942 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
2943 {
2944         TempoSection* prev_t = 0;
2945         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
2946
2947         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2948                 TempoSection* t;
2949                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2950                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
2951                                 break;
2952                         }
2953                         prev_t = t;
2954                 }
2955
2956         }
2957         return *prev_t;
2958 }
2959
2960 const TempoSection&
2961 TempoMap::tempo_section_at_pulse_locked (const Metrics& metrics, const double& pulse) const
2962 {
2963         TempoSection* prev_t = 0;
2964
2965         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2966                 TempoSection* t;
2967                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2968                         if (prev_t && t->pulse() > pulse) {
2969                                 break;
2970                         }
2971                         prev_t = t;
2972                 }
2973
2974         }
2975         return *prev_t;
2976 }
2977
2978 /* don't use this to calculate length (the tempo is only correct for this frame).
2979    do that stuff based on the beat_at_frame and frame_at_beat api
2980 */
2981 double
2982 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
2983 {
2984         Glib::Threads::RWLock::ReaderLock lm (lock);
2985
2986         const TempoSection* ts_at = &tempo_section_at_locked (_metrics, frame);
2987         const TempoSection* ts_after = 0;
2988         Metrics::const_iterator i;
2989
2990         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2991                 TempoSection* t;
2992
2993                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2994                         if (!t->active()) {
2995                                 continue;
2996                         }
2997                         if ((*i)->frame() > frame) {
2998                                 ts_after = t;
2999                                 break;
3000                         }
3001                 }
3002         }
3003
3004         if (ts_after) {
3005                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
3006         }
3007         /* must be treated as constant tempo */
3008         return ts_at->frames_per_beat (_frame_rate);
3009 }
3010
3011 const Tempo
3012 TempoMap::tempo_at_locked (const Metrics& metrics, const framepos_t& frame) const
3013 {
3014         TempoSection* prev_t = 0;
3015
3016         Metrics::const_iterator i;
3017
3018         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3019                 TempoSection* t;
3020                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3021                         if (!t->active()) {
3022                                 continue;
3023                         }
3024                         if ((prev_t) && t->frame() > frame) {
3025                                 /* t is the section past frame */
3026                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
3027                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
3028                                 return ret_tempo;
3029                         }
3030                         prev_t = t;
3031                 }
3032         }
3033
3034         const double ret = prev_t->beats_per_minute();
3035         const Tempo ret_tempo (ret, prev_t->note_type ());
3036
3037         return ret_tempo;
3038 }
3039
3040 const Tempo
3041 TempoMap::tempo_at (const framepos_t& frame) const
3042 {
3043         Glib::Threads::RWLock::ReaderLock lm (lock);
3044         return tempo_at_locked (_metrics, frame);
3045 }
3046
3047 const MeterSection&
3048 TempoMap::meter_section_at_locked (const Metrics& metrics, framepos_t frame) const
3049 {
3050         Metrics::const_iterator i;
3051         MeterSection* prev = 0;
3052
3053         for (i = metrics.begin(); i != metrics.end(); ++i) {
3054                 MeterSection* m;
3055
3056                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3057
3058                         if (prev && (*i)->frame() > frame) {
3059                                 break;
3060                         }
3061
3062                         prev = m;
3063                 }
3064         }
3065
3066         if (prev == 0) {
3067                 fatal << endmsg;
3068                 abort(); /*NOTREACHED*/
3069         }
3070
3071         return *prev;
3072 }
3073
3074
3075 const MeterSection&
3076 TempoMap::meter_section_at (framepos_t frame) const
3077 {
3078         Glib::Threads::RWLock::ReaderLock lm (lock);
3079         return meter_section_at_locked (_metrics, frame);
3080 }
3081
3082 const MeterSection&
3083 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3084 {
3085         MeterSection* prev_m = 0;
3086
3087         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3088                 MeterSection* m;
3089                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3090                         if (prev_m && m->beat() > beat) {
3091                                 break;
3092                         }
3093                         prev_m = m;
3094                 }
3095
3096         }
3097         return *prev_m;
3098 }
3099
3100 const MeterSection&
3101 TempoMap::meter_section_at_beat (double beat) const
3102 {
3103         Glib::Threads::RWLock::ReaderLock lm (lock);
3104         return meter_section_at_beat_locked (_metrics, beat);
3105 }
3106
3107 const Meter&
3108 TempoMap::meter_at (framepos_t frame) const
3109 {
3110         TempoMetric m (metric_at (frame));
3111         return m.meter();
3112 }
3113
3114 void
3115 TempoMap::fix_legacy_session ()
3116 {
3117         MeterSection* prev_m = 0;
3118         TempoSection* prev_t = 0;
3119
3120         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3121                 MeterSection* m;
3122                 TempoSection* t;
3123
3124                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3125                         if (!m->movable()) {
3126                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3127                                 m->set_beat (bbt);
3128                                 m->set_pulse (0.0);
3129                                 m->set_frame (0);
3130                                 m->set_position_lock_style (AudioTime);
3131                                 prev_m = m;
3132                                 continue;
3133                         }
3134                         if (prev_m) {
3135                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3136                                                                           + (m->bbt().beats - 1)
3137                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3138                                                                           , m->bbt());
3139                                 m->set_beat (start);
3140                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3141                                         + (m->bbt().beats - 1)
3142                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3143                                 m->set_pulse (start_beat / prev_m->note_divisor());
3144                         }
3145                         prev_m = m;
3146                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3147
3148                         if (!t->active()) {
3149                                 continue;
3150                         }
3151
3152                         if (!t->movable()) {
3153                                 t->set_pulse (0.0);
3154                                 t->set_frame (0);
3155                                 t->set_position_lock_style (AudioTime);
3156                                 prev_t = t;
3157                                 continue;
3158                         }
3159
3160                         if (prev_t) {
3161                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3162                                         + (t->legacy_bbt().beats - 1)
3163                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3164                                 if (prev_m) {
3165                                         t->set_pulse (beat / prev_m->note_divisor());
3166                                 } else {
3167                                         /* really shouldn't happen but.. */
3168                                         t->set_pulse (beat / 4.0);
3169                                 }
3170                         }
3171                         prev_t = t;
3172                 }
3173         }
3174 }
3175
3176 XMLNode&
3177 TempoMap::get_state ()
3178 {
3179         Metrics::const_iterator i;
3180         XMLNode *root = new XMLNode ("TempoMap");
3181
3182         {
3183                 Glib::Threads::RWLock::ReaderLock lm (lock);
3184                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3185                         root->add_child_nocopy ((*i)->get_state());
3186                 }
3187         }
3188
3189         return *root;
3190 }
3191
3192 int
3193 TempoMap::set_state (const XMLNode& node, int /*version*/)
3194 {
3195         {
3196                 Glib::Threads::RWLock::WriterLock lm (lock);
3197
3198                 XMLNodeList nlist;
3199                 XMLNodeConstIterator niter;
3200                 Metrics old_metrics (_metrics);
3201                 _metrics.clear();
3202
3203                 nlist = node.children();
3204
3205                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3206                         XMLNode* child = *niter;
3207
3208                         if (child->name() == TempoSection::xml_state_node_name) {
3209
3210                                 try {
3211                                         TempoSection* ts = new TempoSection (*child);
3212                                         _metrics.push_back (ts);
3213                                 }
3214
3215                                 catch (failed_constructor& err){
3216                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3217                                         _metrics = old_metrics;
3218                                         break;
3219                                 }
3220
3221                         } else if (child->name() == MeterSection::xml_state_node_name) {
3222
3223                                 try {
3224                                         MeterSection* ms = new MeterSection (*child);
3225                                         _metrics.push_back (ms);
3226                                 }
3227
3228                                 catch (failed_constructor& err) {
3229                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3230                                         _metrics = old_metrics;
3231                                         break;
3232                                 }
3233                         }
3234                 }
3235
3236                 if (niter == nlist.end()) {
3237                         MetricSectionSorter cmp;
3238                         _metrics.sort (cmp);
3239                 }
3240
3241                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3242                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3243                         TempoSection* t;
3244                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3245                                 if (t->legacy_bbt().bars != 0) {
3246                                         fix_legacy_session();
3247                                         break;
3248                                 }
3249                                 break;
3250                         }
3251                 }
3252
3253                 /* check for multiple tempo/meters at the same location, which
3254                    ardour2 somehow allowed.
3255                 */
3256
3257                 Metrics::iterator prev = _metrics.end();
3258                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3259                         if (prev != _metrics.end()) {
3260                                 MeterSection* ms;
3261                                 MeterSection* prev_m;
3262                                 TempoSection* ts;
3263                                 TempoSection* prev_t;
3264                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3265                                         if (prev_m->pulse() == ms->pulse()) {
3266                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3267                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3268                                                 return -1;
3269                                         }
3270                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3271                                         if (prev_t->pulse() == ts->pulse()) {
3272                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3273                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3274                                                 return -1;
3275                                         }
3276                                 }
3277                         }
3278                         prev = i;
3279                 }
3280
3281                 recompute_map (_metrics);
3282         }
3283
3284         PropertyChanged (PropertyChange ());
3285
3286         return 0;
3287 }
3288
3289 void
3290 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3291 {
3292         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3293         const MeterSection* m;
3294         const TempoSection* t;
3295         const TempoSection* prev_t = 0;
3296
3297         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3298
3299                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3300                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3301                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3302                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3303                         if (prev_t) {
3304                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3305                                 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;
3306                         }
3307                         prev_t = t;
3308                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3309                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3310                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3311                 }
3312         }
3313         o << "------" << std::endl;
3314 }
3315
3316 int
3317 TempoMap::n_tempos() const
3318 {
3319         Glib::Threads::RWLock::ReaderLock lm (lock);
3320         int cnt = 0;
3321
3322         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3323                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3324                         cnt++;
3325                 }
3326         }
3327
3328         return cnt;
3329 }
3330
3331 int
3332 TempoMap::n_meters() const
3333 {
3334         Glib::Threads::RWLock::ReaderLock lm (lock);
3335         int cnt = 0;
3336
3337         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3338                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3339                         cnt++;
3340                 }
3341         }
3342
3343         return cnt;
3344 }
3345
3346 void
3347 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3348 {
3349         {
3350                 Glib::Threads::RWLock::WriterLock lm (lock);
3351                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3352                         if ((*i)->frame() >= where && (*i)->movable ()) {
3353                                 (*i)->set_frame ((*i)->frame() + amount);
3354                         }
3355                 }
3356
3357                 /* now reset the BBT time of all metrics, based on their new
3358                  * audio time. This is the only place where we do this reverse
3359                  * timestamp.
3360                  */
3361
3362                 Metrics::iterator i;
3363                 const MeterSection* meter;
3364                 const TempoSection* tempo;
3365                 MeterSection *m;
3366                 TempoSection *t;
3367
3368                 meter = &first_meter ();
3369                 tempo = &first_tempo ();
3370
3371                 BBT_Time start;
3372                 BBT_Time end;
3373
3374                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3375
3376                 bool first = true;
3377                 MetricSection* prev = 0;
3378
3379                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3380
3381                         BBT_Time bbt;
3382                         //TempoMetric metric (*meter, *tempo);
3383                         MeterSection* ms = const_cast<MeterSection*>(meter);
3384                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3385                         if (prev) {
3386                                 if (ts){
3387                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3388                                                 if (!t->active()) {
3389                                                         continue;
3390                                                 }
3391                                                 ts->set_pulse (t->pulse());
3392                                         }
3393                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3394                                                 ts->set_pulse (m->pulse());
3395                                         }
3396                                         ts->set_frame (prev->frame());
3397
3398                                 }
3399                                 if (ms) {
3400                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3401                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3402                                                 ms->set_beat (start);
3403                                                 ms->set_pulse (m->pulse());
3404                                         }
3405                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3406                                                 if (!t->active()) {
3407                                                         continue;
3408                                                 }
3409                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3410                                                 pair<double, BBT_Time> start = make_pair (beat, beats_to_bbt_locked (_metrics, beat));
3411                                                 ms->set_beat (start);
3412                                                 ms->set_pulse (t->pulse());
3413                                         }
3414                                         ms->set_frame (prev->frame());
3415                                 }
3416
3417                         } else {
3418                                 // metric will be at frames=0 bbt=1|1|0 by default
3419                                 // which is correct for our purpose
3420                         }
3421
3422                         // cerr << bbt << endl;
3423
3424                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3425                                 if (!t->active()) {
3426                                         continue;
3427                                 }
3428                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3429                                 tempo = t;
3430                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3431                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3432                                 bbt_time (m->frame(), bbt);
3433
3434                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3435
3436                                 if (first) {
3437                                         first = false;
3438                                 } else {
3439
3440                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3441                                                 /* round up to next beat */
3442                                                 bbt.beats += 1;
3443                                         }
3444
3445                                         bbt.ticks = 0;
3446
3447                                         if (bbt.beats != 1) {
3448                                                 /* round up to next bar */
3449                                                 bbt.bars += 1;
3450                                                 bbt.beats = 1;
3451                                         }
3452                                 }
3453                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3454                                 m->set_beat (start);
3455                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3456                                 meter = m;
3457                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3458                         } else {
3459                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3460                                 abort(); /*NOTREACHED*/
3461                         }
3462
3463                         prev = (*i);
3464                 }
3465
3466                 recompute_map (_metrics);
3467         }
3468
3469
3470         PropertyChanged (PropertyChange ());
3471 }
3472 bool
3473 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3474 {
3475         bool moved = false;
3476
3477         std::list<MetricSection*> metric_kill_list;
3478
3479         TempoSection* last_tempo = NULL;
3480         MeterSection* last_meter = NULL;
3481         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3482         bool meter_after = false; // is there a meter marker likewise?
3483         {
3484                 Glib::Threads::RWLock::WriterLock lm (lock);
3485                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3486                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3487                                 metric_kill_list.push_back(*i);
3488                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3489                                 if (lt)
3490                                         last_tempo = lt;
3491                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3492                                 if (lm)
3493                                         last_meter = lm;
3494                         }
3495                         else if ((*i)->frame() >= where) {
3496                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3497                                 (*i)->set_frame ((*i)->frame() - amount);
3498                                 if ((*i)->frame() == where) {
3499                                         // marker was immediately after end of range
3500                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3501                                         meter_after = dynamic_cast<MeterSection*> (*i);
3502                                 }
3503                                 moved = true;
3504                         }
3505                 }
3506
3507                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3508                 if (last_tempo && !tempo_after) {
3509                         metric_kill_list.remove(last_tempo);
3510                         last_tempo->set_frame(where);
3511                         moved = true;
3512                 }
3513                 if (last_meter && !meter_after) {
3514                         metric_kill_list.remove(last_meter);
3515                         last_meter->set_frame(where);
3516                         moved = true;
3517                 }
3518
3519                 //remove all the remaining metrics
3520                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3521                         _metrics.remove(*i);
3522                         moved = true;
3523                 }
3524
3525                 if (moved) {
3526                         recompute_map (_metrics);
3527                 }
3528         }
3529         PropertyChanged (PropertyChange ());
3530         return moved;
3531 }
3532
3533 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3534  *  pos can be -ve, if required.
3535  */
3536 framepos_t
3537 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3538 {
3539         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
3540 }
3541
3542 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3543 framepos_t
3544 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3545 {
3546         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
3547 }
3548
3549 /** Add the BBT interval op to pos and return the result */
3550 framepos_t
3551 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3552 {
3553         Glib::Threads::RWLock::ReaderLock lm (lock);
3554
3555         BBT_Time pos_bbt = beats_to_bbt_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3556         pos_bbt.ticks += op.ticks;
3557         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3558                 ++pos_bbt.beats;
3559                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3560         }
3561         pos_bbt.beats += op.beats;
3562         /* the meter in effect will start on the bar */
3563         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();
3564         while (pos_bbt.beats >= divisions_per_bar + 1) {
3565                 ++pos_bbt.bars;
3566                 divisions_per_bar = meter_section_at_beat (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3567                 pos_bbt.beats -= divisions_per_bar;
3568         }
3569         pos_bbt.bars += op.bars;
3570
3571         return frame_time_locked (_metrics, pos_bbt);
3572 }
3573
3574 /** Count the number of beats that are equivalent to distance when going forward,
3575     starting at pos.
3576 */
3577 Evoral::Beats
3578 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3579 {
3580         return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
3581 }
3582
3583 struct bbtcmp {
3584     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3585             return a < b;
3586     }
3587 };
3588
3589 std::ostream&
3590 operator<< (std::ostream& o, const Meter& m) {
3591         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3592 }
3593
3594 std::ostream&
3595 operator<< (std::ostream& o, const Tempo& t) {
3596         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3597 }
3598
3599 std::ostream&
3600 operator<< (std::ostream& o, const MetricSection& section) {
3601
3602         o << "MetricSection @ " << section.frame() << ' ';
3603
3604         const TempoSection* ts;
3605         const MeterSection* ms;
3606
3607         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3608                 o << *((const Tempo*) ts);
3609         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3610                 o << *((const Meter*) ms);
3611         }
3612
3613         return o;
3614 }