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