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