dfe75152011a8693e40db1f659e01063f9e455e8
[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->pulse() == insert_meter->pulse()) || (!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
799                                 break;
800                         }
801                 } else {
802                         /* non-matching types, so we don't care */
803                 }
804         }
805
806         /* Add the given MetricSection, if we didn't just reset an existing
807          * one above
808          */
809
810         if (need_add) {
811                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
812                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
813                 Metrics::iterator i;
814                 if (insert_meter) {
815                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
816                                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
817
818                                 if (meter) {
819                                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
820                                         if ((ipm && meter->pulse() > insert_meter->pulse()) || (!ipm && meter->frame() > insert_meter->frame())) {
821                                                 break;
822                                         }
823                                 }
824                         }
825                 } else if (insert_tempo) {
826                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
827                                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
828
829                                 if (tempo) {
830                                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
831                                         if ((ipm && tempo->pulse() > insert_tempo->pulse()) || (!ipm && tempo->frame() > insert_tempo->frame())) {
832                                                 break;
833                                         }
834                                 }
835                         }
836                 }
837
838                 _metrics.insert (i, section);
839                 //dump (_metrics, std::cerr);
840         }
841 }
842
843 void
844 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, TempoSection::Type type)
845 {
846         {
847                 Glib::Threads::RWLock::WriterLock lm (lock);
848                 TempoSection& first (first_tempo());
849                 if (ts.pulse() != first.pulse()) {
850                         remove_tempo_locked (ts);
851                         add_tempo_locked (tempo, pulse, true, type);
852                 } else {
853                         first.set_type (type);
854                         {
855                                 /* cannot move the first tempo section */
856                                 *static_cast<Tempo*>(&first) = tempo;
857                                 recompute_map (_metrics);
858                         }
859                 }
860         }
861
862         PropertyChanged (PropertyChange ());
863 }
864
865 void
866 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const framepos_t& frame, TempoSection::Type type)
867 {
868         {
869                 Glib::Threads::RWLock::WriterLock lm (lock);
870                 TempoSection& first (first_tempo());
871                 if (ts.frame() != first.frame()) {
872                         remove_tempo_locked (ts);
873                         add_tempo_locked (tempo, frame, true, type);
874                 } else {
875                         first.set_type (type);
876                         first.set_pulse (0.0);
877                         first.set_position_lock_style (AudioTime);
878                         {
879                                 /* cannot move the first tempo section */
880                                 *static_cast<Tempo*>(&first) = tempo;
881                                 recompute_map (_metrics);
882                         }
883                 }
884         }
885
886         PropertyChanged (PropertyChange ());
887 }
888
889 void
890 TempoMap::add_tempo (const Tempo& tempo, const double& pulse, ARDOUR::TempoSection::Type type)
891 {
892         {
893                 Glib::Threads::RWLock::WriterLock lm (lock);
894                 add_tempo_locked (tempo, pulse, true, type);
895         }
896
897         PropertyChanged (PropertyChange ());
898 }
899
900 void
901 TempoMap::add_tempo (const Tempo& tempo, const framepos_t& frame, ARDOUR::TempoSection::Type type)
902 {
903         {
904                 Glib::Threads::RWLock::WriterLock lm (lock);
905                 add_tempo_locked (tempo, frame, true, type);
906         }
907
908
909         PropertyChanged (PropertyChange ());
910 }
911
912 void
913 TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, bool recompute, ARDOUR::TempoSection::Type type)
914 {
915         TempoSection* ts = new TempoSection (pulse, tempo.beats_per_minute(), tempo.note_type(), type);
916
917         do_insert (ts);
918
919         if (recompute) {
920                 solve_map (_metrics, ts, Tempo (ts->beats_per_minute(), ts->note_type()), ts->pulse());
921         }
922 }
923
924 void
925 TempoMap::add_tempo_locked (const Tempo& tempo, framepos_t frame, bool recompute, ARDOUR::TempoSection::Type type)
926 {
927         TempoSection* ts = new TempoSection (frame, tempo.beats_per_minute(), tempo.note_type(), type);
928
929         do_insert (ts);
930
931         if (recompute) {
932                 solve_map (_metrics, ts, Tempo (ts->beats_per_minute(), ts->note_type()), ts->frame());
933         }
934 }
935
936 void
937 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
938 {
939         {
940                 Glib::Threads::RWLock::WriterLock lm (lock);
941
942                 if (ms.movable()) {
943                         remove_meter_locked (ms);
944                         add_meter_locked (meter, bbt_to_beats_locked (_metrics, where), where, true);
945                 } else {
946                         MeterSection& first (first_meter());
947                         const PositionLockStyle pl = ms.position_lock_style();
948                         /* cannot move the first meter section */
949                         *static_cast<Meter*>(&first) = meter;
950                         first.set_position_lock_style (pl);
951                         recompute_map (_metrics);
952                 }
953         }
954
955         PropertyChanged (PropertyChange ());
956 }
957
958 void
959 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const framepos_t& frame)
960 {
961         {
962                 Glib::Threads::RWLock::WriterLock lm (lock);
963
964                 const double beat = ms.beat();
965                 const BBT_Time bbt = ms.bbt();
966
967                 if (ms.movable()) {
968                         remove_meter_locked (ms);
969                         add_meter_locked (meter, frame, beat, bbt, true);
970                 } else {
971                         MeterSection& first (first_meter());
972                         TempoSection& first_t (first_tempo());
973                         /* cannot move the first meter section */
974                         *static_cast<Meter*>(&first) = meter;
975                         first.set_position_lock_style (AudioTime);
976                         first.set_pulse (0.0);
977                         first.set_frame (frame);
978                         pair<double, BBT_Time> beat = make_pair (0.0, BBT_Time (1, 1, 0));
979                         first.set_beat (beat);
980                         first_t.set_frame (first.frame());
981                         first_t.set_pulse (0.0);
982                         first_t.set_position_lock_style (AudioTime);
983
984                         recompute_map (_metrics);
985                 }
986         }
987         PropertyChanged (PropertyChange ());
988 }
989
990
991 void
992 TempoMap::add_meter (const Meter& meter, const double& beat, const BBT_Time& where)
993 {
994         {
995                 Glib::Threads::RWLock::WriterLock lm (lock);
996                 add_meter_locked (meter, beat, where, true);
997         }
998
999
1000 #ifndef NDEBUG
1001         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
1002                 dump (_metrics, std::cerr);
1003         }
1004 #endif
1005
1006         PropertyChanged (PropertyChange ());
1007 }
1008
1009 void
1010 TempoMap::add_meter (const Meter& meter, const framepos_t& frame, const double& beat, const Timecode::BBT_Time& where)
1011 {
1012         {
1013                 Glib::Threads::RWLock::WriterLock lm (lock);
1014                 add_meter_locked (meter, frame, beat, where, true);
1015         }
1016
1017
1018 #ifndef NDEBUG
1019         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
1020                 dump (_metrics, std::cerr);
1021         }
1022 #endif
1023
1024         PropertyChanged (PropertyChange ());
1025 }
1026
1027 void
1028 TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, bool recompute)
1029 {
1030         /* a new meter always starts a new bar on the first beat. so
1031            round the start time appropriately. remember that
1032            `where' is based on the existing tempo map, not
1033            the result after we insert the new meter.
1034
1035         */
1036
1037         if (where.beats != 1) {
1038                 where.beats = 1;
1039                 where.bars++;
1040         }
1041         /* new meters *always* start on a beat. */
1042         where.ticks = 0;
1043         double pulse = pulse_at_beat_locked (_metrics, beat);
1044
1045         MeterSection* new_meter = new MeterSection (pulse, beat, where, meter.divisions_per_bar(), meter.note_divisor());
1046         do_insert (new_meter);
1047
1048         if (recompute) {
1049                 solve_map (_metrics, new_meter, Meter (meter.divisions_per_bar(), meter.note_divisor()), pulse);
1050         }
1051
1052 }
1053
1054 void
1055 TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, double beat, Timecode::BBT_Time where, bool recompute)
1056 {
1057
1058         MeterSection* new_meter = new MeterSection (frame, beat, where, meter.divisions_per_bar(), meter.note_divisor());
1059
1060         double pulse = pulse_at_frame_locked (_metrics, frame);
1061         new_meter->set_pulse (pulse);
1062
1063         do_insert (new_meter);
1064
1065         if (recompute) {
1066                 solve_map (_metrics, new_meter, Meter (new_meter->divisions_per_bar(), new_meter->note_divisor()), frame);
1067         }
1068
1069 }
1070
1071 void
1072 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
1073 {
1074         Tempo newtempo (beats_per_minute, note_type);
1075         TempoSection* t;
1076
1077         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1078                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1079                         if (!t->active()) {
1080                                 continue;
1081                         }
1082                         {
1083                                 Glib::Threads::RWLock::WriterLock lm (lock);
1084                                 *((Tempo*) t) = newtempo;
1085                                 recompute_map (_metrics);
1086                         }
1087                         PropertyChanged (PropertyChange ());
1088                         break;
1089                 }
1090         }
1091 }
1092
1093 void
1094 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
1095 {
1096         Tempo newtempo (beats_per_minute, note_type);
1097
1098         TempoSection* prev;
1099         TempoSection* first;
1100         Metrics::iterator i;
1101
1102         /* find the TempoSection immediately preceding "where"
1103          */
1104
1105         for (first = 0, i = _metrics.begin(), prev = 0; i != _metrics.end(); ++i) {
1106
1107                 if ((*i)->frame() > where) {
1108                         break;
1109                 }
1110
1111                 TempoSection* t;
1112
1113                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1114                         if (!t->active()) {
1115                                 continue;
1116                         }
1117                         if (!first) {
1118                                 first = t;
1119                         }
1120                         prev = t;
1121                 }
1122         }
1123
1124         if (!prev) {
1125                 if (!first) {
1126                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
1127                         return;
1128                 }
1129
1130                 prev = first;
1131         }
1132
1133         /* reset */
1134
1135         {
1136                 Glib::Threads::RWLock::WriterLock lm (lock);
1137                 /* cannot move the first tempo section */
1138                 *((Tempo*)prev) = newtempo;
1139                 recompute_map (_metrics);
1140         }
1141
1142         PropertyChanged (PropertyChange ());
1143 }
1144
1145 const MeterSection&
1146 TempoMap::first_meter () const
1147 {
1148         const MeterSection *m = 0;
1149
1150         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1151                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
1152                         return *m;
1153                 }
1154         }
1155
1156         fatal << _("programming error: no meter section in tempo map!") << endmsg;
1157         abort(); /*NOTREACHED*/
1158         return *m;
1159 }
1160
1161 MeterSection&
1162 TempoMap::first_meter ()
1163 {
1164         MeterSection *m = 0;
1165
1166         /* CALLER MUST HOLD LOCK */
1167
1168         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1169                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1170                         return *m;
1171                 }
1172         }
1173
1174         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1175         abort(); /*NOTREACHED*/
1176         return *m;
1177 }
1178
1179 const TempoSection&
1180 TempoMap::first_tempo () const
1181 {
1182         const TempoSection *t = 0;
1183
1184         /* CALLER MUST HOLD LOCK */
1185
1186         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1187                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1188                         if (!t->active()) {
1189                                 continue;
1190                         }
1191                         if (!t->movable()) {
1192                                 return *t;
1193                         }
1194                 }
1195         }
1196
1197         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1198         abort(); /*NOTREACHED*/
1199         return *t;
1200 }
1201
1202 TempoSection&
1203 TempoMap::first_tempo ()
1204 {
1205         TempoSection *t = 0;
1206
1207         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1208                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1209                         if (!t->active()) {
1210                                 continue;
1211                         }
1212                         if (!t->movable()) {
1213                                 return *t;
1214                         }
1215                 }
1216         }
1217
1218         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1219         abort(); /*NOTREACHED*/
1220         return *t;
1221 }
1222 void
1223 TempoMap::recompute_tempos (Metrics& metrics)
1224 {
1225         TempoSection* prev_ts = 0;
1226
1227         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1228                 TempoSection* t;
1229
1230                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1231                         if (!t->active()) {
1232                                 continue;
1233                         }
1234                         if (prev_ts) {
1235                                 if (t->position_lock_style() == AudioTime) {
1236                                         prev_ts->set_c_func (prev_ts->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1237                                         t->set_pulse (prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate));
1238
1239                                 } else {
1240                                         prev_ts->set_c_func (prev_ts->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1241                                         t->set_frame (prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate));
1242
1243                                 }
1244                         }
1245                         prev_ts = t;
1246                 }
1247         }
1248         prev_ts->set_c_func (0.0);
1249 }
1250
1251 /* tempos must be positioned correctly */
1252 void
1253 TempoMap::recompute_meters (Metrics& metrics)
1254 {
1255         MeterSection* meter = 0;
1256         MeterSection* prev_m = 0;
1257
1258         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1259                 if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
1260                         if (meter->position_lock_style() == AudioTime) {
1261                                 double pulse = 0.0;
1262                                 pair<double, BBT_Time> b_bbt;
1263                                 if (meter->movable()) {
1264                                         const double beats = ((pulse_at_frame_locked (metrics, meter->frame()) - prev_m->pulse()) * prev_m->note_divisor()) - prev_m->beat();
1265                                         const double ceil_beats = beats - fmod (beats, prev_m->divisions_per_bar());
1266                                         b_bbt = make_pair (ceil_beats, BBT_Time ((ceil_beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1267                                         const double true_pulse = prev_m->pulse() + (ceil_beats - prev_m->beat()) / prev_m->note_divisor();
1268                                         const double pulse_off = true_pulse - ((beats - prev_m->beat()) / prev_m->note_divisor());
1269                                         pulse = true_pulse - pulse_off;
1270                                 } else {
1271                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
1272                                 }
1273                                 meter->set_beat (b_bbt);
1274                                 meter->set_pulse (pulse);
1275                         } else {
1276                                 double pulse = 0.0;
1277                                 if (prev_m) {
1278                                         pulse = prev_m->pulse() + (meter->beat() - prev_m->beat()) / prev_m->note_divisor();
1279                                 } else {
1280                                         pulse = pulse_at_beat_locked (metrics, meter->beat());
1281                                 }
1282                                 meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1283                                 meter->set_pulse (pulse);
1284                         }
1285
1286                         prev_m = meter;
1287                 }
1288         }
1289 }
1290
1291 void
1292 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1293 {
1294         /* CALLER MUST HOLD WRITE LOCK */
1295
1296         if (end < 0) {
1297
1298                 /* we will actually stop once we hit
1299                    the last metric.
1300                 */
1301                 end = max_framepos;
1302
1303         }
1304
1305         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1306
1307         if (end == 0) {
1308                 /* silly call from Session::process() during startup
1309                  */
1310                 return;
1311         }
1312
1313         recompute_tempos (metrics);
1314         recompute_meters (metrics);
1315 }
1316
1317 TempoMetric
1318 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1319 {
1320         Glib::Threads::RWLock::ReaderLock lm (lock);
1321         TempoMetric m (first_meter(), first_tempo());
1322
1323         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1324            at something, because we insert the default tempo and meter during
1325            TempoMap construction.
1326
1327            now see if we can find better candidates.
1328         */
1329
1330         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1331
1332                 if ((*i)->frame() > frame) {
1333                         break;
1334                 }
1335
1336                 m.set_metric(*i);
1337
1338                 if (last) {
1339                         *last = i;
1340                 }
1341         }
1342
1343         return m;
1344 }
1345
1346 /* XX meters only */
1347 TempoMetric
1348 TempoMap::metric_at (BBT_Time bbt) const
1349 {
1350         Glib::Threads::RWLock::ReaderLock lm (lock);
1351         TempoMetric m (first_meter(), first_tempo());
1352
1353         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1354            at something, because we insert the default tempo and meter during
1355            TempoMap construction.
1356
1357            now see if we can find better candidates.
1358         */
1359
1360         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1361                 MeterSection* mw;
1362                 if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
1363                         BBT_Time section_start (mw->bbt());
1364
1365                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1366                                 break;
1367                         }
1368
1369                         m.set_metric (*i);
1370                 }
1371         }
1372
1373         return m;
1374 }
1375
1376 double
1377 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1378 {
1379         /* HOLD (at least) THE READER LOCK */
1380         TempoSection* prev_ts = 0;
1381         double accumulated_pulses = 0.0;
1382
1383         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1384                 TempoSection* t;
1385                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1386                         if (!t->active()) {
1387                                 continue;
1388                         }
1389                         if (prev_ts && t->frame() > frame) {
1390                                 /*the previous ts is the one containing the frame */
1391                                 const double ret = prev_ts->pulse_at_frame (frame, _frame_rate);
1392                                 return ret;
1393                         }
1394                         accumulated_pulses = t->pulse();
1395                         prev_ts = t;
1396                 }
1397         }
1398
1399         /* treated as constant for this ts */
1400         const double pulses_in_section = (frame - prev_ts->frame()) / prev_ts->frames_per_pulse (_frame_rate);
1401
1402         return pulses_in_section + accumulated_pulses;
1403 }
1404
1405 double
1406 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1407 {
1408         MeterSection* prev_ms = 0;
1409         double accumulated_beats = 0.0;
1410
1411         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1412                 MeterSection* m;
1413                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1414                         if (prev_ms && m->beat() > beat) {
1415                                 break;
1416                         }
1417                         accumulated_beats = m->beat();
1418                         prev_ms = m;
1419                 }
1420
1421         }
1422         double const ret = prev_ms->pulse() + ((beat - accumulated_beats) / prev_ms->note_divisor());
1423         return ret;
1424 }
1425
1426 double
1427 TempoMap::pulse_at_beat (const double& beat) const
1428 {
1429         Glib::Threads::RWLock::ReaderLock lm (lock);
1430         return pulse_at_beat_locked (_metrics, beat);
1431 }
1432
1433 double
1434 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1435 {
1436         MeterSection* prev_ms = 0;
1437         double accumulated_beats = 0.0;
1438
1439         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1440                 MeterSection* m;
1441                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1442                         if (prev_ms && m->pulse() > pulse) {
1443                                 break;
1444                         }
1445                         accumulated_beats = m->beat();
1446                         prev_ms = m;
1447                 }
1448         }
1449
1450         double const beats_in_section = (pulse - prev_ms->pulse()) * prev_ms->note_divisor();
1451
1452         return beats_in_section + accumulated_beats;
1453 }
1454
1455 double
1456 TempoMap::beat_at_pulse (const double& pulse) const
1457 {
1458         Glib::Threads::RWLock::ReaderLock lm (lock);
1459         return beat_at_pulse_locked (_metrics, pulse);
1460 }
1461
1462 framecnt_t
1463 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1464 {
1465         /* HOLD THE READER LOCK */
1466
1467         const TempoSection* prev_ts = 0;
1468         double accumulated_pulses = 0.0;
1469
1470         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1471                 TempoSection* t;
1472
1473                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1474                         if (!t->active()) {
1475                                 continue;
1476                         }
1477                         if (prev_ts && t->pulse() > pulse) {
1478                                 return prev_ts->frame_at_pulse (pulse, _frame_rate);
1479                         }
1480
1481                         accumulated_pulses = t->pulse();
1482                         prev_ts = t;
1483                 }
1484         }
1485         /* must be treated as constant, irrespective of _type */
1486         double const pulses_in_section = pulse - accumulated_pulses;
1487         double const dtime = pulses_in_section * prev_ts->frames_per_pulse (_frame_rate);
1488
1489         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_ts->frame();
1490
1491         return ret;
1492 }
1493
1494 double
1495 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1496 {
1497         const double pulse = pulse_at_frame_locked (metrics, frame);
1498         return beat_at_pulse_locked (metrics, pulse);
1499 }
1500
1501 double
1502 TempoMap::beat_at_frame (const framecnt_t& frame) const
1503 {
1504         Glib::Threads::RWLock::ReaderLock lm (lock);
1505         return beat_at_frame_locked (_metrics, frame);
1506 }
1507
1508 framecnt_t
1509 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1510 {
1511         const framecnt_t frame = frame_at_pulse_locked (metrics, pulse_at_beat_locked (metrics, beat));
1512         return frame;
1513 }
1514
1515 framecnt_t
1516 TempoMap::frame_at_beat (const double& beat) const
1517 {
1518         Glib::Threads::RWLock::ReaderLock lm (lock);
1519         return frame_at_beat_locked (_metrics, beat);
1520 }
1521
1522 double
1523 TempoMap::bbt_to_beats_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1524 {
1525         /* CALLER HOLDS READ LOCK */
1526
1527         double accumulated_beats = 0.0;
1528         double accumulated_bars = 0.0;
1529         MeterSection* prev_ms = 0;
1530
1531         /* because audio-locked meters have 'fake' integral beats,
1532            there is no pulse offset here.
1533         */
1534         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1535                 MeterSection* m;
1536                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1537                         if (prev_ms) {
1538                                 const double bars_to_m = (m->beat() - prev_ms->beat()) / prev_ms->divisions_per_bar();
1539                                 if ((bars_to_m + accumulated_bars) > (bbt.bars - 1)) {
1540                                         break;
1541                                 }
1542                                 accumulated_beats = m->beat();
1543                                 accumulated_bars += bars_to_m;
1544                         }
1545                         prev_ms = m;
1546                 }
1547         }
1548
1549         const double remaining_bars = (bbt.bars - 1) - accumulated_bars;
1550         const double remaining_bars_in_beats = remaining_bars * prev_ms->divisions_per_bar();
1551         const double ret = remaining_bars_in_beats + accumulated_beats + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1552
1553         return ret;
1554 }
1555
1556 double
1557 TempoMap::bbt_to_beats (const Timecode::BBT_Time& bbt)
1558 {
1559         Glib::Threads::RWLock::ReaderLock lm (lock);
1560         return bbt_to_beats_locked (_metrics, bbt);
1561 }
1562
1563 Timecode::BBT_Time
1564 TempoMap::beats_to_bbt_locked (const Metrics& metrics, const double& b) const
1565 {
1566         /* CALLER HOLDS READ LOCK */
1567         MeterSection* prev_ms = 0;
1568         const double beats = (b < 0.0) ? 0.0 : b;
1569         uint32_t accumulated_bars = 0;
1570         double accumulated_beats = 0.0;
1571
1572         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1573                 MeterSection* m = 0;
1574
1575                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1576                         if (prev_ms) {
1577                                 if (m->beat() > beats) {
1578                                         /* this is the meter after the one our beat is on*/
1579                                         break;
1580                                 }
1581                                 const double beats_to_m = m->beat() - prev_ms->beat();
1582                                 /* we need a whole number of bars. */
1583                                 accumulated_bars += (beats_to_m + 1) / prev_ms->divisions_per_bar();
1584                                 accumulated_beats += beats_to_m;
1585                         }
1586
1587                         prev_ms = m;
1588                 }
1589         }
1590
1591         const double beats_in_ms = beats - accumulated_beats;
1592         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_ms->divisions_per_bar());
1593         const uint32_t total_bars = bars_in_ms + accumulated_bars;
1594         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_ms->divisions_per_bar());
1595         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1596
1597         BBT_Time ret;
1598
1599         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1600         ret.beats = (uint32_t) floor (remaining_beats);
1601         ret.bars = total_bars;
1602
1603         /* 0 0 0 to 1 1 0 - based mapping*/
1604         ++ret.bars;
1605         ++ret.beats;
1606
1607         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1608                 ++ret.beats;
1609                 ret.ticks -= BBT_Time::ticks_per_beat;
1610         }
1611
1612         if (ret.beats >= prev_ms->divisions_per_bar() + 1) {
1613                 ++ret.bars;
1614                 ret.beats = 1;
1615         }
1616
1617         return ret;
1618 }
1619
1620 Timecode::BBT_Time
1621 TempoMap::beats_to_bbt (const double& beats)
1622 {
1623         Glib::Threads::RWLock::ReaderLock lm (lock);
1624         return beats_to_bbt_locked (_metrics, beats);
1625 }
1626
1627 Timecode::BBT_Time
1628 TempoMap::pulse_to_bbt (const double& pulse)
1629 {
1630         Glib::Threads::RWLock::ReaderLock lm (lock);
1631         MeterSection* prev_ms = 0;
1632         uint32_t accumulated_bars = 0;
1633         double accumulated_pulses = 0.0;
1634
1635         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1636                 MeterSection* m = 0;
1637
1638                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1639
1640                         if (prev_ms) {
1641                                 double const pulses_to_m = m->pulse() - prev_ms->pulse();
1642                                 if (accumulated_pulses + pulses_to_m > pulse) {
1643                                         /* this is the meter after the one our beat is on*/
1644                                         break;
1645                                 }
1646
1647                                 /* we need a whole number of bars. */
1648                                 accumulated_pulses += pulses_to_m;
1649                                 accumulated_bars += ((pulses_to_m * prev_ms->note_divisor()) + 1) / prev_ms->divisions_per_bar();
1650                         }
1651
1652                         prev_ms = m;
1653                 }
1654         }
1655         const double beats_in_ms = (pulse - prev_ms->pulse()) * prev_ms->note_divisor();
1656         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_ms->divisions_per_bar());
1657         const uint32_t total_bars = bars_in_ms + accumulated_bars;
1658         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_ms->divisions_per_bar());
1659         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1660
1661         BBT_Time ret;
1662
1663         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1664         ret.beats = (uint32_t) floor (remaining_beats);
1665         ret.bars = total_bars;
1666
1667         /* 0 0 0 to 1 1 0 mapping*/
1668         ++ret.bars;
1669         ++ret.beats;
1670
1671         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1672                 ++ret.beats;
1673                 ret.ticks -= BBT_Time::ticks_per_beat;
1674         }
1675
1676         if (ret.beats >= prev_ms->divisions_per_bar() + 1) {
1677                 ++ret.bars;
1678                 ret.beats = 1;
1679         }
1680
1681         return ret;
1682 }
1683
1684 void
1685 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1686 {
1687
1688         if (frame < 0) {
1689                 bbt.bars = 1;
1690                 bbt.beats = 1;
1691                 bbt.ticks = 0;
1692                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1693                 return;
1694         }
1695         Glib::Threads::RWLock::ReaderLock lm (lock);
1696         const double beat = beat_at_frame_locked (_metrics, frame);
1697
1698         bbt = beats_to_bbt_locked (_metrics, beat);
1699 }
1700
1701 framepos_t
1702 TempoMap::frame_time_locked (const Metrics& metrics, const BBT_Time& bbt) const
1703 {
1704         /* HOLD THE READER LOCK */
1705
1706         const framepos_t ret = frame_at_beat_locked (metrics, bbt_to_beats_locked (metrics, bbt));
1707         return ret;
1708 }
1709
1710 framepos_t
1711 TempoMap::frame_time (const BBT_Time& bbt)
1712 {
1713         if (bbt.bars < 1) {
1714                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1715                 return 0;
1716         }
1717
1718         if (bbt.beats < 1) {
1719                 throw std::logic_error ("beats are counted from one");
1720         }
1721         Glib::Threads::RWLock::ReaderLock lm (lock);
1722         const double beat = bbt_to_beats_locked (_metrics, bbt);
1723         const framecnt_t frame = frame_at_beat_locked (_metrics, beat);
1724
1725         return frame;
1726 }
1727
1728 bool
1729 TempoMap::check_solved (Metrics& metrics, bool by_frame)
1730 {
1731         TempoSection* prev_ts = 0;
1732
1733         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1734                 TempoSection* t;
1735                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1736                         if (!t->active()) {
1737                                 continue;
1738                         }
1739                         if (prev_ts) {
1740                                 if ((by_frame && t->frame() < prev_ts->frame()) || (!by_frame && t->pulse() < prev_ts->pulse())) {
1741                                         return false;
1742                                 }
1743
1744                                 if (t->frame() == prev_ts->frame()) {
1745                                         return false;
1746                                 }
1747
1748                                 /* precision check ensures pulses and frames align independent of lock style.*/
1749                                 if (by_frame && t->frame() != prev_ts->frame_at_pulse (t->pulse(), _frame_rate)) {
1750                                         return false;
1751                                 }
1752                         }
1753                         prev_ts = t;
1754                 }
1755         }
1756
1757         return true;
1758 }
1759
1760 bool
1761 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
1762 {
1763         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1764                 TempoSection* t;
1765                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1766                         if (!t->movable()) {
1767                                 t->set_active (true);
1768                                 continue;
1769                         }
1770                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
1771                                 t->set_active (false);
1772                                 t->set_pulse (0.0);
1773                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
1774                                 t->set_active (true);
1775                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
1776                                 return false;
1777                         }
1778                 }
1779         }
1780         return true;
1781 }
1782
1783 bool
1784 TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const Tempo& bpm, const framepos_t& frame)
1785 {
1786         TempoSection* prev_ts = 0;
1787         TempoSection* section_prev = 0;
1788         framepos_t first_m_frame = 0;
1789
1790         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1791                 MeterSection* m;
1792                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1793                         if (!m->movable()) {
1794                                 first_m_frame = m->frame();
1795                                 break;
1796                         }
1797                 }
1798         }
1799         if (section->movable() && frame <= first_m_frame) {
1800                 return false;
1801         } else {
1802                 section->set_active (true);
1803         }
1804         section->set_frame (frame);
1805
1806         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1807                 TempoSection* t;
1808                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1809
1810                         if (!t->active()) {
1811                                 continue;
1812                         }
1813                         if (prev_ts) {
1814                                 if (t == section) {
1815                                         section_prev = prev_ts;
1816                                         continue;
1817                                 }
1818                                 if (t->position_lock_style() == MusicTime) {
1819                                         prev_ts->set_c_func (prev_ts->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1820                                         t->set_frame (prev_ts->frame_at_pulse (t->pulse(), _frame_rate));
1821                                 } else {
1822                                         prev_ts->set_c_func (prev_ts->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1823                                         t->set_pulse (prev_ts->pulse_at_frame (t->frame(), _frame_rate));
1824                                 }
1825                         }
1826                         prev_ts = t;
1827                 }
1828         }
1829
1830         if (section_prev) {
1831                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
1832                 section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
1833         }
1834
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
1844         if (check_solved (imaginary, true)) {
1845                 recompute_meters (imaginary);
1846                 return true;
1847         }
1848
1849         MetricSectionFrameSorter fcmp;
1850         imaginary.sort (fcmp);
1851         if (section->position_lock_style() == MusicTime) {
1852                 /* we're setting the frame */
1853                 section->set_position_lock_style (AudioTime);
1854                 recompute_tempos (imaginary);
1855                 section->set_position_lock_style (MusicTime);
1856         } else {
1857                 recompute_tempos (imaginary);
1858         }
1859         if (check_solved (imaginary, true)) {
1860                 recompute_meters (imaginary);
1861                 return true;
1862         }
1863
1864         MetricSectionSorter cmp;
1865         imaginary.sort (cmp);
1866         if (section->position_lock_style() == MusicTime) {
1867                 /* we're setting the frame */
1868                 section->set_position_lock_style (AudioTime);
1869                 recompute_tempos (imaginary);
1870                 section->set_position_lock_style (MusicTime);
1871         } else {
1872                 recompute_tempos (imaginary);
1873         }
1874         if (check_solved (imaginary, true)) {
1875                 recompute_meters (imaginary);
1876                 return true;
1877         }
1878         //dump (imaginary, std::cerr);
1879
1880         return false;
1881 }
1882
1883 bool
1884 TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const Tempo& bpm, const double& pulse)
1885 {
1886         TempoSection* prev_ts = 0;
1887         TempoSection* section_prev = 0;
1888
1889         section->set_pulse (pulse);
1890
1891         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1892                 TempoSection* t;
1893                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1894                         if (!t->active()) {
1895                                 continue;
1896                         }
1897                         if (prev_ts) {
1898                                 if (t == section) {
1899                                         section_prev = prev_ts;
1900                                         continue;
1901                                 }
1902                                 if (t->position_lock_style() == MusicTime) {
1903                                         prev_ts->set_c_func (prev_ts->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1904                                         t->set_frame (prev_ts->frame_at_pulse (t->pulse(), _frame_rate));
1905                                 } else {
1906                                         prev_ts->set_c_func (prev_ts->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1907                                         t->set_pulse (prev_ts->pulse_at_frame (t->frame(), _frame_rate));
1908                                 }
1909                         }
1910                         prev_ts = t;
1911                 }
1912         }
1913         if (section_prev) {
1914                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
1915                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
1916         }
1917
1918         if (section->position_lock_style() == AudioTime) {
1919                 /* we're setting the pulse */
1920                 section->set_position_lock_style (MusicTime);
1921                 recompute_tempos (imaginary);
1922                 section->set_position_lock_style (AudioTime);
1923         } else {
1924                 recompute_tempos (imaginary);
1925         }
1926         if (check_solved (imaginary, false)) {
1927                 recompute_meters (imaginary);
1928                 return true;
1929         }
1930
1931         MetricSectionSorter cmp;
1932         imaginary.sort (cmp);
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         MetricSectionFrameSorter fcmp;
1948         imaginary.sort (fcmp);
1949         if (section->position_lock_style() == AudioTime) {
1950                 /* we're setting the pulse */
1951                 section->set_position_lock_style (MusicTime);
1952                 recompute_tempos (imaginary);
1953                 section->set_position_lock_style (AudioTime);
1954         } else {
1955                 recompute_tempos (imaginary);
1956         }
1957
1958         if (check_solved (imaginary, false)) {
1959                 recompute_meters (imaginary);
1960                 return true;
1961         }
1962
1963         //dump (imaginary, std::cerr);
1964
1965         return false;
1966 }
1967
1968 void
1969 TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const Meter& mt, const framepos_t& frame)
1970 {
1971         MeterSection* prev_ms = 0;
1972
1973         if (!section->movable()) {
1974                 /* lock the first tempo to our first meter */
1975                 if (!set_active_tempos (imaginary, frame)) {
1976                         return;
1977                 }
1978                 TempoSection* first_t = &first_tempo();
1979                 Metrics future_map;
1980                 TempoSection* new_section = copy_metrics_and_point (future_map, first_t);
1981
1982                 new_section->set_frame (frame);
1983                 new_section->set_pulse (0.0);
1984                 new_section->set_active (true);
1985
1986                 if (solve_map (future_map, new_section, Tempo (new_section->beats_per_minute(), new_section->note_type()), frame)) {
1987                         first_t->set_frame (frame);
1988                         first_t->set_pulse (0.0);
1989                         first_t->set_active (true);
1990                         solve_map (imaginary, first_t, Tempo (first_t->beats_per_minute(), first_t->note_type()), frame);
1991                 } else {
1992                         return;
1993                 }
1994         }
1995
1996         section->set_frame (frame);
1997
1998         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1999                 MeterSection* m;
2000                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2001                         if (m == section){
2002                                 /*
2003                                   here we set the beat for this frame.
2004                                   we set it 'incorrectly' to the next bar's beat
2005                                   and use this difference to find the meter's pulse.
2006                                 */
2007                                 double pulse = 0.0;
2008                                 pair<double, BBT_Time> b_bbt;
2009                                 if (m->movable()) {
2010                                         const double beats = ((pulse_at_frame_locked (imaginary, frame) - prev_ms->pulse()) * prev_ms->note_divisor()) - prev_ms->beat();
2011                                         const double ceil_beats = beats - fmod (beats,  prev_ms->divisions_per_bar());
2012                                         b_bbt = make_pair (ceil_beats, BBT_Time ((ceil_beats / prev_ms->divisions_per_bar()) + prev_ms->bbt().bars, 1, 0));
2013                                         const double true_pulse = prev_ms->pulse() + ((ceil_beats - prev_ms->beat()) / prev_ms->note_divisor());
2014                                         const double pulse_off = true_pulse - ((beats - prev_ms->beat()) / prev_ms->note_divisor());
2015                                         pulse = true_pulse - pulse_off;
2016                                 } else {
2017                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2018                                 }
2019                                 m->set_beat (b_bbt);
2020                                 m->set_pulse (pulse);
2021                                 prev_ms = m;
2022                                 continue;
2023                         }
2024                         if (prev_ms) {
2025                                 if (m->position_lock_style() == MusicTime) {
2026                                         const double pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2027                                         m->set_frame (frame_at_pulse_locked (imaginary, pulse));
2028                                         m->set_pulse (pulse);
2029                                 } else {
2030                                         double pulse = 0.0;
2031                                         pair<double, BBT_Time> b_bbt;
2032                                         if (m->movable()) {
2033                                                 const double beats = ((pulse_at_frame_locked (imaginary, m->frame()) - prev_ms->pulse()) * prev_ms->note_divisor()) - prev_ms->beat();
2034                                                 const double ceil_beats = beats - fmod (beats , prev_ms->divisions_per_bar());
2035                                                 b_bbt = make_pair (ceil_beats, BBT_Time ((ceil_beats / prev_ms->divisions_per_bar()) + prev_ms->bbt().bars, 1, 0));
2036                                                 const double true_pulse = prev_ms->pulse() + (ceil_beats - prev_ms->beat()) / prev_ms->note_divisor();
2037                                                 const double pulse_off = true_pulse - ((beats - prev_ms->beat()) / prev_ms->note_divisor());
2038                                                 pulse = true_pulse - pulse_off;
2039                                         } else {
2040                                                 b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2041                                                 pulse = 0.0;
2042                                         }
2043                                         m->set_beat (b_bbt);
2044                                         m->set_pulse (pulse);
2045                                 }
2046                         }
2047                         prev_ms = m;
2048                 }
2049         }
2050
2051         if (section->position_lock_style() == MusicTime) {
2052                 /* we're setting the frame */
2053                 section->set_position_lock_style (AudioTime);
2054                 recompute_meters (imaginary);
2055                 section->set_position_lock_style (MusicTime);
2056         } else {
2057                 recompute_meters (imaginary);
2058         }
2059         //dump (imaginary, std::cerr);
2060 }
2061
2062 void
2063 TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const Meter& mt, const double& pulse)
2064 {
2065         MeterSection* prev_ms = 0;
2066
2067         section->set_pulse (pulse);
2068
2069         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2070                 MeterSection* m;
2071                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2072                         if (m == section){
2073                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2074                                 const double beats = ((pulse - prev_ms->pulse()) * prev_ms->note_divisor()) - prev_ms->beat();
2075                                 const int32_t bars = (beats + 1) / prev_ms->divisions_per_bar();
2076                                 pair<double, BBT_Time> b_bbt = make_pair (beats, BBT_Time (bars + 1, 1, 0));
2077                                 section->set_beat (b_bbt);
2078                                 prev_ms = section;
2079                                 continue;
2080                         }
2081                         if (prev_ms) {
2082                                 if (m->position_lock_style() == MusicTime) {
2083                                         const double pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2084                                         m->set_frame (frame_at_pulse_locked (imaginary, pulse));
2085                                         m->set_pulse (pulse);
2086                                 } else {
2087                                         double pulse = 0.0;
2088                                         pair<double, BBT_Time> b_bbt;
2089                                         if (m->movable()) {
2090                                                 const double beats = ((pulse_at_frame_locked (imaginary, m->frame()) - prev_ms->pulse()) * prev_ms->note_divisor()) - prev_ms->beat();
2091                                                 const double ceil_beats = beats - fmod (beats, prev_ms->divisions_per_bar());
2092                                                 b_bbt = make_pair (ceil_beats, BBT_Time ((ceil_beats / prev_ms->divisions_per_bar()) + prev_ms->bbt().bars, 1, 0));
2093                                                 const double true_pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2094                                                 const double pulse_off = true_pulse - ((ceil_beats - prev_ms->beat()) / prev_ms->note_divisor());
2095                                                 pulse = true_pulse - pulse_off;
2096                                         } else {
2097                                                 b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2098                                         }
2099                                         m->set_beat (b_bbt);
2100                                         m->set_pulse (pulse);
2101                                 }
2102                         }
2103                         prev_ms = m;
2104                 }
2105         }
2106
2107         if (section->position_lock_style() == AudioTime) {
2108                 /* we're setting the pulse */
2109                 section->set_position_lock_style (MusicTime);
2110                 recompute_meters (imaginary);
2111                 section->set_position_lock_style (AudioTime);
2112         } else {
2113                 recompute_meters (imaginary);
2114         }
2115 }
2116
2117 /** places a copy of _metrics into copy and returns a pointer
2118  *  to section's equivalent.
2119  */
2120 TempoSection*
2121 TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
2122 {
2123         TempoSection* t;
2124         TempoSection* ret = 0;
2125         MeterSection* m;
2126
2127         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2128                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2129                         if (t == section) {
2130                                 if (t->position_lock_style() == MusicTime) {
2131                                         ret = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
2132                                 } else {
2133                                         ret = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
2134                                 }
2135                                 ret->set_active (t->active());
2136                                 ret->set_movable (t->movable());
2137                                 copy.push_back (ret);
2138                                 continue;
2139                         }
2140                         TempoSection* cp = 0;
2141                         if (t->position_lock_style() == MusicTime) {
2142                                 cp = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
2143                         } else {
2144                                 cp = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
2145                         }
2146                         cp->set_active (t->active());
2147                         cp->set_movable (t->movable());
2148                         copy.push_back (cp);
2149                 }
2150                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2151                         MeterSection* cp = 0;
2152                         if (m->position_lock_style() == MusicTime) {
2153                                 cp = new MeterSection (m->pulse(), m->beat(), m->bbt(), m->divisions_per_bar(), m->note_divisor());
2154                                 cp->set_frame (m->frame());
2155                         } else {
2156                                 cp = new MeterSection (m->frame(), m->beat(), m->bbt(), m->divisions_per_bar(), m->note_divisor());
2157                                 cp->set_pulse (m->pulse());
2158                         }
2159                         cp->set_movable (m->movable());
2160                         copy.push_back (cp);
2161                 }
2162         }
2163         //recompute_map (copy);
2164         return ret;
2165 }
2166
2167 bool
2168 TempoMap::can_solve_bbt (TempoSection* ts,  const Tempo& bpm, const BBT_Time& bbt)
2169 {
2170         Metrics copy;
2171         TempoSection* new_section = 0;
2172
2173         {
2174                 Glib::Threads::RWLock::ReaderLock lm (lock);
2175                 new_section = copy_metrics_and_point (copy, ts);
2176         }
2177
2178         double const beat = bbt_to_beats_locked (copy, bbt);
2179         bool ret = solve_map (copy, new_section, bpm, pulse_at_beat_locked (copy, beat));
2180
2181         Metrics::const_iterator d = copy.begin();
2182         while (d != copy.end()) {
2183                 delete (*d);
2184                 ++d;
2185         }
2186
2187         return ret;
2188 }
2189
2190 /**
2191 * 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,
2192 * taking any possible reordering as a consequence of this into account.
2193 * @param section - the section to be altered
2194 * @param bpm - the new Tempo
2195 * @param bbt - the bbt where the altered tempo will fall
2196 * @return returns - the position in frames where the new tempo section will lie.
2197 */
2198 framepos_t
2199 TempoMap::predict_tempo_frame (TempoSection* section, const Tempo& bpm, const BBT_Time& bbt)
2200 {
2201         Glib::Threads::RWLock::ReaderLock lm (lock);
2202         Metrics future_map;
2203         framepos_t ret = 0;
2204         TempoSection* new_section = copy_metrics_and_point (future_map, section);
2205
2206         const double beat = bbt_to_beats_locked (future_map, bbt);
2207         if (solve_map (future_map, new_section, bpm, pulse_at_beat_locked (future_map, beat))) {
2208                 ret = new_section->frame();
2209         } else {
2210                 ret = frame_at_beat_locked (_metrics, beat);
2211         }
2212
2213         Metrics::const_iterator d = future_map.begin();
2214         while (d != future_map.end()) {
2215                 delete (*d);
2216                 ++d;
2217         }
2218         return ret;
2219 }
2220
2221 double
2222 TempoMap::predict_tempo_pulse (TempoSection* section, const Tempo& bpm, const framepos_t& frame)
2223 {
2224         Glib::Threads::RWLock::ReaderLock lm (lock);
2225         Metrics future_map;
2226         double ret = 0.0;
2227         TempoSection* new_section = copy_metrics_and_point (future_map, section);
2228
2229         if (solve_map (future_map, new_section, bpm, frame)) {
2230                 ret = new_section->pulse();
2231         } else {
2232                 ret = pulse_at_frame_locked (_metrics, frame);
2233         }
2234
2235         Metrics::const_iterator d = future_map.begin();
2236         while (d != future_map.end()) {
2237                 delete (*d);
2238                 ++d;
2239         }
2240         return ret;
2241 }
2242
2243 void
2244 TempoMap::gui_move_tempo_frame (TempoSection* ts,  const Tempo& bpm, const framepos_t& frame)
2245 {
2246         Metrics future_map;
2247         {
2248                 Glib::Threads::RWLock::WriterLock lm (lock);
2249                 TempoSection* new_section = copy_metrics_and_point (future_map, ts);
2250                 if (solve_map (future_map, new_section, bpm, frame)) {
2251                         solve_map (_metrics, ts, bpm, frame);
2252                 }
2253         }
2254
2255         Metrics::const_iterator d = future_map.begin();
2256         while (d != future_map.end()) {
2257                 delete (*d);
2258                 ++d;
2259         }
2260
2261         MetricPositionChanged (); // Emit Signal
2262 }
2263
2264 void
2265 TempoMap::gui_move_tempo_beat (TempoSection* ts,  const Tempo& bpm, const double& beat)
2266 {
2267         Metrics future_map;
2268         {
2269                 Glib::Threads::RWLock::WriterLock lm (lock);
2270                 TempoSection* new_section = copy_metrics_and_point (future_map, ts);
2271                 if (solve_map (future_map, new_section, bpm, pulse_at_beat_locked (future_map, beat))) {
2272                         solve_map (_metrics, ts, bpm, pulse_at_beat_locked (_metrics, beat));
2273                 }
2274         }
2275
2276         Metrics::const_iterator d = future_map.begin();
2277         while (d != future_map.end()) {
2278                 delete (*d);
2279                 ++d;
2280         }
2281
2282         MetricPositionChanged (); // Emit Signal
2283 }
2284
2285 void
2286 TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const framepos_t&  frame)
2287 {
2288         {
2289                 Glib::Threads::RWLock::WriterLock lm (lock);
2290                 solve_map (_metrics, ms, mt, frame);
2291         }
2292
2293         MetricPositionChanged (); // Emit Signal
2294 }
2295
2296 void
2297 TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const double&  beat)
2298 {
2299         {
2300                 Glib::Threads::RWLock::WriterLock lm (lock);
2301                 solve_map (_metrics, ms, mt, pulse_at_beat_locked (_metrics, beat));
2302         }
2303
2304         MetricPositionChanged (); // Emit Signal
2305 }
2306
2307 bool
2308 TempoMap::gui_change_tempo (TempoSection* ts,  const Tempo& bpm)
2309 {
2310         Metrics future_map;
2311         bool can_solve = false;
2312         {
2313                 Glib::Threads::RWLock::WriterLock lm (lock);
2314                 TempoSection* new_section = copy_metrics_and_point (future_map, ts);
2315                 new_section->set_beats_per_minute (bpm.beats_per_minute());
2316                 recompute_tempos (future_map);
2317
2318                 if (check_solved (future_map, true)) {
2319                         ts->set_beats_per_minute (bpm.beats_per_minute());
2320                         recompute_map (_metrics);
2321                         can_solve = true;
2322                 }
2323         }
2324
2325         Metrics::const_iterator d = future_map.begin();
2326         while (d != future_map.end()) {
2327                 delete (*d);
2328                 ++d;
2329         }
2330         if (can_solve) {
2331                 MetricPositionChanged (); // Emit Signal
2332         }
2333         return can_solve;
2334 }
2335
2336 framecnt_t
2337 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2338 {
2339         Glib::Threads::RWLock::ReaderLock lm (lock);
2340
2341         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2342         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2343         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2344         const framecnt_t time_at_bbt = frame_at_beat_locked (_metrics, total_beats);
2345         const framecnt_t ret = time_at_bbt;
2346
2347         return ret;
2348 }
2349
2350 framepos_t
2351 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2352 {
2353         return round_to_type (fr, dir, Bar);
2354 }
2355
2356 framepos_t
2357 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2358 {
2359         return round_to_type (fr, dir, Beat);
2360 }
2361
2362 framepos_t
2363 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2364 {
2365         Glib::Threads::RWLock::ReaderLock lm (lock);
2366         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2367         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2368         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2369
2370         ticks -= beats * BBT_Time::ticks_per_beat;
2371
2372         if (dir > 0) {
2373                 /* round to next (or same iff dir == RoundUpMaybe) */
2374
2375                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2376
2377                 if (mod == 0 && dir == RoundUpMaybe) {
2378                         /* right on the subdivision, which is fine, so do nothing */
2379
2380                 } else if (mod == 0) {
2381                         /* right on the subdivision, so the difference is just the subdivision ticks */
2382                         ticks += ticks_one_subdivisions_worth;
2383
2384                 } else {
2385                         /* not on subdivision, compute distance to next subdivision */
2386
2387                         ticks += ticks_one_subdivisions_worth - mod;
2388                 }
2389
2390                 if (ticks >= BBT_Time::ticks_per_beat) {
2391                         ticks -= BBT_Time::ticks_per_beat;
2392                 }
2393         } else if (dir < 0) {
2394
2395                 /* round to previous (or same iff dir == RoundDownMaybe) */
2396
2397                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2398
2399                 if (difference == 0 && dir == RoundDownAlways) {
2400                         /* right on the subdivision, but force-rounding down,
2401                            so the difference is just the subdivision ticks */
2402                         difference = ticks_one_subdivisions_worth;
2403                 }
2404
2405                 if (ticks < difference) {
2406                         ticks = BBT_Time::ticks_per_beat - ticks;
2407                 } else {
2408                         ticks -= difference;
2409                 }
2410
2411         } else {
2412                 /* round to nearest */
2413                 double rem;
2414
2415                 /* compute the distance to the previous and next subdivision */
2416
2417                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2418
2419                         /* closer to the next subdivision, so shift forward */
2420
2421                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2422
2423                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2424
2425                         if (ticks > BBT_Time::ticks_per_beat) {
2426                                 ++beats;
2427                                 ticks -= BBT_Time::ticks_per_beat;
2428                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2429                         }
2430
2431                 } else if (rem > 0) {
2432
2433                         /* closer to previous subdivision, so shift backward */
2434
2435                         if (rem > ticks) {
2436                                 if (beats == 0) {
2437                                         /* can't go backwards past zero, so ... */
2438                                         return 0;
2439                                 }
2440                                 /* step back to previous beat */
2441                                 --beats;
2442                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2443                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2444                         } else {
2445                                 ticks = lrint (ticks - rem);
2446                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2447                         }
2448                 } else {
2449                         /* on the subdivision, do nothing */
2450                 }
2451         }
2452
2453         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2454
2455         return ret_frame;
2456 }
2457
2458 void
2459 TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
2460 {
2461         if (sub_num == -1) {
2462                 const double bpb = meter_section_at (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
2463                 if ((double) when.beats > bpb / 2.0) {
2464                         ++when.bars;
2465                 }
2466                 when.beats = 1;
2467                 when.ticks = 0;
2468                 return;
2469         } else if (sub_num == 0) {
2470                 const double bpb = meter_section_at (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
2471                 if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
2472                         ++when.beats;
2473                         while ((double) when.beats > bpb) {
2474                                 ++when.bars;
2475                                 when.beats -= (uint32_t) floor (bpb);
2476                         }
2477                 }
2478                 when.ticks = 0;
2479                 return;
2480         }
2481         const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
2482         double rem;
2483         if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
2484                 /* closer to the next subdivision, so shift forward */
2485
2486                 when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
2487
2488                 if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
2489                         ++when.beats;
2490                         when.ticks -= Timecode::BBT_Time::ticks_per_beat;
2491                 }
2492
2493         } else if (rem > 0) {
2494                 /* closer to previous subdivision, so shift backward */
2495
2496                 if (rem > when.ticks) {
2497                         if (when.beats == 0) {
2498                                 /* can't go backwards past zero, so ... */
2499                         }
2500                         /* step back to previous beat */
2501                         --when.beats;
2502                         when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
2503                 } else {
2504                         when.ticks = when.ticks - rem;
2505                 }
2506         }
2507 }
2508
2509 framepos_t
2510 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2511 {
2512         Glib::Threads::RWLock::ReaderLock lm (lock);
2513
2514         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2515         BBT_Time bbt (beats_to_bbt_locked (_metrics, beat_at_framepos));
2516
2517         switch (type) {
2518         case Bar:
2519                 if (dir < 0) {
2520                         /* find bar previous to 'frame' */
2521                         bbt.beats = 1;
2522                         bbt.ticks = 0;
2523                         return frame_time (bbt);
2524
2525                 } else if (dir > 0) {
2526                         /* find bar following 'frame' */
2527                         ++bbt.bars;
2528                         bbt.beats = 1;
2529                         bbt.ticks = 0;
2530                         return frame_time (bbt);
2531                 } else {
2532                         /* true rounding: find nearest bar */
2533                         framepos_t raw_ft = frame_time (bbt);
2534                         bbt.beats = 1;
2535                         bbt.ticks = 0;
2536                         framepos_t prev_ft = frame_time (bbt);
2537                         ++bbt.bars;
2538                         framepos_t next_ft = frame_time (bbt);
2539
2540                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2541                                 return next_ft;
2542                         } else {
2543                                 return prev_ft;
2544                         }
2545                 }
2546
2547                 break;
2548
2549         case Beat:
2550                 if (dir < 0) {
2551                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2552                 } else if (dir > 0) {
2553                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2554                 } else {
2555                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2556                 }
2557                 break;
2558         }
2559
2560         return 0;
2561 }
2562
2563 void
2564 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2565                     framepos_t lower, framepos_t upper)
2566 {
2567         Glib::Threads::RWLock::ReaderLock lm (lock);
2568         const int32_t upper_beat = (int32_t) ceil (beat_at_frame_locked (_metrics, upper));
2569         int32_t cnt = floor (beat_at_frame_locked (_metrics, lower));
2570         /* although the map handles negative beats, bbt doesn't. */
2571         if (cnt < 0.0) {
2572                 cnt = 0.0;
2573         }
2574         while (cnt <= upper_beat) {
2575                 framecnt_t pos = frame_at_beat_locked (_metrics, cnt);
2576                 const TempoSection tempo = tempo_section_at_locked (pos);
2577                 const MeterSection meter = meter_section_at_locked (pos);
2578                 const BBT_Time bbt = beats_to_bbt (cnt);
2579                 points.push_back (BBTPoint (meter, tempo_at_locked (pos), pos, bbt.bars, bbt.beats, tempo.get_c_func()));
2580                 ++cnt;
2581         }
2582 }
2583
2584 const TempoSection&
2585 TempoMap::tempo_section_at (framepos_t frame) const
2586 {
2587         Glib::Threads::RWLock::ReaderLock lm (lock);
2588         return tempo_section_at_locked (frame);
2589 }
2590
2591 const TempoSection&
2592 TempoMap::tempo_section_at_locked (framepos_t frame) const
2593 {
2594         Metrics::const_iterator i;
2595         TempoSection* prev = 0;
2596
2597         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2598                 TempoSection* t;
2599
2600                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2601                         if (!t->active()) {
2602                                 continue;
2603                         }
2604                         if (t->frame() > frame) {
2605                                 break;
2606                         }
2607
2608                         prev = t;
2609                 }
2610         }
2611
2612         if (prev == 0) {
2613                 fatal << endmsg;
2614                 abort(); /*NOTREACHED*/
2615         }
2616
2617         return *prev;
2618 }
2619
2620
2621 /* don't use this to calculate length (the tempo is only correct for this frame).
2622    do that stuff based on the beat_at_frame and frame_at_beat api
2623 */
2624 double
2625 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
2626 {
2627         Glib::Threads::RWLock::ReaderLock lm (lock);
2628
2629         const TempoSection* ts_at = &tempo_section_at_locked (frame);
2630         const TempoSection* ts_after = 0;
2631         Metrics::const_iterator i;
2632
2633         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2634                 TempoSection* t;
2635
2636                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2637                         if (!t->active()) {
2638                                 continue;
2639                         }
2640                         if ((*i)->frame() > frame) {
2641                                 ts_after = t;
2642                                 break;
2643                         }
2644                 }
2645         }
2646
2647         if (ts_after) {
2648                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
2649         }
2650         /* must be treated as constant tempo */
2651         return ts_at->frames_per_beat (_frame_rate);
2652 }
2653
2654 const Tempo
2655 TempoMap::tempo_at (const framepos_t& frame) const
2656 {
2657         Glib::Threads::RWLock::ReaderLock lm (lock);
2658         return tempo_at_locked (frame);
2659 }
2660
2661 const Tempo
2662 TempoMap::tempo_at_locked (const framepos_t& frame) const
2663 {
2664         TempoSection* prev_ts = 0;
2665
2666         Metrics::const_iterator i;
2667
2668         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2669                 TempoSection* t;
2670                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2671                         if (!t->active()) {
2672                                 continue;
2673                         }
2674                         if ((prev_ts) && t->frame() > frame) {
2675                                 /* t is the section past frame */
2676                                 const double ret = prev_ts->tempo_at_frame (frame, _frame_rate) * prev_ts->note_type();
2677                                 const Tempo ret_tempo (ret, prev_ts->note_type());
2678                                 return ret_tempo;
2679                         }
2680                         prev_ts = t;
2681                 }
2682         }
2683
2684         const double ret = prev_ts->beats_per_minute();
2685         const Tempo ret_tempo (ret, prev_ts->note_type ());
2686
2687         return ret_tempo;
2688 }
2689
2690 const MeterSection&
2691 TempoMap::meter_section_at (framepos_t frame) const
2692 {
2693         Glib::Threads::RWLock::ReaderLock lm (lock);
2694         return meter_section_at_locked (frame);
2695 }
2696
2697 const MeterSection&
2698 TempoMap::meter_section_at_locked (framepos_t frame) const
2699 {
2700         //framepos_t const frame_off = frame + frame_offset_at (_metrics, frame);
2701         Metrics::const_iterator i;
2702         MeterSection* prev = 0;
2703
2704         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2705                 MeterSection* m;
2706
2707                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2708
2709                         if (prev && (*i)->frame() > frame) {
2710                                 break;
2711                         }
2712
2713                         prev = m;
2714                 }
2715         }
2716
2717         if (prev == 0) {
2718                 fatal << endmsg;
2719                 abort(); /*NOTREACHED*/
2720         }
2721
2722         return *prev;
2723 }
2724
2725 const Meter&
2726 TempoMap::meter_at (framepos_t frame) const
2727 {
2728         TempoMetric m (metric_at (frame));
2729         return m.meter();
2730 }
2731
2732 const MeterSection&
2733 TempoMap::meter_section_at (const double& beat) const
2734 {
2735         MeterSection* prev_ms = 0;
2736         Glib::Threads::RWLock::ReaderLock lm (lock);
2737
2738         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2739                 MeterSection* m;
2740                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2741                         if (prev_ms && m->beat() > beat) {
2742                                 break;
2743                         }
2744                         prev_ms = m;
2745                 }
2746
2747         }
2748         return *prev_ms;
2749 }
2750
2751 XMLNode&
2752 TempoMap::get_state ()
2753 {
2754         Metrics::const_iterator i;
2755         XMLNode *root = new XMLNode ("TempoMap");
2756
2757         {
2758                 Glib::Threads::RWLock::ReaderLock lm (lock);
2759                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2760                         root->add_child_nocopy ((*i)->get_state());
2761                 }
2762         }
2763
2764         return *root;
2765 }
2766
2767 int
2768 TempoMap::set_state (const XMLNode& node, int /*version*/)
2769 {
2770         {
2771                 Glib::Threads::RWLock::WriterLock lm (lock);
2772
2773                 XMLNodeList nlist;
2774                 XMLNodeConstIterator niter;
2775                 Metrics old_metrics (_metrics);
2776                 _metrics.clear();
2777
2778                 nlist = node.children();
2779
2780                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2781                         XMLNode* child = *niter;
2782
2783                         if (child->name() == TempoSection::xml_state_node_name) {
2784
2785                                 try {
2786                                         TempoSection* ts = new TempoSection (*child);
2787                                         _metrics.push_back (ts);
2788                                 }
2789
2790                                 catch (failed_constructor& err){
2791                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2792                                         _metrics = old_metrics;
2793                                         break;
2794                                 }
2795
2796                         } else if (child->name() == MeterSection::xml_state_node_name) {
2797
2798                                 try {
2799                                         MeterSection* ms = new MeterSection (*child);
2800                                         _metrics.push_back (ms);
2801                                 }
2802
2803                                 catch (failed_constructor& err) {
2804                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2805                                         _metrics = old_metrics;
2806                                         break;
2807                                 }
2808                         }
2809                 }
2810
2811                 if (niter == nlist.end()) {
2812                         MetricSectionSorter cmp;
2813                         _metrics.sort (cmp);
2814                 }
2815                 /* check for legacy sessions where bbt was the base musical unit for tempo */
2816                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2817                         MeterSection* m;
2818                         TempoSection* t;
2819                         MeterSection* prev_ms = 0;
2820                         TempoSection* prev_ts = 0;
2821                         if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2822                                 if (prev_ms && prev_ms->pulse() < 0.0) {
2823                                         /*XX we cannot possibly make this work??. */
2824                                         pair<double, BBT_Time> start = make_pair (((prev_ms->bbt().bars - 1) * prev_ms->note_divisor()) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat), prev_ms->bbt());
2825                                         prev_ms->set_beat (start);
2826                                         const double start_pulse = ((prev_ms->bbt().bars - 1) * prev_ms->note_divisor()) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat);
2827                                         prev_ms->set_pulse (start_pulse);
2828                                 }
2829                                 prev_ms = m;
2830                         } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2831                                 if (!t->active()) {
2832                                         continue;
2833                                 }
2834                                 if (prev_ts && prev_ts->pulse() < 0.0) {
2835                                         double const start = ((prev_ts->legacy_bbt().bars - 1) * prev_ms->note_divisor()) + (prev_ts->legacy_bbt().beats - 1) + (prev_ts->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
2836                                         prev_ts->set_pulse (start);
2837                                 }
2838                                 prev_ts = t;
2839                         }
2840                 }
2841                 /* check for multiple tempo/meters at the same location, which
2842                    ardour2 somehow allowed.
2843                 */
2844
2845                 Metrics::iterator prev = _metrics.end();
2846                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2847                         if (prev != _metrics.end()) {
2848                                 MeterSection* ms;
2849                                 MeterSection* prev_ms;
2850                                 TempoSection* ts;
2851                                 TempoSection* prev_ts;
2852                                 if ((prev_ms = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
2853                                         if (prev_ms->pulse() == ms->pulse()) {
2854                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_ms->pulse()) << endmsg;
2855                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_ms->pulse()) << endmsg;
2856                                                 return -1;
2857                                         }
2858                                 } else if ((prev_ts = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
2859                                         if (prev_ts->pulse() == ts->pulse()) {
2860                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->pulse()) << endmsg;
2861                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->pulse()) << endmsg;
2862                                                 return -1;
2863                                         }
2864                                 }
2865                         }
2866                         prev = i;
2867                 }
2868
2869                 recompute_map (_metrics);
2870         }
2871
2872         PropertyChanged (PropertyChange ());
2873
2874         return 0;
2875 }
2876
2877 void
2878 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
2879 {
2880         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2881         const MeterSection* m;
2882         const TempoSection* t;
2883         const TempoSection* prev_ts = 0;
2884
2885         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2886
2887                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2888                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
2889                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
2890                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
2891                         if (prev_ts) {
2892                                 o << "previous     : " << prev_ts->beats_per_minute() << " | " << prev_ts->pulse() << " | " << prev_ts->frame() << std::endl;
2893                                 o << "calculated   : " << prev_ts->tempo_at_pulse (t->pulse()) *  prev_ts->note_type() << " | " << prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) <<  " | " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
2894                         }
2895                         prev_ts = t;
2896                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2897                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
2898                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
2899                 }
2900         }
2901         o << "------" << std::endl;
2902 }
2903
2904 int
2905 TempoMap::n_tempos() const
2906 {
2907         Glib::Threads::RWLock::ReaderLock lm (lock);
2908         int cnt = 0;
2909
2910         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2911                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
2912                         cnt++;
2913                 }
2914         }
2915
2916         return cnt;
2917 }
2918
2919 int
2920 TempoMap::n_meters() const
2921 {
2922         Glib::Threads::RWLock::ReaderLock lm (lock);
2923         int cnt = 0;
2924
2925         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2926                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
2927                         cnt++;
2928                 }
2929         }
2930
2931         return cnt;
2932 }
2933
2934 void
2935 TempoMap::insert_time (framepos_t where, framecnt_t amount)
2936 {
2937         {
2938                 Glib::Threads::RWLock::WriterLock lm (lock);
2939                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2940                         if ((*i)->frame() >= where && (*i)->movable ()) {
2941                                 (*i)->set_frame ((*i)->frame() + amount);
2942                         }
2943                 }
2944
2945                 /* now reset the BBT time of all metrics, based on their new
2946                  * audio time. This is the only place where we do this reverse
2947                  * timestamp.
2948                  */
2949
2950                 Metrics::iterator i;
2951                 const MeterSection* meter;
2952                 const TempoSection* tempo;
2953                 MeterSection *m;
2954                 TempoSection *t;
2955
2956                 meter = &first_meter ();
2957                 tempo = &first_tempo ();
2958
2959                 BBT_Time start;
2960                 BBT_Time end;
2961
2962                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
2963
2964                 bool first = true;
2965                 MetricSection* prev = 0;
2966
2967                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2968
2969                         BBT_Time bbt;
2970                         //TempoMetric metric (*meter, *tempo);
2971                         MeterSection* ms = const_cast<MeterSection*>(meter);
2972                         TempoSection* ts = const_cast<TempoSection*>(tempo);
2973                         if (prev) {
2974                                 if (ts){
2975                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
2976                                                 if (!t->active()) {
2977                                                         continue;
2978                                                 }
2979                                                 ts->set_pulse (t->pulse());
2980                                         }
2981                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
2982                                                 ts->set_pulse (m->pulse());
2983                                         }
2984                                         ts->set_frame (prev->frame());
2985
2986                                 }
2987                                 if (ms) {
2988                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
2989                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
2990                                                 ms->set_beat (start);
2991                                                 ms->set_pulse (m->pulse());
2992                                         }
2993                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
2994                                                 if (!t->active()) {
2995                                                         continue;
2996                                                 }
2997                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
2998                                                 pair<double, BBT_Time> start = make_pair (beat, beats_to_bbt_locked (_metrics, beat));
2999                                                 ms->set_beat (start);
3000                                                 ms->set_pulse (t->pulse());
3001                                         }
3002                                         ms->set_frame (prev->frame());
3003                                 }
3004
3005                         } else {
3006                                 // metric will be at frames=0 bbt=1|1|0 by default
3007                                 // which is correct for our purpose
3008                         }
3009
3010                         // cerr << bbt << endl;
3011
3012                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3013                                 if (!t->active()) {
3014                                         continue;
3015                                 }
3016                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3017                                 tempo = t;
3018                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3019                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3020                                 bbt_time (m->frame(), bbt);
3021
3022                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3023
3024                                 if (first) {
3025                                         first = false;
3026                                 } else {
3027
3028                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3029                                                 /* round up to next beat */
3030                                                 bbt.beats += 1;
3031                                         }
3032
3033                                         bbt.ticks = 0;
3034
3035                                         if (bbt.beats != 1) {
3036                                                 /* round up to next bar */
3037                                                 bbt.bars += 1;
3038                                                 bbt.beats = 1;
3039                                         }
3040                                 }
3041                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3042                                 m->set_beat (start);
3043                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3044                                 meter = m;
3045                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3046                         } else {
3047                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3048                                 abort(); /*NOTREACHED*/
3049                         }
3050
3051                         prev = (*i);
3052                 }
3053
3054                 recompute_map (_metrics);
3055         }
3056
3057
3058         PropertyChanged (PropertyChange ());
3059 }
3060 bool
3061 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3062 {
3063         bool moved = false;
3064
3065         std::list<MetricSection*> metric_kill_list;
3066
3067         TempoSection* last_tempo = NULL;
3068         MeterSection* last_meter = NULL;
3069         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3070         bool meter_after = false; // is there a meter marker likewise?
3071         {
3072                 Glib::Threads::RWLock::WriterLock lm (lock);
3073                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3074                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3075                                 metric_kill_list.push_back(*i);
3076                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3077                                 if (lt)
3078                                         last_tempo = lt;
3079                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3080                                 if (lm)
3081                                         last_meter = lm;
3082                         }
3083                         else if ((*i)->frame() >= where) {
3084                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3085                                 (*i)->set_frame ((*i)->frame() - amount);
3086                                 if ((*i)->frame() == where) {
3087                                         // marker was immediately after end of range
3088                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3089                                         meter_after = dynamic_cast<MeterSection*> (*i);
3090                                 }
3091                                 moved = true;
3092                         }
3093                 }
3094
3095                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3096                 if (last_tempo && !tempo_after) {
3097                         metric_kill_list.remove(last_tempo);
3098                         last_tempo->set_frame(where);
3099                         moved = true;
3100                 }
3101                 if (last_meter && !meter_after) {
3102                         metric_kill_list.remove(last_meter);
3103                         last_meter->set_frame(where);
3104                         moved = true;
3105                 }
3106
3107                 //remove all the remaining metrics
3108                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3109                         _metrics.remove(*i);
3110                         moved = true;
3111                 }
3112
3113                 if (moved) {
3114                         recompute_map (_metrics);
3115                 }
3116         }
3117         PropertyChanged (PropertyChange ());
3118         return moved;
3119 }
3120
3121 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3122  *  pos can be -ve, if required.
3123  */
3124 framepos_t
3125 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3126 {
3127         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
3128 }
3129
3130 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3131 framepos_t
3132 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3133 {
3134         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
3135 }
3136
3137 /** Add the BBT interval op to pos and return the result */
3138 framepos_t
3139 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3140 {
3141         Glib::Threads::RWLock::ReaderLock lm (lock);
3142
3143         BBT_Time pos_bbt = beats_to_bbt_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3144         pos_bbt.ticks += op.ticks;
3145         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3146                 ++pos_bbt.beats;
3147                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3148         }
3149         pos_bbt.beats += op.beats;
3150         /* the meter in effect will start on the bar */
3151         double divisions_per_bar = meter_section_at (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3152         while (pos_bbt.beats >= divisions_per_bar + 1) {
3153                 ++pos_bbt.bars;
3154                 divisions_per_bar = meter_section_at (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3155                 pos_bbt.beats -= divisions_per_bar;
3156         }
3157         pos_bbt.bars += op.bars;
3158
3159         return frame_time_locked (_metrics, pos_bbt);
3160 }
3161
3162 /** Count the number of beats that are equivalent to distance when going forward,
3163     starting at pos.
3164 */
3165 Evoral::Beats
3166 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3167 {
3168         return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
3169 }
3170
3171 struct bbtcmp {
3172     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3173             return a < b;
3174     }
3175 };
3176
3177 std::ostream&
3178 operator<< (std::ostream& o, const Meter& m) {
3179         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3180 }
3181
3182 std::ostream&
3183 operator<< (std::ostream& o, const Tempo& t) {
3184         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3185 }
3186
3187 std::ostream&
3188 operator<< (std::ostream& o, const MetricSection& section) {
3189
3190         o << "MetricSection @ " << section.frame() << ' ';
3191
3192         const TempoSection* ts;
3193         const MeterSection* ms;
3194
3195         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3196                 o << *((const Tempo*) ts);
3197         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3198                 o << *((const Meter*) ms);
3199         }
3200
3201         return o;
3202 }