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