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