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