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