Tempo ramps - comments,
[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    pulse p 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& p, const framecnt_t& frame_rate) const
227 {
228         if (_type == Constant || _c_func == 0.0) {
229                 return ((p - 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_frame_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_frame_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         /* audio locked meters fake their beat */
1419         if (next_m && next_m->beat() < beat) {
1420                 return next_m->beat();
1421         }
1422
1423         return beat;
1424 }
1425
1426 framecnt_t
1427 TempoMap::frame_at_beat (const double& beat) const
1428 {
1429         Glib::Threads::RWLock::ReaderLock lm (lock);
1430         return frame_at_beat_locked (_metrics, beat);
1431 }
1432
1433 /* meter section based */
1434 framecnt_t
1435 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1436 {
1437         const TempoSection* prev_t = &tempo_section_at_beat_locked (metrics, beat);
1438         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1439
1440         return prev_t->frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
1441 }
1442
1443 Tempo
1444 TempoMap::tempo_at_frame (const framepos_t& frame) const
1445 {
1446         Glib::Threads::RWLock::ReaderLock lm (lock);
1447         return tempo_at_frame_locked (_metrics, frame);
1448 }
1449
1450 Tempo
1451 TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1452 {
1453         TempoSection* prev_t = 0;
1454
1455         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1456                 TempoSection* t;
1457                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1458                         if (!t->active()) {
1459                                 continue;
1460                         }
1461                         if ((prev_t) && t->frame() > frame) {
1462                                 /* t is the section past frame */
1463                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
1464                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
1465                                 return ret_tempo;
1466                         }
1467                         prev_t = t;
1468                 }
1469         }
1470
1471         const double ret = prev_t->beats_per_minute();
1472         const Tempo ret_tempo (ret, prev_t->note_type ());
1473
1474         return ret_tempo;
1475 }
1476
1477 /** returns the frame at which the supplied tempo occurs, or
1478  *  the frame of the last tempo section (search exhausted)
1479  *  only the position of the first occurence will be returned
1480  *  (extend me)
1481 */
1482 framepos_t
1483 TempoMap::frame_at_tempo (const Tempo& tempo) const
1484 {
1485         Glib::Threads::RWLock::ReaderLock lm (lock);
1486         return frame_at_tempo_locked (_metrics, tempo);
1487 }
1488
1489
1490 framepos_t
1491 TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1492 {
1493         TempoSection* prev_t = 0;
1494         const double tempo_ppm = tempo.beats_per_minute() / tempo.note_type();
1495
1496         Metrics::const_iterator i;
1497
1498         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
1499                 TempoSection* t;
1500                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1501
1502                         if (!t->active()) {
1503                                 continue;
1504                         }
1505
1506                         const double t_ppm = t->beats_per_minute() / t->note_type();
1507
1508                         if (t_ppm == tempo_ppm) {
1509                                 return t->frame();
1510                         }
1511
1512                         if (prev_t) {
1513                                 const double prev_t_ppm = prev_t->beats_per_minute() / prev_t->note_type();
1514
1515                                 if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) {
1516                                         const framepos_t ret_frame = prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate);
1517                                         return ret_frame;
1518                                 }
1519                         }
1520                         prev_t = t;
1521                 }
1522         }
1523
1524         return prev_t->frame();
1525 }
1526
1527 /** more precise than doing tempo_at_frame (frame_at_beat (b)),
1528  *  as there is no intermediate frame rounding.
1529  */
1530 Tempo
1531 TempoMap::tempo_at_beat (const double& beat) const
1532 {
1533         Glib::Threads::RWLock::ReaderLock lm (lock);
1534         const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
1535         const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
1536         const double note_type = prev_t->note_type();
1537
1538         return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()) * note_type, note_type);
1539 }
1540
1541 double
1542 TempoMap::pulse_at_beat (const double& beat) const
1543 {
1544         Glib::Threads::RWLock::ReaderLock lm (lock);
1545         return pulse_at_beat_locked (_metrics, beat);
1546 }
1547
1548 double
1549 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1550 {
1551         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1552
1553         return prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1554 }
1555
1556 double
1557 TempoMap::beat_at_pulse (const double& pulse) const
1558 {
1559         Glib::Threads::RWLock::ReaderLock lm (lock);
1560         return beat_at_pulse_locked (_metrics, pulse);
1561 }
1562
1563 double
1564 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1565 {
1566         MeterSection* prev_m = 0;
1567
1568         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1569                 MeterSection* m;
1570                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1571                         if (prev_m && m->pulse() > pulse) {
1572                                 if (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > m->beat()) {
1573                                         break;
1574                                 }
1575                         }
1576                         prev_m = m;
1577                 }
1578         }
1579
1580         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1581         return ret;
1582 }
1583
1584 double
1585 TempoMap::pulse_at_frame (const framecnt_t& frame) const
1586 {
1587         Glib::Threads::RWLock::ReaderLock lm (lock);
1588         return pulse_at_frame_locked (_metrics, frame);
1589 }
1590
1591 /* tempo section based */
1592 double
1593 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1594 {
1595         /* HOLD (at least) THE READER LOCK */
1596         TempoSection* prev_t = 0;
1597
1598         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1599                 TempoSection* t;
1600                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1601                         if (!t->active()) {
1602                                 continue;
1603                         }
1604                         if (prev_t && t->frame() > frame) {
1605                                 /*the previous ts is the one containing the frame */
1606                                 const double ret = prev_t->pulse_at_frame (frame, _frame_rate);
1607                                 return ret;
1608                         }
1609                         prev_t = t;
1610                 }
1611         }
1612
1613         /* treated as constant for this ts */
1614         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1615
1616         return pulses_in_section + prev_t->pulse();
1617 }
1618
1619 framecnt_t
1620 TempoMap::frame_at_pulse (const double& pulse) const
1621 {
1622         Glib::Threads::RWLock::ReaderLock lm (lock);
1623         return frame_at_pulse_locked (_metrics, pulse);
1624 }
1625
1626 /* tempo section based */
1627 framecnt_t
1628 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1629 {
1630         /* HOLD THE READER LOCK */
1631
1632         const TempoSection* prev_t = 0;
1633
1634         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1635                 TempoSection* t;
1636
1637                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1638                         if (!t->active()) {
1639                                 continue;
1640                         }
1641                         if (prev_t && t->pulse() > pulse) {
1642                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1643                         }
1644
1645                         prev_t = t;
1646                 }
1647         }
1648         /* must be treated as constant, irrespective of _type */
1649         double const pulses_in_section = pulse - prev_t->pulse();
1650         double const dtime = pulses_in_section * prev_t->frames_per_pulse (_frame_rate);
1651
1652         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_t->frame();
1653
1654         return ret;
1655 }
1656
1657 double
1658 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1659 {
1660         Glib::Threads::RWLock::ReaderLock lm (lock);
1661         return beat_at_bbt_locked (_metrics, bbt);
1662 }
1663
1664
1665 double
1666 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1667 {
1668         /* CALLER HOLDS READ LOCK */
1669
1670         MeterSection* prev_m = 0;
1671
1672         /* because audio-locked meters have 'fake' integral beats,
1673            there is no pulse offset here.
1674         */
1675         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1676                 MeterSection* m;
1677                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1678                         if (prev_m) {
1679                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1680                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1681                                         break;
1682                                 }
1683                         }
1684                         prev_m = m;
1685                 }
1686         }
1687
1688         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1689         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1690         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1691
1692         return ret;
1693 }
1694
1695 Timecode::BBT_Time
1696 TempoMap::bbt_at_beat (const double& beats)
1697 {
1698         Glib::Threads::RWLock::ReaderLock lm (lock);
1699         return bbt_at_beat_locked (_metrics, beats);
1700 }
1701
1702 Timecode::BBT_Time
1703 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1704 {
1705         /* CALLER HOLDS READ LOCK */
1706         MeterSection* prev_m = 0;
1707         const double beats = max (0.0, b);
1708
1709         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1710                 MeterSection* m = 0;
1711
1712                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1713                         if (prev_m) {
1714                                 if (m->beat() > beats) {
1715                                         /* this is the meter after the one our beat is on*/
1716                                         break;
1717                                 }
1718                         }
1719
1720                         prev_m = m;
1721                 }
1722         }
1723
1724         const double beats_in_ms = beats - prev_m->beat();
1725         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1726         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1727         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1728         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1729
1730         BBT_Time ret;
1731
1732         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1733         ret.beats = (uint32_t) floor (remaining_beats);
1734         ret.bars = total_bars;
1735
1736         /* 0 0 0 to 1 1 0 - based mapping*/
1737         ++ret.bars;
1738         ++ret.beats;
1739
1740         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1741                 ++ret.beats;
1742                 ret.ticks -= BBT_Time::ticks_per_beat;
1743         }
1744
1745         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1746                 ++ret.bars;
1747                 ret.beats = 1;
1748         }
1749
1750         return ret;
1751 }
1752
1753 double
1754 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1755 {
1756         Glib::Threads::RWLock::ReaderLock lm (lock);
1757
1758         return pulse_at_bbt_locked (_metrics, bbt);
1759 }
1760
1761 double
1762 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1763 {
1764         /* CALLER HOLDS READ LOCK */
1765
1766         MeterSection* prev_m = 0;
1767
1768         /* because audio-locked meters have 'fake' integral beats,
1769            there is no pulse offset here.
1770         */
1771         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1772                 MeterSection* m;
1773                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1774                         if (prev_m) {
1775                                 if (m->bbt().bars > bbt.bars) {
1776                                         break;
1777                                 }
1778                         }
1779                         prev_m = m;
1780                 }
1781         }
1782
1783         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1784         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1785         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1786
1787         return ret;
1788 }
1789
1790 Timecode::BBT_Time
1791 TempoMap::bbt_at_pulse (const double& pulse)
1792 {
1793         Glib::Threads::RWLock::ReaderLock lm (lock);
1794
1795         return bbt_at_pulse_locked (_metrics, pulse);
1796 }
1797
1798 Timecode::BBT_Time
1799 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1800 {
1801         MeterSection* prev_m = 0;
1802
1803         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1804                 MeterSection* m = 0;
1805
1806                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1807
1808                         if (prev_m) {
1809                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1810                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1811                                         /* this is the meter after the one our beat is on*/
1812                                         break;
1813                                 }
1814                         }
1815
1816                         prev_m = m;
1817                 }
1818         }
1819
1820         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1821         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1822         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1823         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1824         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1825
1826         BBT_Time ret;
1827
1828         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1829         ret.beats = (uint32_t) floor (remaining_beats);
1830         ret.bars = total_bars;
1831
1832         /* 0 0 0 to 1 1 0 mapping*/
1833         ++ret.bars;
1834         ++ret.beats;
1835
1836         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1837                 ++ret.beats;
1838                 ret.ticks -= BBT_Time::ticks_per_beat;
1839         }
1840
1841         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1842                 ++ret.bars;
1843                 ret.beats = 1;
1844         }
1845
1846         return ret;
1847 }
1848
1849 BBT_Time
1850 TempoMap::bbt_at_frame (framepos_t frame)
1851 {
1852         if (frame < 0) {
1853                 BBT_Time bbt;
1854                 bbt.bars = 1;
1855                 bbt.beats = 1;
1856                 bbt.ticks = 0;
1857                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1858                 return bbt;
1859         }
1860         Glib::Threads::RWLock::ReaderLock lm (lock);
1861
1862         return bbt_at_frame_locked (_metrics, frame);
1863 }
1864
1865 Timecode::BBT_Time
1866 TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1867 {
1868         if (frame < 0) {
1869                 BBT_Time bbt;
1870                 bbt.bars = 1;
1871                 bbt.beats = 1;
1872                 bbt.ticks = 0;
1873                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1874                 return bbt;
1875         }
1876         const double beat = beat_at_frame_locked (metrics, frame);
1877
1878         return bbt_at_beat_locked (metrics, beat);
1879 }
1880
1881 framepos_t
1882 TempoMap::frame_at_bbt (const BBT_Time& bbt)
1883 {
1884         if (bbt.bars < 1) {
1885                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1886                 return 0;
1887         }
1888
1889         if (bbt.beats < 1) {
1890                 throw std::logic_error ("beats are counted from one");
1891         }
1892         Glib::Threads::RWLock::ReaderLock lm (lock);
1893
1894         return frame_at_bbt_locked (_metrics, bbt);
1895 }
1896
1897 /* meter & tempo section based */
1898 framepos_t
1899 TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
1900 {
1901         /* HOLD THE READER LOCK */
1902
1903         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
1904         return ret;
1905 }
1906
1907 bool
1908 TempoMap::check_solved (const Metrics& metrics) const
1909 {
1910         TempoSection* prev_t = 0;
1911         MeterSection* prev_m = 0;
1912
1913         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1914                 TempoSection* t;
1915                 MeterSection* m;
1916                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1917                         if (!t->active()) {
1918                                 continue;
1919                         }
1920                         if (prev_t) {
1921                                 /* check ordering */
1922                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
1923                                         return false;
1924                                 }
1925
1926                                 /* precision check ensures tempo and frames align.*/
1927                                 if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
1928                                         if (!t->locked_to_meter()) {
1929                                                 return false;
1930                                         }
1931                                 }
1932
1933                                 /* gradient limit - who knows what it should be?
1934                                    things are also ok (if a little chaotic) without this
1935                                 */
1936                                 if (fabs (prev_t->c_func()) > 1000.0) {
1937                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
1938                                         return false;
1939                                 }
1940                         }
1941                         prev_t = t;
1942                 }
1943
1944                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1945                         if (prev_m && m->position_lock_style() == AudioTime) {
1946                                 TempoSection* t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (metrics, m->frame() - 1));
1947                                 const double nascent_m_pulse = ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
1948                                 const framepos_t nascent_m_frame = t->frame_at_pulse (nascent_m_pulse, _frame_rate);
1949
1950                                 if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
1951                                         return false;
1952                                 }
1953                         }
1954
1955                         prev_m = m;
1956                 }
1957
1958         }
1959
1960         return true;
1961 }
1962
1963 bool
1964 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
1965 {
1966         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1967                 TempoSection* t;
1968                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1969                         if (!t->movable()) {
1970                                 t->set_active (true);
1971                                 continue;
1972                         }
1973                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
1974                                 t->set_active (false);
1975                                 t->set_pulse (0.0);
1976                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
1977                                 t->set_active (true);
1978                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
1979                                 return false;
1980                         }
1981                 }
1982         }
1983         return true;
1984 }
1985
1986 bool
1987 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
1988 {
1989         TempoSection* prev_t = 0;
1990         TempoSection* section_prev = 0;
1991         framepos_t first_m_frame = 0;
1992
1993         /* can't move a tempo before the first meter */
1994         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1995                 MeterSection* m;
1996                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1997                         if (!m->movable()) {
1998                                 first_m_frame = m->frame();
1999                                 break;
2000                         }
2001                 }
2002         }
2003         if (section->movable() && frame <= first_m_frame) {
2004                 return false;
2005         }
2006
2007         section->set_active (true);
2008         section->set_frame (frame);
2009
2010         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2011                 TempoSection* t;
2012                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2013
2014                         if (!t->active()) {
2015                                 continue;
2016                         }
2017                         if (prev_t) {
2018                                 if (t == section) {
2019                                         section_prev = prev_t;
2020                                         continue;
2021                                 }
2022                                 if (t->position_lock_style() == MusicTime) {
2023                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2024                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2025                                 } else {
2026                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2027                                         if (!t->locked_to_meter()) {
2028                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2029                                         }
2030                                 }
2031                         }
2032                         prev_t = t;
2033                 }
2034         }
2035
2036         if (section_prev) {
2037                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
2038                 if (!section->locked_to_meter()) {
2039                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2040                 }
2041         }
2042
2043         recompute_tempos (imaginary);
2044
2045         if (check_solved (imaginary)) {
2046                 return true;
2047         }
2048
2049         MetricSectionFrameSorter fcmp;
2050         imaginary.sort (fcmp);
2051
2052         recompute_tempos (imaginary);
2053
2054         if (check_solved (imaginary)) {
2055                 return true;
2056         }
2057
2058         return false;
2059 }
2060
2061 bool
2062 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2063 {
2064         TempoSection* prev_t = 0;
2065         TempoSection* section_prev = 0;
2066
2067         section->set_pulse (pulse);
2068
2069         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2070                 TempoSection* t;
2071                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2072                         if (!t->active()) {
2073                                 continue;
2074                         }
2075                         if (!t->movable()) {
2076                                 t->set_pulse (0.0);
2077                                 prev_t = t;
2078                                 continue;
2079                         }
2080                         if (prev_t) {
2081                                 if (t == section) {
2082                                         section_prev = prev_t;
2083                                         continue;
2084                                 }
2085                                 if (t->position_lock_style() == MusicTime) {
2086                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2087                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2088                                 } else {
2089                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2090                                         if (!t->locked_to_meter()) {
2091                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2092                                         }
2093                                 }
2094                         }
2095                         prev_t = t;
2096                 }
2097         }
2098
2099         if (section_prev) {
2100                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
2101                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2102         }
2103
2104         recompute_tempos (imaginary);
2105
2106         if (check_solved (imaginary)) {
2107                 return true;
2108         }
2109
2110         MetricSectionSorter cmp;
2111         imaginary.sort (cmp);
2112
2113         recompute_tempos (imaginary);
2114         /* Reordering
2115          * XX need a restriction here, but only for this case,
2116          * as audio locked tempos don't interact in the same way.
2117          *
2118          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2119          * e.g.
2120          * |50 bpm                        |250 bpm |60 bpm
2121          *                drag 250 to the pulse after 60->
2122          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2123          */
2124         if (check_solved (imaginary)) {
2125                 return true;
2126         }
2127
2128         return false;
2129 }
2130
2131 bool
2132 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2133 {
2134         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2135         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2136         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2137                 return false;
2138         }
2139
2140         if (!section->movable()) {
2141                 /* lock the first tempo to our first meter */
2142                 if (!set_active_tempos (imaginary, frame)) {
2143                         return false;
2144                 }
2145         }
2146
2147         TempoSection* meter_locked_tempo = 0;
2148
2149         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2150                 TempoSection* t;
2151                 if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2152                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2153                                 meter_locked_tempo = t;
2154                                 break;
2155                         }
2156                 }
2157         }
2158
2159         if (!meter_locked_tempo) {
2160                 return false;
2161         }
2162
2163         MeterSection* prev_m = 0;
2164         Metrics future_map;
2165         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2166         bool solved = false;
2167
2168         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2169                 MeterSection* m;
2170                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2171                         if (m == section){
2172                                 if (prev_m && section->movable()) {
2173                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2174                                         if (beats + prev_m->beat() < section->beat()) {
2175                                                 /* set the frame/pulse corresponding to its musical position,
2176                                                  * as an earlier time than this has been requested.
2177                                                 */
2178                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2179                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2180
2181                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2182
2183                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2184                                                         meter_locked_tempo->set_pulse (new_pulse);
2185                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2186                                                         section->set_frame (smallest_frame);
2187                                                         section->set_pulse (new_pulse);
2188                                                 } else {
2189                                                         solved = false;
2190                                                 }
2191
2192                                                 Metrics::const_iterator d = future_map.begin();
2193                                                 while (d != future_map.end()) {
2194                                                         delete (*d);
2195                                                         ++d;
2196                                                 }
2197
2198                                                 if (!solved) {
2199                                                         return false;
2200                                                 }
2201                                         } else {
2202                                                 /* all is ok. set section's locked tempo if allowed.
2203                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2204                                                    XX this check could possibly go. its never actually happened here.
2205                                                 */
2206                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2207                                                 meter_copy->set_frame (frame);
2208
2209                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2210                                                         section->set_frame (frame);
2211                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2212                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2213                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2214                                                 } else {
2215                                                         solved = false;
2216                                                 }
2217
2218                                                 Metrics::const_iterator d = future_map.begin();
2219                                                 while (d != future_map.end()) {
2220                                                         delete (*d);
2221                                                         ++d;
2222                                                 }
2223
2224                                                 if (!solved) {
2225                                                         return false;
2226                                                 }
2227                                         }
2228                                 } else {
2229                                         /* not movable (first meter atm) */
2230
2231                                         tempo_copy->set_frame (frame);
2232                                         tempo_copy->set_pulse (0.0);
2233
2234                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2235                                                 section->set_frame (frame);
2236                                                 meter_locked_tempo->set_frame (frame);
2237                                                 meter_locked_tempo->set_pulse (0.0);
2238                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2239                                         } else {
2240                                                 solved = false;
2241                                         }
2242
2243                                         Metrics::const_iterator d = future_map.begin();
2244                                         while (d != future_map.end()) {
2245                                                 delete (*d);
2246                                                 ++d;
2247                                         }
2248
2249                                         if (!solved) {
2250                                                 return false;
2251                                         }
2252
2253                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2254                                         section->set_beat (b_bbt);
2255                                         section->set_pulse (0.0);
2256
2257                                 }
2258                                 break;
2259                         }
2260
2261                         prev_m = m;
2262                 }
2263         }
2264
2265         MetricSectionFrameSorter fcmp;
2266         imaginary.sort (fcmp);
2267
2268         recompute_meters (imaginary);
2269
2270         return true;
2271 }
2272
2273 bool
2274 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2275 {
2276         /* disallow setting section to an existing meter's bbt */
2277         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2278                 MeterSection* m;
2279                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2280                         if (m != section && m->bbt().bars == when.bars) {
2281                                 return false;
2282                         }
2283                 }
2284         }
2285
2286         MeterSection* prev_m = 0;
2287         MeterSection* section_prev = 0;
2288
2289         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2290                 MeterSection* m;
2291                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2292                         pair<double, BBT_Time> b_bbt;
2293                         double new_pulse = 0.0;
2294
2295                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2296                                 section_prev = prev_m;
2297                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2298                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2299                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2300
2301                                 section->set_beat (b_bbt);
2302                                 section->set_pulse (pulse);
2303                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2304                                 prev_m = section;
2305                                 continue;
2306                         }
2307
2308                         if (m->position_lock_style() == AudioTime) {
2309                                 TempoSection* meter_locked_tempo = 0;
2310
2311                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2312                                         TempoSection* t;
2313                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2314                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2315                                                         meter_locked_tempo = t;
2316                                                         break;
2317                                                 }
2318                                         }
2319                                 }
2320
2321                                 if (!meter_locked_tempo) {
2322                                         return false;
2323                                 }
2324
2325                                 if (prev_m) {
2326                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2327
2328                                         if (beats + prev_m->beat() != m->beat()) {
2329                                                 /* tempo/ meter change caused a change in beat (bar). */
2330                                                 b_bbt = make_pair (beats + prev_m->beat()
2331                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2332                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2333                                         } else if (m->movable()) {
2334                                                 b_bbt = make_pair (m->beat(), m->bbt());
2335                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2336                                         }
2337                                 } else {
2338                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2339                                 }
2340
2341                                 meter_locked_tempo->set_pulse (new_pulse);
2342                                 m->set_beat (b_bbt);
2343                                 m->set_pulse (new_pulse);
2344
2345                         } else {
2346                                 /* MusicTime */
2347                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2348                                 if (beats + prev_m->beat() != m->beat()) {
2349                                         /* tempo/ meter change caused a change in beat (bar). */
2350                                         b_bbt = make_pair (beats + prev_m->beat()
2351                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2352                                 } else {
2353                                         b_bbt = make_pair (beats + prev_m->beat()
2354                                                            , m->bbt());
2355                                 }
2356                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2357                                 m->set_beat (b_bbt);
2358                                 m->set_pulse (new_pulse);
2359                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2360                         }
2361
2362                         prev_m = m;
2363                 }
2364         }
2365
2366         if (!section_prev) {
2367
2368                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2369                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2370                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2371
2372                 section->set_beat (b_bbt);
2373                 section->set_pulse (pulse);
2374                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2375         }
2376
2377         MetricSectionSorter cmp;
2378         imaginary.sort (cmp);
2379
2380         recompute_meters (imaginary);
2381
2382         return true;
2383 }
2384
2385 /** places a copy of _metrics into copy and returns a pointer
2386  *  to section's equivalent in copy.
2387  */
2388 TempoSection*
2389 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2390 {
2391         TempoSection* ret = 0;
2392
2393         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2394                 TempoSection* t;
2395                 MeterSection* m;
2396                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2397                         if (t == section) {
2398                                 ret = new TempoSection (*t);
2399                                 copy.push_back (ret);
2400                                 continue;
2401                         }
2402
2403                         TempoSection* cp = new TempoSection (*t);
2404                         copy.push_back (cp);
2405                 }
2406                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2407                         MeterSection* cp = new MeterSection (*m);
2408                         copy.push_back (cp);
2409                 }
2410         }
2411
2412         return ret;
2413 }
2414
2415 MeterSection*
2416 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2417 {
2418         MeterSection* ret = 0;
2419
2420         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2421                 TempoSection* t;
2422                 MeterSection* m;
2423                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2424                         TempoSection* cp = new TempoSection (*t);
2425                         copy.push_back (cp);
2426                 }
2427
2428                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2429                         if (m == section) {
2430                                 ret = new MeterSection (*m);
2431                                 copy.push_back (ret);
2432                                 continue;
2433                         }
2434                         MeterSection* cp = new MeterSection (*m);
2435                         copy.push_back (cp);
2436                 }
2437         }
2438
2439         return ret;
2440 }
2441
2442 /** answers the question "is this a valid beat position for this tempo section?".
2443  *  it returns true if the tempo section can be moved to the requested bbt position,
2444  *  leaving the tempo map in a solved state.
2445  * @param section the tempo section to be moved
2446  * @param bbt the requested new position for the tempo section
2447  * @return true if the tempo section can be moved to the position, otherwise false.
2448  */
2449 bool
2450 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2451 {
2452         Metrics copy;
2453         TempoSection* tempo_copy = 0;
2454
2455         {
2456                 Glib::Threads::RWLock::ReaderLock lm (lock);
2457                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2458                 if (!tempo_copy) {
2459                         return false;
2460                 }
2461         }
2462
2463         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2464
2465         Metrics::const_iterator d = copy.begin();
2466         while (d != copy.end()) {
2467                 delete (*d);
2468                 ++d;
2469         }
2470
2471         return ret;
2472 }
2473
2474 /**
2475 * 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,
2476 * taking any possible reordering as a consequence of this into account.
2477 * @param section - the section to be altered
2478 * @param bbt - the bbt where the altered tempo will fall
2479 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2480 */
2481 pair<double, framepos_t>
2482 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2483 {
2484         Metrics future_map;
2485         pair<double, framepos_t> ret = make_pair (0.0, 0);
2486
2487         Glib::Threads::RWLock::ReaderLock lm (lock);
2488
2489         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2490
2491         const double beat = beat_at_bbt_locked (future_map, bbt);
2492
2493         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2494                 ret.first = tempo_copy->pulse();
2495                 ret.second = tempo_copy->frame();
2496         } else {
2497                 ret.first = section->pulse();
2498                 ret.second = section->frame();
2499         }
2500
2501         Metrics::const_iterator d = future_map.begin();
2502         while (d != future_map.end()) {
2503                 delete (*d);
2504                 ++d;
2505         }
2506         return ret;
2507 }
2508
2509 void
2510 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame)
2511 {
2512         Metrics future_map;
2513
2514         if (ts->position_lock_style() == MusicTime) {
2515                 {
2516                         Glib::Threads::RWLock::WriterLock lm (lock);
2517                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2518                         const double pulse = pulse_at_frame_locked (future_map, frame);
2519                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2520                                 solve_map_pulse (_metrics, ts, pulse);
2521                                 recompute_meters (_metrics);
2522                         }
2523                 }
2524
2525         } else {
2526
2527                 {
2528                         Glib::Threads::RWLock::WriterLock lm (lock);
2529                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2530                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2531                                 solve_map_frame (_metrics, ts, frame);
2532                                 recompute_meters (_metrics);
2533                         }
2534                 }
2535         }
2536
2537         Metrics::const_iterator d = future_map.begin();
2538         while (d != future_map.end()) {
2539                 delete (*d);
2540                 ++d;
2541         }
2542
2543         MetricPositionChanged (); // Emit Signal
2544 }
2545
2546 void
2547 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2548 {
2549         Metrics future_map;
2550
2551         if (ms->position_lock_style() == AudioTime) {
2552
2553                 {
2554                         Glib::Threads::RWLock::WriterLock lm (lock);
2555                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2556
2557                         if (solve_map_frame (future_map, copy, frame)) {
2558                                 solve_map_frame (_metrics, ms, frame);
2559                                 recompute_tempos (_metrics);
2560                         }
2561                 }
2562         } else {
2563                 {
2564                         Glib::Threads::RWLock::WriterLock lm (lock);
2565                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2566
2567                         const double beat = beat_at_frame_locked (_metrics, frame);
2568                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2569
2570                         if (solve_map_bbt (future_map, copy, bbt)) {
2571                                 solve_map_bbt (_metrics, ms, bbt);
2572                                 recompute_tempos (_metrics);
2573                         }
2574                 }
2575         }
2576
2577         Metrics::const_iterator d = future_map.begin();
2578         while (d != future_map.end()) {
2579                 delete (*d);
2580                 ++d;
2581         }
2582
2583         MetricPositionChanged (); // Emit Signal
2584 }
2585
2586 bool
2587 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2588 {
2589         Metrics future_map;
2590         bool can_solve = false;
2591         {
2592                 Glib::Threads::RWLock::WriterLock lm (lock);
2593                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2594                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2595                 recompute_tempos (future_map);
2596
2597                 if (check_solved (future_map)) {
2598                         ts->set_beats_per_minute (bpm.beats_per_minute());
2599                         recompute_map (_metrics);
2600                         can_solve = true;
2601                 }
2602         }
2603
2604         Metrics::const_iterator d = future_map.begin();
2605         while (d != future_map.end()) {
2606                 delete (*d);
2607                 ++d;
2608         }
2609         if (can_solve) {
2610                 MetricPositionChanged (); // Emit Signal
2611         }
2612         return can_solve;
2613 }
2614
2615 void
2616 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2617 {
2618         /*
2619           Ts (future prev_t)   Tnext
2620           |                    |
2621           |     [drag^]        |
2622           |----------|----------
2623                 e_f  pulse(frame)
2624         */
2625
2626         Metrics future_map;
2627
2628         {
2629                 Glib::Threads::RWLock::WriterLock lm (lock);
2630
2631                 if (!ts) {
2632                         return;
2633                 }
2634
2635                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2636                 TempoSection* prev_to_prev_t = 0;
2637                 const frameoffset_t fr_off = end_frame - frame;
2638
2639                 if (prev_t && prev_t->pulse() > 0.0) {
2640                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2641                 }
2642
2643                 TempoSection* next_t = 0;
2644                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2645                         TempoSection* t = 0;
2646                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2647                                 if (t->frame() > ts->frame()) {
2648                                         next_t = t;
2649                                         break;
2650                                 }
2651                         }
2652                 }
2653
2654                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2655                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2656                 */
2657                 double contribution = 0.0;
2658                 double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2659
2660                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2661                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2662                 }
2663
2664                 frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2665                 double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2666                 double new_bpm;
2667
2668                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2669
2670                         if (prev_t->position_lock_style() == MusicTime) {
2671                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2672
2673                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2674                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2675
2676                                 } else {
2677                                         /* prev to prev is irrelevant */
2678
2679                                         if (start_pulse != prev_t->pulse()) {
2680                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2681                                         } else {
2682                                                 new_bpm = prev_t->beats_per_minute();
2683                                         }
2684                                 }
2685                         } else {
2686                                 /* AudioTime */
2687                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2688                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
2689                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
2690                                 } else {
2691                                         /* prev_to_prev_t is irrelevant */
2692
2693                                         if (end_frame != prev_t->frame()) {
2694                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2695                                         } else {
2696                                                 new_bpm = prev_t->beats_per_minute();
2697                                         }
2698                                 }
2699                         }
2700                 } else {
2701
2702                         double frame_ratio;
2703                         double pulse_ratio;
2704                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2705
2706                         if (prev_to_prev_t) {
2707
2708                                 frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2709                                 pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2710                         } else {
2711
2712                                 frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2713                                 pulse_ratio = (start_pulse / end_pulse);
2714                         }
2715                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2716                 }
2717
2718                 prev_t->set_beats_per_minute (new_bpm);
2719                 recompute_tempos (future_map);
2720                 recompute_meters (future_map);
2721
2722                 if (check_solved (future_map)) {
2723                         ts->set_beats_per_minute (new_bpm);
2724                         recompute_tempos (_metrics);
2725                         recompute_meters (_metrics);
2726                 }
2727         }
2728
2729         Metrics::const_iterator d = future_map.begin();
2730         while (d != future_map.end()) {
2731                 delete (*d);
2732                 ++d;
2733         }
2734
2735         MetricPositionChanged (); // Emit Signal
2736 }
2737
2738 framecnt_t
2739 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2740 {
2741         Glib::Threads::RWLock::ReaderLock lm (lock);
2742
2743         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2744         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2745         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2746
2747         return frame_at_beat_locked (_metrics, total_beats);
2748 }
2749
2750 framepos_t
2751 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2752 {
2753         return round_to_type (fr, dir, Bar);
2754 }
2755
2756 framepos_t
2757 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2758 {
2759         return round_to_type (fr, dir, Beat);
2760 }
2761
2762 framepos_t
2763 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2764 {
2765         Glib::Threads::RWLock::ReaderLock lm (lock);
2766         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2767         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2768         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2769
2770         ticks -= beats * BBT_Time::ticks_per_beat;
2771
2772         if (dir > 0) {
2773                 /* round to next (or same iff dir == RoundUpMaybe) */
2774
2775                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2776
2777                 if (mod == 0 && dir == RoundUpMaybe) {
2778                         /* right on the subdivision, which is fine, so do nothing */
2779
2780                 } else if (mod == 0) {
2781                         /* right on the subdivision, so the difference is just the subdivision ticks */
2782                         ticks += ticks_one_subdivisions_worth;
2783
2784                 } else {
2785                         /* not on subdivision, compute distance to next subdivision */
2786
2787                         ticks += ticks_one_subdivisions_worth - mod;
2788                 }
2789
2790                 if (ticks >= BBT_Time::ticks_per_beat) {
2791                         ticks -= BBT_Time::ticks_per_beat;
2792                 }
2793         } else if (dir < 0) {
2794
2795                 /* round to previous (or same iff dir == RoundDownMaybe) */
2796
2797                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2798
2799                 if (difference == 0 && dir == RoundDownAlways) {
2800                         /* right on the subdivision, but force-rounding down,
2801                            so the difference is just the subdivision ticks */
2802                         difference = ticks_one_subdivisions_worth;
2803                 }
2804
2805                 if (ticks < difference) {
2806                         ticks = BBT_Time::ticks_per_beat - ticks;
2807                 } else {
2808                         ticks -= difference;
2809                 }
2810
2811         } else {
2812                 /* round to nearest */
2813                 double rem;
2814
2815                 /* compute the distance to the previous and next subdivision */
2816
2817                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2818
2819                         /* closer to the next subdivision, so shift forward */
2820
2821                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2822
2823                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2824
2825                         if (ticks > BBT_Time::ticks_per_beat) {
2826                                 ++beats;
2827                                 ticks -= BBT_Time::ticks_per_beat;
2828                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2829                         }
2830
2831                 } else if (rem > 0) {
2832
2833                         /* closer to previous subdivision, so shift backward */
2834
2835                         if (rem > ticks) {
2836                                 if (beats == 0) {
2837                                         /* can't go backwards past zero, so ... */
2838                                         return 0;
2839                                 }
2840                                 /* step back to previous beat */
2841                                 --beats;
2842                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2843                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2844                         } else {
2845                                 ticks = lrint (ticks - rem);
2846                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2847                         }
2848                 } else {
2849                         /* on the subdivision, do nothing */
2850                 }
2851         }
2852
2853         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2854
2855         return ret_frame;
2856 }
2857
2858 framepos_t
2859 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2860 {
2861         Glib::Threads::RWLock::ReaderLock lm (lock);
2862
2863         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2864         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
2865
2866         switch (type) {
2867         case Bar:
2868                 if (dir < 0) {
2869                         /* find bar previous to 'frame' */
2870                         bbt.beats = 1;
2871                         bbt.ticks = 0;
2872                         return frame_at_bbt_locked (_metrics, bbt);
2873
2874                 } else if (dir > 0) {
2875                         /* find bar following 'frame' */
2876                         ++bbt.bars;
2877                         bbt.beats = 1;
2878                         bbt.ticks = 0;
2879                         return frame_at_bbt_locked (_metrics, bbt);
2880                 } else {
2881                         /* true rounding: find nearest bar */
2882                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
2883                         bbt.beats = 1;
2884                         bbt.ticks = 0;
2885                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
2886                         ++bbt.bars;
2887                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
2888
2889                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2890                                 return next_ft;
2891                         } else {
2892                                 return prev_ft;
2893                         }
2894                 }
2895
2896                 break;
2897
2898         case Beat:
2899                 if (dir < 0) {
2900                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2901                 } else if (dir > 0) {
2902                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2903                 } else {
2904                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2905                 }
2906                 break;
2907         }
2908
2909         return 0;
2910 }
2911
2912 void
2913 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2914                     framepos_t lower, framepos_t upper)
2915 {
2916         Glib::Threads::RWLock::ReaderLock lm (lock);
2917         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
2918         framecnt_t pos = 0;
2919         /* although the map handles negative beats, bbt doesn't. */
2920         if (cnt < 0.0) {
2921                 cnt = 0.0;
2922         }
2923         while (pos < upper) {
2924                 pos = frame_at_beat_locked (_metrics, cnt);
2925                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
2926                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
2927                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
2928                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
2929                 ++cnt;
2930         }
2931 }
2932
2933 const TempoSection&
2934 TempoMap::tempo_section_at_frame (framepos_t frame) const
2935 {
2936         Glib::Threads::RWLock::ReaderLock lm (lock);
2937         return tempo_section_at_frame_locked (_metrics, frame);
2938 }
2939
2940 const TempoSection&
2941 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
2942 {
2943         Metrics::const_iterator i;
2944         TempoSection* prev = 0;
2945
2946         for (i = metrics.begin(); i != metrics.end(); ++i) {
2947                 TempoSection* t;
2948
2949                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2950                         if (!t->active()) {
2951                                 continue;
2952                         }
2953                         if (prev && t->frame() > frame) {
2954                                 break;
2955                         }
2956
2957                         prev = t;
2958                 }
2959         }
2960
2961         if (prev == 0) {
2962                 fatal << endmsg;
2963                 abort(); /*NOTREACHED*/
2964         }
2965
2966         return *prev;
2967 }
2968
2969 const TempoSection&
2970 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
2971 {
2972         TempoSection* prev_t = 0;
2973         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
2974
2975         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2976                 TempoSection* t;
2977                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2978                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
2979                                 break;
2980                         }
2981                         prev_t = t;
2982                 }
2983
2984         }
2985         return *prev_t;
2986 }
2987
2988 /* don't use this to calculate length (the tempo is only correct for this frame).
2989    do that stuff based on the beat_at_frame and frame_at_beat api
2990 */
2991 double
2992 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
2993 {
2994         Glib::Threads::RWLock::ReaderLock lm (lock);
2995
2996         const TempoSection* ts_at = &tempo_section_at_frame_locked (_metrics, frame);
2997         const TempoSection* ts_after = 0;
2998         Metrics::const_iterator i;
2999
3000         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3001                 TempoSection* t;
3002
3003                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3004                         if (!t->active()) {
3005                                 continue;
3006                         }
3007                         if ((*i)->frame() > frame) {
3008                                 ts_after = t;
3009                                 break;
3010                         }
3011                 }
3012         }
3013
3014         if (ts_after) {
3015                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
3016         }
3017         /* must be treated as constant tempo */
3018         return ts_at->frames_per_beat (_frame_rate);
3019 }
3020
3021 const MeterSection&
3022 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3023 {
3024         Metrics::const_iterator i;
3025         MeterSection* prev = 0;
3026
3027         for (i = metrics.begin(); i != metrics.end(); ++i) {
3028                 MeterSection* m;
3029
3030                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3031
3032                         if (prev && (*i)->frame() > frame) {
3033                                 break;
3034                         }
3035
3036                         prev = m;
3037                 }
3038         }
3039
3040         if (prev == 0) {
3041                 fatal << endmsg;
3042                 abort(); /*NOTREACHED*/
3043         }
3044
3045         return *prev;
3046 }
3047
3048
3049 const MeterSection&
3050 TempoMap::meter_section_at_frame (framepos_t frame) const
3051 {
3052         Glib::Threads::RWLock::ReaderLock lm (lock);
3053         return meter_section_at_frame_locked (_metrics, frame);
3054 }
3055
3056 const MeterSection&
3057 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3058 {
3059         MeterSection* prev_m = 0;
3060
3061         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3062                 MeterSection* m;
3063                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3064                         if (prev_m && m->beat() > beat) {
3065                                 break;
3066                         }
3067                         prev_m = m;
3068                 }
3069
3070         }
3071         return *prev_m;
3072 }
3073
3074 const MeterSection&
3075 TempoMap::meter_section_at_beat (double beat) const
3076 {
3077         Glib::Threads::RWLock::ReaderLock lm (lock);
3078         return meter_section_at_beat_locked (_metrics, beat);
3079 }
3080
3081 const Meter&
3082 TempoMap::meter_at_frame (framepos_t frame) const
3083 {
3084         TempoMetric m (metric_at (frame));
3085         return m.meter();
3086 }
3087
3088 void
3089 TempoMap::fix_legacy_session ()
3090 {
3091         MeterSection* prev_m = 0;
3092         TempoSection* prev_t = 0;
3093
3094         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3095                 MeterSection* m;
3096                 TempoSection* t;
3097
3098                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3099                         if (!m->movable()) {
3100                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3101                                 m->set_beat (bbt);
3102                                 m->set_pulse (0.0);
3103                                 m->set_frame (0);
3104                                 m->set_position_lock_style (AudioTime);
3105                                 prev_m = m;
3106                                 continue;
3107                         }
3108                         if (prev_m) {
3109                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3110                                                                           + (m->bbt().beats - 1)
3111                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3112                                                                           , m->bbt());
3113                                 m->set_beat (start);
3114                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3115                                         + (m->bbt().beats - 1)
3116                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3117                                 m->set_pulse (start_beat / prev_m->note_divisor());
3118                         }
3119                         prev_m = m;
3120                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3121
3122                         if (!t->active()) {
3123                                 continue;
3124                         }
3125
3126                         if (!t->movable()) {
3127                                 t->set_pulse (0.0);
3128                                 t->set_frame (0);
3129                                 t->set_position_lock_style (AudioTime);
3130                                 prev_t = t;
3131                                 continue;
3132                         }
3133
3134                         if (prev_t) {
3135                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3136                                         + (t->legacy_bbt().beats - 1)
3137                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3138                                 if (prev_m) {
3139                                         t->set_pulse (beat / prev_m->note_divisor());
3140                                 } else {
3141                                         /* really shouldn't happen but.. */
3142                                         t->set_pulse (beat / 4.0);
3143                                 }
3144                         }
3145                         prev_t = t;
3146                 }
3147         }
3148 }
3149
3150 XMLNode&
3151 TempoMap::get_state ()
3152 {
3153         Metrics::const_iterator i;
3154         XMLNode *root = new XMLNode ("TempoMap");
3155
3156         {
3157                 Glib::Threads::RWLock::ReaderLock lm (lock);
3158                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3159                         root->add_child_nocopy ((*i)->get_state());
3160                 }
3161         }
3162
3163         return *root;
3164 }
3165
3166 int
3167 TempoMap::set_state (const XMLNode& node, int /*version*/)
3168 {
3169         {
3170                 Glib::Threads::RWLock::WriterLock lm (lock);
3171
3172                 XMLNodeList nlist;
3173                 XMLNodeConstIterator niter;
3174                 Metrics old_metrics (_metrics);
3175                 _metrics.clear();
3176
3177                 nlist = node.children();
3178
3179                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3180                         XMLNode* child = *niter;
3181
3182                         if (child->name() == TempoSection::xml_state_node_name) {
3183
3184                                 try {
3185                                         TempoSection* ts = new TempoSection (*child);
3186                                         _metrics.push_back (ts);
3187                                 }
3188
3189                                 catch (failed_constructor& err){
3190                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3191                                         _metrics = old_metrics;
3192                                         break;
3193                                 }
3194
3195                         } else if (child->name() == MeterSection::xml_state_node_name) {
3196
3197                                 try {
3198                                         MeterSection* ms = new MeterSection (*child);
3199                                         _metrics.push_back (ms);
3200                                 }
3201
3202                                 catch (failed_constructor& err) {
3203                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3204                                         _metrics = old_metrics;
3205                                         break;
3206                                 }
3207                         }
3208                 }
3209
3210                 if (niter == nlist.end()) {
3211                         MetricSectionSorter cmp;
3212                         _metrics.sort (cmp);
3213                 }
3214
3215                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3216                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3217                         TempoSection* t;
3218                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3219                                 if (t->legacy_bbt().bars != 0) {
3220                                         fix_legacy_session();
3221                                         break;
3222                                 }
3223                                 break;
3224                         }
3225                 }
3226
3227                 /* check for multiple tempo/meters at the same location, which
3228                    ardour2 somehow allowed.
3229                 */
3230
3231                 Metrics::iterator prev = _metrics.end();
3232                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3233                         if (prev != _metrics.end()) {
3234                                 MeterSection* ms;
3235                                 MeterSection* prev_m;
3236                                 TempoSection* ts;
3237                                 TempoSection* prev_t;
3238                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3239                                         if (prev_m->pulse() == ms->pulse()) {
3240                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3241                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3242                                                 return -1;
3243                                         }
3244                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3245                                         if (prev_t->pulse() == ts->pulse()) {
3246                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3247                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3248                                                 return -1;
3249                                         }
3250                                 }
3251                         }
3252                         prev = i;
3253                 }
3254
3255                 recompute_map (_metrics);
3256         }
3257
3258         PropertyChanged (PropertyChange ());
3259
3260         return 0;
3261 }
3262
3263 void
3264 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3265 {
3266         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3267         const MeterSection* m;
3268         const TempoSection* t;
3269         const TempoSection* prev_t = 0;
3270
3271         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3272
3273                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3274                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3275                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3276                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3277                         if (prev_t) {
3278                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3279                                 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;
3280                         }
3281                         prev_t = t;
3282                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3283                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3284                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3285                 }
3286         }
3287         o << "------" << std::endl;
3288 }
3289
3290 int
3291 TempoMap::n_tempos() const
3292 {
3293         Glib::Threads::RWLock::ReaderLock lm (lock);
3294         int cnt = 0;
3295
3296         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3297                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3298                         cnt++;
3299                 }
3300         }
3301
3302         return cnt;
3303 }
3304
3305 int
3306 TempoMap::n_meters() const
3307 {
3308         Glib::Threads::RWLock::ReaderLock lm (lock);
3309         int cnt = 0;
3310
3311         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3312                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3313                         cnt++;
3314                 }
3315         }
3316
3317         return cnt;
3318 }
3319
3320 void
3321 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3322 {
3323         {
3324                 Glib::Threads::RWLock::WriterLock lm (lock);
3325                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3326                         if ((*i)->frame() >= where && (*i)->movable ()) {
3327                                 (*i)->set_frame ((*i)->frame() + amount);
3328                         }
3329                 }
3330
3331                 /* now reset the BBT time of all metrics, based on their new
3332                  * audio time. This is the only place where we do this reverse
3333                  * timestamp.
3334                  */
3335
3336                 Metrics::iterator i;
3337                 const MeterSection* meter;
3338                 const TempoSection* tempo;
3339                 MeterSection *m;
3340                 TempoSection *t;
3341
3342                 meter = &first_meter ();
3343                 tempo = &first_tempo ();
3344
3345                 BBT_Time start;
3346                 BBT_Time end;
3347
3348                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3349
3350                 bool first = true;
3351                 MetricSection* prev = 0;
3352
3353                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3354
3355                         BBT_Time bbt;
3356                         //TempoMetric metric (*meter, *tempo);
3357                         MeterSection* ms = const_cast<MeterSection*>(meter);
3358                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3359                         if (prev) {
3360                                 if (ts){
3361                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3362                                                 if (!t->active()) {
3363                                                         continue;
3364                                                 }
3365                                                 ts->set_pulse (t->pulse());
3366                                         }
3367                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3368                                                 ts->set_pulse (m->pulse());
3369                                         }
3370                                         ts->set_frame (prev->frame());
3371
3372                                 }
3373                                 if (ms) {
3374                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3375                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3376                                                 ms->set_beat (start);
3377                                                 ms->set_pulse (m->pulse());
3378                                         }
3379                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3380                                                 if (!t->active()) {
3381                                                         continue;
3382                                                 }
3383                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3384                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3385                                                 ms->set_beat (start);
3386                                                 ms->set_pulse (t->pulse());
3387                                         }
3388                                         ms->set_frame (prev->frame());
3389                                 }
3390
3391                         } else {
3392                                 // metric will be at frames=0 bbt=1|1|0 by default
3393                                 // which is correct for our purpose
3394                         }
3395
3396                         // cerr << bbt << endl;
3397
3398                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3399                                 if (!t->active()) {
3400                                         continue;
3401                                 }
3402                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3403                                 tempo = t;
3404                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3405                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3406                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3407
3408                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3409
3410                                 if (first) {
3411                                         first = false;
3412                                 } else {
3413
3414                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3415                                                 /* round up to next beat */
3416                                                 bbt.beats += 1;
3417                                         }
3418
3419                                         bbt.ticks = 0;
3420
3421                                         if (bbt.beats != 1) {
3422                                                 /* round up to next bar */
3423                                                 bbt.bars += 1;
3424                                                 bbt.beats = 1;
3425                                         }
3426                                 }
3427                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3428                                 m->set_beat (start);
3429                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3430                                 meter = m;
3431                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3432                         } else {
3433                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3434                                 abort(); /*NOTREACHED*/
3435                         }
3436
3437                         prev = (*i);
3438                 }
3439
3440                 recompute_map (_metrics);
3441         }
3442
3443
3444         PropertyChanged (PropertyChange ());
3445 }
3446 bool
3447 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3448 {
3449         bool moved = false;
3450
3451         std::list<MetricSection*> metric_kill_list;
3452
3453         TempoSection* last_tempo = NULL;
3454         MeterSection* last_meter = NULL;
3455         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3456         bool meter_after = false; // is there a meter marker likewise?
3457         {
3458                 Glib::Threads::RWLock::WriterLock lm (lock);
3459                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3460                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3461                                 metric_kill_list.push_back(*i);
3462                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3463                                 if (lt)
3464                                         last_tempo = lt;
3465                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3466                                 if (lm)
3467                                         last_meter = lm;
3468                         }
3469                         else if ((*i)->frame() >= where) {
3470                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3471                                 (*i)->set_frame ((*i)->frame() - amount);
3472                                 if ((*i)->frame() == where) {
3473                                         // marker was immediately after end of range
3474                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3475                                         meter_after = dynamic_cast<MeterSection*> (*i);
3476                                 }
3477                                 moved = true;
3478                         }
3479                 }
3480
3481                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3482                 if (last_tempo && !tempo_after) {
3483                         metric_kill_list.remove(last_tempo);
3484                         last_tempo->set_frame(where);
3485                         moved = true;
3486                 }
3487                 if (last_meter && !meter_after) {
3488                         metric_kill_list.remove(last_meter);
3489                         last_meter->set_frame(where);
3490                         moved = true;
3491                 }
3492
3493                 //remove all the remaining metrics
3494                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3495                         _metrics.remove(*i);
3496                         moved = true;
3497                 }
3498
3499                 if (moved) {
3500                         recompute_map (_metrics);
3501                 }
3502         }
3503         PropertyChanged (PropertyChange ());
3504         return moved;
3505 }
3506
3507 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3508  *  pos can be -ve, if required.
3509  */
3510 framepos_t
3511 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3512 {
3513         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
3514 }
3515
3516 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3517 framepos_t
3518 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3519 {
3520         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
3521 }
3522
3523 /** Add the BBT interval op to pos and return the result */
3524 framepos_t
3525 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3526 {
3527         Glib::Threads::RWLock::ReaderLock lm (lock);
3528
3529         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3530         pos_bbt.ticks += op.ticks;
3531         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3532                 ++pos_bbt.beats;
3533                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3534         }
3535         pos_bbt.beats += op.beats;
3536         /* the meter in effect will start on the bar */
3537         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();
3538         while (pos_bbt.beats >= divisions_per_bar + 1) {
3539                 ++pos_bbt.bars;
3540                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3541                 pos_bbt.beats -= divisions_per_bar;
3542         }
3543         pos_bbt.bars += op.bars;
3544
3545         return frame_at_bbt_locked (_metrics, pos_bbt);
3546 }
3547
3548 /** Count the number of beats that are equivalent to distance when going forward,
3549     starting at pos.
3550 */
3551 Evoral::Beats
3552 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3553 {
3554         return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
3555 }
3556
3557 struct bbtcmp {
3558     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3559             return a < b;
3560     }
3561 };
3562
3563 std::ostream&
3564 operator<< (std::ostream& o, const Meter& m) {
3565         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3566 }
3567
3568 std::ostream&
3569 operator<< (std::ostream& o, const Tempo& t) {
3570         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3571 }
3572
3573 std::ostream&
3574 operator<< (std::ostream& o, const MetricSection& section) {
3575
3576         o << "MetricSection @ " << section.frame() << ' ';
3577
3578         const TempoSection* ts;
3579         const MeterSection* ms;
3580
3581         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3582                 o << *((const Tempo*) ts);
3583         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3584                 o << *((const Meter*) ms);
3585         }
3586
3587         return o;
3588 }