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