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