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