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