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