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