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