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