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