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