Make TempoMap::bbt_at_frame() more efficient.
[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, 0, MusicTime)
77         , Tempo (TempoMap::default_tempo())
78         , _c_func (0.0)
79         , _active (true)
80         , _locked_to_meter (false)
81 {
82         XMLProperty const * prop;
83         LocaleGuard lg;
84         BBT_Time bbt;
85         double pulse;
86         uint32_t frame;
87
88         _legacy_bbt = BBT_Time (0, 0, 0);
89
90         if ((prop = node.property ("start")) != 0) {
91                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
92                             &bbt.bars,
93                             &bbt.beats,
94                             &bbt.ticks) == 3) {
95                         /* legacy session - start used to be in bbt*/
96                         _legacy_bbt = bbt;
97                         pulse = -1.0;
98                         info << _("Legacy session detected. TempoSection XML node will be altered.") << endmsg;
99                 }
100         }
101
102         if ((prop = node.property ("pulse")) != 0) {
103                 if (sscanf (prop->value().c_str(), "%lf", &pulse) != 1) {
104                         error << _("TempoSection XML node has an illegal \"pulse\" value") << endmsg;
105                 }
106         }
107
108         set_pulse (pulse);
109
110         if ((prop = node.property ("frame")) != 0) {
111                 if (sscanf (prop->value().c_str(), "%" PRIu32, &frame) != 1) {
112                         error << _("TempoSection XML node has an illegal \"frame\" value") << endmsg;
113                 } else {
114                         set_frame (frame);
115                 }
116         }
117
118         if ((prop = node.property ("beats-per-minute")) == 0) {
119                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
120                 throw failed_constructor();
121         }
122
123         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
124                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
125                 throw failed_constructor();
126         }
127
128         if ((prop = node.property ("note-type")) == 0) {
129                 /* older session, make note type be quarter by default */
130                 _note_type = 4.0;
131         } else {
132                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
133                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
134                         throw failed_constructor();
135                 }
136         }
137
138         if ((prop = node.property ("movable")) == 0) {
139                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
140                 throw failed_constructor();
141         }
142
143         set_movable (string_is_affirmative (prop->value()));
144
145         if ((prop = node.property ("active")) == 0) {
146                 warning << _("TempoSection XML node has no \"active\" property") << endmsg;
147                 set_active(true);
148         } else {
149                 set_active (string_is_affirmative (prop->value()));
150         }
151
152         if ((prop = node.property ("tempo-type")) == 0) {
153                 _type = Constant;
154         } else {
155                 _type = Type (string_2_enum (prop->value(), _type));
156         }
157
158         if ((prop = node.property ("lock-style")) == 0) {
159                 if (movable()) {
160                         set_position_lock_style (MusicTime);
161                 } else {
162                         set_position_lock_style (AudioTime);
163                 }
164         } else {
165                 set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
166         }
167
168         if ((prop = node.property ("locked-to-meter")) == 0) {
169                 set_locked_to_meter (false);
170         } else {
171                 set_locked_to_meter (string_is_affirmative (prop->value()));
172         }
173 }
174
175 XMLNode&
176 TempoSection::get_state() const
177 {
178         XMLNode *root = new XMLNode (xml_state_node_name);
179         char buf[256];
180         LocaleGuard lg;
181
182         snprintf (buf, sizeof (buf), "%f", pulse());
183         root->add_property ("pulse", buf);
184         snprintf (buf, sizeof (buf), "%li", frame());
185         root->add_property ("frame", buf);
186         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
187         root->add_property ("beats-per-minute", buf);
188         snprintf (buf, sizeof (buf), "%f", _note_type);
189         root->add_property ("note-type", buf);
190         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
191         root->add_property ("movable", buf);
192         snprintf (buf, sizeof (buf), "%s", active()?"yes":"no");
193         root->add_property ("active", buf);
194         root->add_property ("tempo-type", enum_2_string (_type));
195         root->add_property ("lock-style", enum_2_string (position_lock_style()));
196         root->add_property ("locked-to-meter", locked_to_meter()?"yes":"no");
197
198         return *root;
199 }
200
201 void
202 TempoSection::set_type (Type type)
203 {
204         _type = type;
205 }
206
207 /** returns the tempo in whole pulses per minute at the zero-based (relative to session) frame.
208 */
209 double
210 TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
211 {
212
213         if (_type == Constant || _c_func == 0.0) {
214                 return pulses_per_minute();
215         }
216
217         return pulse_tempo_at_time (frame_to_minute (f - frame(), frame_rate));
218 }
219
220 /** returns the zero-based frame (relative to session)
221    where the tempo in whole pulses per minute occurs in this section.
222    pulse p is only used for constant tempos.
223    note that the tempo map may have multiple such values.
224 */
225 framepos_t
226 TempoSection::frame_at_tempo (const double& ppm, const double& p, const framecnt_t& frame_rate) const
227 {
228         if (_type == Constant || _c_func == 0.0) {
229                 return ((p - pulse()) * frames_per_pulse (frame_rate))  + frame();
230         }
231
232         return minute_to_frame (time_at_pulse_tempo (ppm), frame_rate) + frame();
233 }
234 /** returns the tempo in pulses per minute at the zero-based (relative to session) beat.
235 */
236 double
237 TempoSection::tempo_at_pulse (const double& p) const
238 {
239
240         if (_type == Constant || _c_func == 0.0) {
241                 return pulses_per_minute();
242         }
243         double const ppm = pulse_tempo_at_pulse (p - pulse());
244         return ppm;
245 }
246
247 /** returns the zero-based beat (relative to session)
248    where the tempo in whole pulses per minute occurs given frame f. frame f is only used for constant tempos.
249    note that the session tempo map may have multiple beats at a given tempo.
250 */
251 double
252 TempoSection::pulse_at_tempo (const double& ppm, const framepos_t& f, const framecnt_t& frame_rate) const
253 {
254         if (_type == Constant || _c_func == 0.0) {
255                 double const pulses = ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
256                 return  pulses;
257         }
258         return pulse_at_pulse_tempo (ppm) + pulse();
259 }
260
261 /** returns the zero-based pulse (relative to session origin)
262    where the zero-based frame (relative to session)
263    lies.
264 */
265 double
266 TempoSection::pulse_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
267 {
268         if (_type == Constant || _c_func == 0.0) {
269                 return ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
270         }
271
272         return pulse_at_time (frame_to_minute (f - frame(), frame_rate)) + pulse();
273 }
274
275 /** returns the zero-based frame (relative to session start frame)
276    where the zero-based pulse (relative to session start)
277    falls.
278 */
279
280 framepos_t
281 TempoSection::frame_at_pulse (const double& p, const framecnt_t& frame_rate) const
282 {
283         if (_type == Constant || _c_func == 0.0) {
284                 return (framepos_t) floor ((p - pulse()) * frames_per_pulse (frame_rate)) + frame();
285         }
286
287         return minute_to_frame (time_at_pulse (p - pulse()), frame_rate) + frame();
288 }
289
290 /*
291 Ramp Overview
292
293       |                     *
294 Tempo |                   *
295 Tt----|-----------------*|
296 Ta----|--------------|*  |
297       |            * |   |
298       |         *    |   |
299       |     *        |   |
300 T0----|*             |   |
301   *   |              |   |
302       _______________|___|____
303       time           a   t (next tempo)
304       [        c         ] defines c
305
306 Duration in beats at time a is the integral of some Tempo function.
307 In our case, the Tempo function (Tempo at time t) is
308 T(t) = T0(e^(ct))
309
310 with function constant
311 c = log(Ta/T0)/a
312 so
313 a = log(Ta/T0)/c
314
315 The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
316 b(t) = T0(e^(ct) - 1) / c
317
318 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:
319 t(b) = log((c.b / T0) + 1) / c
320
321 The time t at which Tempo T occurs is a as above:
322 t(T) = log(T / T0) / c
323
324 The beat at which a Tempo T occurs is:
325 b(T) = (T - T0) / c
326
327 The Tempo at which beat b occurs is:
328 T(b) = b.c + T0
329
330 We define c for this tempo ramp by placing a new tempo section at some time t after this one.
331 Our problem is that we usually don't know t.
332 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.
333 Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
334 t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
335
336 By substituting our expanded t as a in the c function above, our problem is reduced to:
337 c = T0 (e^(log (Ta / T0)) - 1) / b
338
339 Of course the word 'beat' has been left loosely defined above.
340 In music, a beat is defined by the musical pulse (which comes from the tempo)
341 and the meter in use at a particular time (how many  pulse divisions there are in one bar).
342 It would be more accurate to substitute the work 'pulse' for 'beat' above.
343
344 Anyway ...
345
346 We can now store c for future time calculations.
347 If the following tempo section (the one that defines c in conjunction with this one)
348 is changed or moved, c is no longer valid.
349
350 The public methods are session-relative.
351
352 Most of this stuff is taken from this paper:
353
354 WHERE’S THE BEAT?
355 TOOLS FOR DYNAMIC TEMPO CALCULATIONS
356 Jan C. Schacher
357 Martin Neukom
358 Zurich University of Arts
359 Institute for Computer Music and Sound Technology
360
361 https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Tempopolyphony_ICMC07.pdf
362
363 */
364
365 /*
366   compute this ramp's function constant using the end tempo (in whole pulses per minute)
367   and duration (pulses into global start) of some later tempo section.
368 */
369 double
370 TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse, const framecnt_t& frame_rate)
371 {
372         double const log_tempo_ratio = log (end_bpm / pulses_per_minute());
373         return pulses_per_minute() *  (expm1 (log_tempo_ratio)) / (end_pulse - pulse());
374 }
375
376 /* compute the function constant from some later tempo section, given tempo (whole pulses/min.) and distance (in frames) from session origin */
377 double
378 TempoSection::compute_c_func_frame (const double& end_bpm, const framepos_t& end_frame, const framecnt_t& frame_rate) const
379 {
380         return c_func (end_bpm, frame_to_minute (end_frame - frame(), frame_rate));
381 }
382
383 framepos_t
384 TempoSection::minute_to_frame (const double& time, const framecnt_t& frame_rate) const
385 {
386         return (framepos_t) floor ((time * 60.0 * frame_rate) + 0.5);
387 }
388
389 double
390 TempoSection::frame_to_minute (const framepos_t& frame, const framecnt_t& frame_rate) const
391 {
392         return (frame / (double) frame_rate) / 60.0;
393 }
394
395 /* position function */
396 double
397 TempoSection::a_func (double end_ppm, double c_func) const
398 {
399         return log (end_ppm / pulses_per_minute()) /  c_func;
400 }
401
402 /*function constant*/
403 double
404 TempoSection::c_func (double end_ppm, double end_time) const
405 {
406         return log (end_ppm / pulses_per_minute()) /  end_time;
407 }
408
409 /* tempo in ppm at time in minutes */
410 double
411 TempoSection::pulse_tempo_at_time (const double& time) const
412 {
413         return exp (_c_func * time) * pulses_per_minute();
414 }
415
416 /* time in minutes at tempo in ppm */
417 double
418 TempoSection::time_at_pulse_tempo (const double& pulse_tempo) const
419 {
420         return log (pulse_tempo / pulses_per_minute()) / _c_func;
421 }
422
423 /* tick at tempo in ppm */
424 double
425 TempoSection::pulse_at_pulse_tempo (const double& pulse_tempo) const
426 {
427         return (pulse_tempo - pulses_per_minute()) / _c_func;
428 }
429
430 /* tempo in ppm at tick */
431 double
432 TempoSection::pulse_tempo_at_pulse (const double& pulse) const
433 {
434         return (pulse * _c_func) + pulses_per_minute();
435 }
436
437 /* pulse at time in minutes */
438 double
439 TempoSection::pulse_at_time (const double& time) const
440 {
441         return expm1 (_c_func * time) * (pulses_per_minute() / _c_func);
442 }
443
444 /* time in minutes at pulse */
445 double
446 TempoSection::time_at_pulse (const double& pulse) const
447 {
448         return log1p ((_c_func * pulse) / pulses_per_minute()) / _c_func;
449 }
450
451 /***********************************************************************/
452
453 const string MeterSection::xml_state_node_name = "Meter";
454
455 MeterSection::MeterSection (const XMLNode& node)
456         : MetricSection (0.0, 0, MusicTime), Meter (TempoMap::default_meter())
457 {
458         XMLProperty const * prop;
459         LocaleGuard lg;
460         BBT_Time bbt;
461         double pulse = 0.0;
462         double beat = 0.0;
463         framepos_t frame = 0;
464         pair<double, BBT_Time> start;
465
466         if ((prop = node.property ("start")) != 0) {
467                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
468                     &bbt.bars,
469                     &bbt.beats,
470                     &bbt.ticks) < 3) {
471                         error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
472                 } else {
473                         /* legacy session - start used to be in bbt*/
474                         info << _("Legacy session detected - MeterSection XML node will be altered.") << endmsg;
475                         pulse = -1.0;
476                 }
477         }
478
479         if ((prop = node.property ("pulse")) != 0) {
480                 if (sscanf (prop->value().c_str(), "%lf", &pulse) != 1) {
481                         error << _("MeterSection XML node has an illegal \"pulse\" value") << endmsg;
482                 }
483         }
484         set_pulse (pulse);
485
486         if ((prop = node.property ("beat")) != 0) {
487                 if (sscanf (prop->value().c_str(), "%lf", &beat) != 1) {
488                         error << _("MeterSection XML node has an illegal \"beat\" value") << endmsg;
489                 }
490         }
491
492         start.first = beat;
493
494         if ((prop = node.property ("bbt")) == 0) {
495                 warning << _("MeterSection XML node has no \"bbt\" property") << endmsg;
496         } else if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
497                     &bbt.bars,
498                     &bbt.beats,
499                     &bbt.ticks) < 3) {
500                 error << _("MeterSection XML node has an illegal \"bbt\" value") << endmsg;
501                 throw failed_constructor();
502         }
503
504         start.second = bbt;
505         set_beat (start);
506
507         if ((prop = node.property ("frame")) != 0) {
508                 if (sscanf (prop->value().c_str(), "%li", &frame) != 1) {
509                         error << _("MeterSection XML node has an illegal \"frame\" value") << endmsg;
510                 } else {
511                         set_frame (frame);
512                 }
513         }
514
515         /* beats-per-bar is old; divisions-per-bar is new */
516
517         if ((prop = node.property ("divisions-per-bar")) == 0) {
518                 if ((prop = node.property ("beats-per-bar")) == 0) {
519                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
520                         throw failed_constructor();
521                 }
522         }
523         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
524                 error << _("MeterSection XML node has an illegal \"divisions-per-bar\" value") << endmsg;
525                 throw failed_constructor();
526         }
527
528         if ((prop = node.property ("note-type")) == 0) {
529                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
530                 throw failed_constructor();
531         }
532         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
533                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
534                 throw failed_constructor();
535         }
536
537         if ((prop = node.property ("movable")) == 0) {
538                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
539                 throw failed_constructor();
540         }
541
542         set_movable (string_is_affirmative (prop->value()));
543
544         if ((prop = node.property ("lock-style")) == 0) {
545                 warning << _("MeterSection XML node has no \"lock-style\" property") << endmsg;
546                 if (movable()) {
547                         set_position_lock_style (MusicTime);
548                 } else {
549                         set_position_lock_style (AudioTime);
550                 }
551         } else {
552                 set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
553         }
554 }
555
556 XMLNode&
557 MeterSection::get_state() const
558 {
559         XMLNode *root = new XMLNode (xml_state_node_name);
560         char buf[256];
561         LocaleGuard lg;
562
563         snprintf (buf, sizeof (buf), "%lf", pulse());
564         root->add_property ("pulse", buf);
565         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
566                   bbt().bars,
567                   bbt().beats,
568                   bbt().ticks);
569         root->add_property ("bbt", buf);
570         snprintf (buf, sizeof (buf), "%lf", beat());
571         root->add_property ("beat", buf);
572         snprintf (buf, sizeof (buf), "%f", _note_type);
573         root->add_property ("note-type", buf);
574         snprintf (buf, sizeof (buf), "%li", frame());
575         root->add_property ("frame", buf);
576         root->add_property ("lock-style", enum_2_string (position_lock_style()));
577         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
578         root->add_property ("divisions-per-bar", buf);
579         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
580         root->add_property ("movable", buf);
581
582         return *root;
583 }
584
585 /***********************************************************************/
586 /*
587   Tempo Map Overview
588
589   The Shaggs - Things I Wonder
590   https://www.youtube.com/watch?v=9wQK6zMJOoQ
591
592   Tempo is the rate of the musical pulse.
593   Meters divide the pulses into measures and beats.
594
595   TempoSections - provide pulses in the form of beats_per_minute() and note_type() where note_type is the division of a whole pulse,
596   and beats_per_minute is the number of note_types in one minute (unlike what its name suggests).
597   Note that Tempo::beats_per_minute() has nothing to do with musical beats. It has been left that way because
598   a shorter one hasn't been found yet (pulse_divisions_per_minute()?).
599
600   MeterSecions - divide pulses into measures (via divisions_per_bar) and beats (via note_divisor).
601
602   Both tempos and meters have a pulse position and a frame position.
603   Meters also have a beat position, which is always 0.0 for the first meter.
604   TempoSections and MeterSections may be locked to either audio or music (position lock style).
605   The lock style determines the 'true' position of the section wich is used to calculate the other postion parameters of the section.
606
607   The first tempo and first meter are special. they must move together, and must be locked to audio.
608   Audio locked tempos which lie before the first meter are made inactive.
609   They will be re-activated if the first meter is again placed before them.
610
611   With tepo sections potentially being ramped, meters provide a way of mapping beats to whole pulses without
612   referring to the tempo function(s) involved as the distance in whole pulses between a meter and a subsequent beat is
613   sb->beat() - meter->beat() / meter->note_divisor().
614   Because every meter falls on a known pulse, (derived from its bar), the rest is easy as the duration in pulses between
615   two meters is of course
616   (meater_b->bar - meter_a->bar) * meter_a->divisions_per_bar / meter_a->note_divisor.
617
618   Below, beat calculations are based on meter sections and all pulse and tempo calculations are based on tempo sections.
619   Beat to frame conversion of course requires the use of meter and tempo.
620
621   Remembering that ramped tempo sections interact, it is important to avoid referring to any other tempos when moving tempo sections,
622   Here, beats (meters) are used to determine the new pulse (see predict_tempo_position())
623
624   Recomputing the map is the process where the 'missing' position
625   (tempo pulse or meter pulse & beat in the case of AudioTime, frame for MusicTime) is calculated.
626   We construct the tempo map by first using the frame or pulse position (depending on position lock style) of each tempo.
627   We then use this tempo map (really just the tempos) to find the pulse or frame position of each meter (again depending on lock style).
628
629   Having done this, we can now find any musical duration by selecting the tempo and meter covering the position (or tempo) in question
630   and querying its appropriate meter/tempo.
631
632   It is important to keep the _metrics in an order that makes sense.
633   Because ramped MusicTime and AudioTime tempos can interact with each other,
634   reordering is frequent. Care must be taken to keep _metrics in a solved state.
635   Solved means ordered by frame or pulse with frame-accurate precision (see check_solved()).
636
637   Music and Audio
638
639   Music and audio-locked objects may seem interchangeable on the surface, but when translating
640   between audio samples and beats, keep in mind that a sample is only a quantised approximation
641   of the actual time (in minutes) of a beat.
642   Thus if a gui user points to the frame occupying the start of a music-locked object on 1|3|0, it does not
643   mean that this frame is the actual location in time of 1|3|0.
644
645   You cannot use a frame measurement to determine beat distance except under special circumstances
646   (e.g. where the user has requested that a beat lie on a SMPTE frame or if the tempo is known to be constant over the duration).
647
648   This means is that a user operating on a musical grid must supply the desired beat position and/or current beat quantization in order for the
649   sample space the user is operating at to be translated correctly to the object.
650
651   The current approach is to interpret the supplied frame using the grid division the user has currently selected.
652   If the user has no musical grid set, they are actually operating in sample space (even SMPTE frames are rounded to audio frame), so
653   the supplied audio frame is interpreted as the desired musical location (beat_at_frame()).
654
655   tldr: Beat, being a function of time, has nothing to do with sample rate, but time quantization can get in the way of precision.
656
657   When frame_at_beat() is called, the position calculation is performed in pulses and minutes.
658   The result is rounded to audio frames.
659   When beat_at_frame() is called, the frame is converted to minutes, with no rounding performed on the result.
660
661   So :
662   frame_at_beat (beat_at_frame (frame)) == frame
663   but :
664   beat_at_frame (frame_at_beat (beat)) != beat due to the time quantization of frame_at_beat().
665
666   Doing the second one will result in a beat distance error of up to 0.5 audio samples.
667   So instead work in pulses and/or beats and only use beat position to caclulate frame position (e.g. after tempo change).
668   For audio-locked objects, use frame position to calculate beat position.
669
670   The above pointless example would then do:
671   beat_at_pulse (pulse_at_beat (beat)) to avoid rounding.
672
673 */
674 struct MetricSectionSorter {
675     bool operator() (const MetricSection* a, const MetricSection* b) {
676             return a->pulse() < b->pulse();
677     }
678 };
679
680 struct MetricSectionFrameSorter {
681     bool operator() (const MetricSection* a, const MetricSection* b) {
682             return a->frame() < b->frame();
683     }
684 };
685
686 TempoMap::TempoMap (framecnt_t fr)
687 {
688         _frame_rate = fr;
689         BBT_Time start (1, 1, 0);
690
691         TempoSection *t = new TempoSection (0.0, 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime);
692         MeterSection *m = new MeterSection (0.0, 0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime);
693
694         t->set_movable (false);
695         m->set_movable (false);
696
697         /* note: frame time is correct (zero) for both of these */
698
699         _metrics.push_back (t);
700         _metrics.push_back (m);
701
702 }
703
704 TempoMap::~TempoMap ()
705 {
706         Metrics::const_iterator d = _metrics.begin();
707         while (d != _metrics.end()) {
708                 delete (*d);
709                 ++d;
710         }
711         _metrics.clear();
712 }
713
714 void
715 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
716 {
717         bool removed = false;
718
719         {
720                 Glib::Threads::RWLock::WriterLock lm (lock);
721                 if ((removed = remove_tempo_locked (tempo))) {
722                         if (complete_operation) {
723                                 recompute_map (_metrics);
724                         }
725                 }
726         }
727
728         if (removed && complete_operation) {
729                 PropertyChanged (PropertyChange ());
730         }
731 }
732
733 bool
734 TempoMap::remove_tempo_locked (const TempoSection& tempo)
735 {
736         Metrics::iterator i;
737
738         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
739                 if (dynamic_cast<TempoSection*> (*i) != 0) {
740                         if (tempo.frame() == (*i)->frame()) {
741                                 if ((*i)->movable()) {
742                                         delete (*i);
743                                         _metrics.erase (i);
744                                         return true;
745                                 }
746                         }
747                 }
748         }
749
750         return false;
751 }
752
753 void
754 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
755 {
756         bool removed = false;
757
758         {
759                 Glib::Threads::RWLock::WriterLock lm (lock);
760                 if ((removed = remove_meter_locked (tempo))) {
761                         if (complete_operation) {
762                                 recompute_map (_metrics);
763                         }
764                 }
765         }
766
767         if (removed && complete_operation) {
768                 PropertyChanged (PropertyChange ());
769         }
770 }
771
772 bool
773 TempoMap::remove_meter_locked (const MeterSection& meter)
774 {
775         Metrics::iterator i;
776
777         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
778                 TempoSection* t = 0;
779                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
780                         if (meter.frame() == (*i)->frame()) {
781                                 if (t->locked_to_meter()) {
782                                         delete (*i);
783                                         _metrics.erase (i);
784                                         break;
785                                 }
786                         }
787                 }
788         }
789
790         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
791                 if (dynamic_cast<MeterSection*> (*i) != 0) {
792                         if (meter.frame() == (*i)->frame()) {
793                                 if ((*i)->movable()) {
794                                         delete (*i);
795                                         _metrics.erase (i);
796                                         return true;
797                                 }
798                         }
799                 }
800         }
801
802         return false;
803 }
804
805 void
806 TempoMap::do_insert (MetricSection* section)
807 {
808         bool need_add = true;
809         /* we only allow new meters to be inserted on beat 1 of an existing
810          * measure.
811          */
812         MeterSection* m = 0;
813         if ((m = dynamic_cast<MeterSection*>(section)) != 0) {
814
815                 if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
816
817                         pair<double, BBT_Time> corrected = make_pair (m->beat(), m->bbt());
818                         corrected.second.beats = 1;
819                         corrected.second.ticks = 0;
820                         corrected.first = beat_at_bbt_locked (_metrics, corrected.second);
821                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
822                                                    m->bbt(), corrected.second) << endmsg;
823                         //m->set_pulse (corrected);
824                 }
825         }
826
827         /* Look for any existing MetricSection that is of the same type and
828            in the same bar as the new one, and remove it before adding
829            the new one. Note that this means that if we find a matching,
830            existing section, we can break out of the loop since we're
831            guaranteed that there is only one such match.
832         */
833
834         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
835
836                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
837                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
838                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
839                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
840
841                 if (tempo && insert_tempo) {
842
843                         /* Tempo sections */
844                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
845                         if ((ipm && tempo->pulse() == insert_tempo->pulse()) || (!ipm && tempo->frame() == insert_tempo->frame())) {
846
847                                 if (!tempo->movable()) {
848
849                                         /* can't (re)move this section, so overwrite
850                                          * its data content (but not its properties as
851                                          * a section).
852                                          */
853
854                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo));
855                                         (*i)->set_position_lock_style (AudioTime);
856                                         TempoSection* t;
857                                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
858                                                 t->set_type (insert_tempo->type());
859                                         }
860                                         need_add = false;
861                                 } else {
862                                         delete (*i);
863                                         _metrics.erase (i);
864                                 }
865                                 break;
866                         }
867
868                 } else if (meter && insert_meter) {
869
870                         /* Meter Sections */
871
872                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
873
874                         if ((ipm && meter->beat() == insert_meter->beat()) || (!ipm && meter->frame() == insert_meter->frame())) {
875
876                                 if (!meter->movable()) {
877
878                                         /* can't (re)move this section, so overwrite
879                                          * its data content (but not its properties as
880                                          * a section
881                                          */
882
883                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
884                                         (*i)->set_position_lock_style (AudioTime);
885                                         need_add = false;
886                                 } else {
887                                         delete (*i);
888                                         _metrics.erase (i);
889                                 }
890
891                                 break;
892                         }
893                 } else {
894                         /* non-matching types, so we don't care */
895                 }
896         }
897
898         /* Add the given MetricSection, if we didn't just reset an existing
899          * one above
900          */
901
902         if (need_add) {
903                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
904                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
905                 Metrics::iterator i;
906                 if (insert_meter) {
907                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
908                                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
909
910                                 if (meter) {
911                                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
912                                         if ((ipm && meter->beat() > insert_meter->beat()) || (!ipm && meter->frame() > insert_meter->frame())) {
913                                                 break;
914                                         }
915                                 }
916                         }
917                 } else if (insert_tempo) {
918                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
919                                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
920
921                                 if (tempo) {
922                                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
923                                         if ((ipm && tempo->pulse() > insert_tempo->pulse()) || (!ipm && tempo->frame() > insert_tempo->frame())) {
924                                                 break;
925                                         }
926                                 }
927                         }
928                 }
929
930                 _metrics.insert (i, section);
931                 //dump (_metrics, std::cout);
932         }
933 }
934
935 TempoSection*
936 TempoMap::add_tempo (const Tempo& tempo, const double& pulse, const framepos_t& frame, ARDOUR::TempoSection::Type type, PositionLockStyle pls)
937 {
938         TempoSection* ts = 0;
939         {
940                 Glib::Threads::RWLock::WriterLock lm (lock);
941                 ts = add_tempo_locked (tempo, pulse, frame, type, pls, true);
942         }
943
944
945         PropertyChanged (PropertyChange ());
946
947         return ts;
948 }
949
950 void
951 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, const framepos_t& frame, TempoSection::Type type, PositionLockStyle pls)
952 {
953         const bool locked_to_meter = ts.locked_to_meter();
954
955         {
956                 Glib::Threads::RWLock::WriterLock lm (lock);
957                 TempoSection& first (first_tempo());
958                 if (ts.frame() != first.frame()) {
959                         remove_tempo_locked (ts);
960                         add_tempo_locked (tempo, pulse, frame, type, pls, true, locked_to_meter);
961                 } else {
962                         first.set_type (type);
963                         first.set_pulse (0.0);
964                         first.set_frame (frame);
965                         first.set_position_lock_style (AudioTime);
966                         {
967                                 /* cannot move the first tempo section */
968                                 *static_cast<Tempo*>(&first) = tempo;
969                                 recompute_map (_metrics);
970                         }
971                 }
972         }
973
974         PropertyChanged (PropertyChange ());
975 }
976
977 TempoSection*
978 TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, framepos_t frame
979                             , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter)
980 {
981         TempoSection* t = new TempoSection (pulse, frame, tempo.beats_per_minute(), tempo.note_type(), type, pls);
982         t->set_locked_to_meter (locked_to_meter);
983
984         do_insert (t);
985
986         if (recompute) {
987                 if (pls == AudioTime) {
988                         solve_map_frame (_metrics, t, t->frame());
989                 } else {
990                         solve_map_pulse (_metrics, t, t->pulse());
991                 }
992                 recompute_meters (_metrics);
993         }
994
995         return t;
996 }
997
998 MeterSection*
999 TempoMap::add_meter (const Meter& meter, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
1000 {
1001         MeterSection* m = 0;
1002         {
1003                 Glib::Threads::RWLock::WriterLock lm (lock);
1004                 m = add_meter_locked (meter, beat, where, frame, pls, true);
1005         }
1006
1007
1008 #ifndef NDEBUG
1009         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
1010                 dump (_metrics, std::cerr);
1011         }
1012 #endif
1013
1014         PropertyChanged (PropertyChange ());
1015         return m;
1016 }
1017
1018 void
1019 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
1020 {
1021         {
1022                 Glib::Threads::RWLock::WriterLock lm (lock);
1023                 const double beat = beat_at_bbt_locked (_metrics, where);
1024
1025                 if (ms.movable()) {
1026                         remove_meter_locked (ms);
1027                         add_meter_locked (meter, beat, where, frame, pls, true);
1028                 } else {
1029                         MeterSection& first (first_meter());
1030                         TempoSection& first_t (first_tempo());
1031                         /* cannot move the first meter section */
1032                         *static_cast<Meter*>(&first) = meter;
1033                         first.set_position_lock_style (AudioTime);
1034                         first.set_pulse (0.0);
1035                         first.set_frame (frame);
1036                         pair<double, BBT_Time> beat = make_pair (0.0, BBT_Time (1, 1, 0));
1037                         first.set_beat (beat);
1038                         first_t.set_frame (first.frame());
1039                         first_t.set_pulse (0.0);
1040                         first_t.set_position_lock_style (AudioTime);
1041                         recompute_map (_metrics);
1042                 }
1043         }
1044
1045         PropertyChanged (PropertyChange ());
1046 }
1047
1048 MeterSection*
1049 TempoMap::add_meter_locked (const Meter& meter, double beat, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
1050 {
1051         const MeterSection& prev_m = meter_section_at_frame_locked  (_metrics, frame - 1);
1052         const double pulse = ((where.bars - prev_m.bbt().bars) * (prev_m.divisions_per_bar() / prev_m.note_divisor())) + prev_m.pulse();
1053
1054         if (pls == AudioTime) {
1055                 /* add meter-locked tempo */
1056                 add_tempo_locked (tempo_at_frame_locked (_metrics, frame), pulse,  frame, TempoSection::Ramp, AudioTime, true, true);
1057         }
1058
1059         MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
1060
1061         do_insert (new_meter);
1062
1063         if (recompute) {
1064
1065                 if (pls == AudioTime) {
1066                         solve_map_frame (_metrics, new_meter, frame);
1067                 } else {
1068                         solve_map_bbt (_metrics, new_meter, where);
1069                 }
1070         }
1071
1072         return new_meter;
1073 }
1074
1075 void
1076 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
1077 {
1078         Tempo newtempo (beats_per_minute, note_type);
1079         TempoSection* t;
1080
1081         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1082                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1083                         if (!t->active()) {
1084                                 continue;
1085                         }
1086                         {
1087                                 Glib::Threads::RWLock::WriterLock lm (lock);
1088                                 *((Tempo*) t) = newtempo;
1089                                 recompute_map (_metrics);
1090                         }
1091                         PropertyChanged (PropertyChange ());
1092                         break;
1093                 }
1094         }
1095 }
1096
1097 void
1098 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
1099 {
1100         Tempo newtempo (beats_per_minute, note_type);
1101
1102         TempoSection* prev;
1103         TempoSection* first;
1104         Metrics::iterator i;
1105
1106         /* find the TempoSection immediately preceding "where"
1107          */
1108
1109         for (first = 0, i = _metrics.begin(), prev = 0; i != _metrics.end(); ++i) {
1110
1111                 if ((*i)->frame() > where) {
1112                         break;
1113                 }
1114
1115                 TempoSection* t;
1116
1117                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1118                         if (!t->active()) {
1119                                 continue;
1120                         }
1121                         if (!first) {
1122                                 first = t;
1123                         }
1124                         prev = t;
1125                 }
1126         }
1127
1128         if (!prev) {
1129                 if (!first) {
1130                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
1131                         return;
1132                 }
1133
1134                 prev = first;
1135         }
1136
1137         /* reset */
1138
1139         {
1140                 Glib::Threads::RWLock::WriterLock lm (lock);
1141                 /* cannot move the first tempo section */
1142                 *((Tempo*)prev) = newtempo;
1143                 recompute_map (_metrics);
1144         }
1145
1146         PropertyChanged (PropertyChange ());
1147 }
1148
1149 const MeterSection&
1150 TempoMap::first_meter () const
1151 {
1152         const MeterSection *m = 0;
1153
1154         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1155                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
1156                         return *m;
1157                 }
1158         }
1159
1160         fatal << _("programming error: no meter section in tempo map!") << endmsg;
1161         abort(); /*NOTREACHED*/
1162         return *m;
1163 }
1164
1165 MeterSection&
1166 TempoMap::first_meter ()
1167 {
1168         MeterSection *m = 0;
1169
1170         /* CALLER MUST HOLD LOCK */
1171
1172         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1173                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1174                         return *m;
1175                 }
1176         }
1177
1178         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1179         abort(); /*NOTREACHED*/
1180         return *m;
1181 }
1182
1183 const TempoSection&
1184 TempoMap::first_tempo () const
1185 {
1186         const TempoSection *t = 0;
1187
1188         /* CALLER MUST HOLD LOCK */
1189
1190         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1191                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1192                         if (!t->active()) {
1193                                 continue;
1194                         }
1195                         if (!t->movable()) {
1196                                 return *t;
1197                         }
1198                 }
1199         }
1200
1201         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1202         abort(); /*NOTREACHED*/
1203         return *t;
1204 }
1205
1206 TempoSection&
1207 TempoMap::first_tempo ()
1208 {
1209         TempoSection *t = 0;
1210
1211         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1212                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1213                         if (!t->active()) {
1214                                 continue;
1215                         }
1216                         if (!t->movable()) {
1217                                 return *t;
1218                         }
1219                 }
1220         }
1221
1222         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1223         abort(); /*NOTREACHED*/
1224         return *t;
1225 }
1226 void
1227 TempoMap::recompute_tempos (Metrics& metrics)
1228 {
1229         TempoSection* prev_t = 0;
1230
1231         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1232                 TempoSection* t;
1233
1234                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1235                         if (!t->active()) {
1236                                 continue;
1237                         }
1238                         if (!t->movable()) {
1239                                 if (!prev_t) {
1240                                         t->set_pulse (0.0);
1241                                         prev_t = t;
1242                                         continue;
1243                                 }
1244                         }
1245                         if (prev_t) {
1246                                 if (t->position_lock_style() == AudioTime) {
1247                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1248                                         if (!t->locked_to_meter()) {
1249                                                 t->set_pulse (prev_t->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate));
1250                                         }
1251
1252                                 } else {
1253                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1254                                         t->set_frame (prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate));
1255
1256                                 }
1257                         }
1258                         prev_t = t;
1259                 }
1260         }
1261         prev_t->set_c_func (0.0);
1262 }
1263
1264 /* tempos must be positioned correctly.
1265    the current approach is to use a meter's bbt time as its base position unit.
1266    an audio-locked meter requires a recomputation of pulse and beat (but not bbt),
1267    while a music-locked meter requires recomputations of frame pulse and beat (but not bbt)
1268 */
1269 void
1270 TempoMap::recompute_meters (Metrics& metrics)
1271 {
1272         MeterSection* meter = 0;
1273         MeterSection* prev_m = 0;
1274
1275         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1276                 if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
1277                         if (meter->position_lock_style() == AudioTime) {
1278                                 double pulse = 0.0;
1279                                 pair<double, BBT_Time> b_bbt;
1280                                 TempoSection* meter_locked_tempo = 0;
1281                                 for (Metrics::const_iterator ii = metrics.begin(); ii != metrics.end(); ++ii) {
1282                                         TempoSection* t;
1283                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
1284                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
1285                                                         meter_locked_tempo = t;
1286                                                         break;
1287                                                 }
1288                                         }
1289                                 }
1290
1291                                 if (prev_m) {
1292                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1293                                         if (beats + prev_m->beat() != meter->beat()) {
1294                                                 /* reordering caused a bbt change */
1295                                                 b_bbt = make_pair (beats + prev_m->beat()
1296                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1297                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1298
1299                                         } else if (meter->movable()) {
1300                                                 b_bbt = make_pair (meter->beat(), meter->bbt());
1301                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1302                                         }
1303                                 } else {
1304                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
1305                                 }
1306                                 if (meter_locked_tempo) {
1307                                         meter_locked_tempo->set_pulse (pulse);
1308                                 }
1309                                 meter->set_beat (b_bbt);
1310                                 meter->set_pulse (pulse);
1311
1312                         } else {
1313                                 /* MusicTime */
1314                                 double pulse = 0.0;
1315                                 pair<double, BBT_Time> b_bbt;
1316                                 if (prev_m) {
1317                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1318                                         if (beats + prev_m->beat() != meter->beat()) {
1319                                                 /* reordering caused a bbt change */
1320                                                 b_bbt = make_pair (beats + prev_m->beat()
1321                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1322                                         } else {
1323                                                 b_bbt = make_pair (beats + prev_m->beat(), meter->bbt());
1324                                         }
1325                                         pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
1326                                 } else {
1327                                         /* shouldn't happen - the first is audio-locked */
1328                                         pulse = pulse_at_beat_locked (metrics, meter->beat());
1329                                         b_bbt = make_pair (meter->beat(), meter->bbt());
1330                                 }
1331
1332                                 meter->set_beat (b_bbt);
1333                                 meter->set_pulse (pulse);
1334                                 meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1335                         }
1336
1337                         prev_m = meter;
1338                 }
1339         }
1340 }
1341
1342 void
1343 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1344 {
1345         /* CALLER MUST HOLD WRITE LOCK */
1346
1347         if (end < 0) {
1348
1349                 /* we will actually stop once we hit
1350                    the last metric.
1351                 */
1352                 end = max_framepos;
1353
1354         }
1355
1356         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1357
1358         if (end == 0) {
1359                 /* silly call from Session::process() during startup
1360                  */
1361                 return;
1362         }
1363
1364         recompute_tempos (metrics);
1365         recompute_meters (metrics);
1366 }
1367
1368 TempoMetric
1369 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1370 {
1371         Glib::Threads::RWLock::ReaderLock lm (lock);
1372         TempoMetric m (first_meter(), first_tempo());
1373
1374         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1375            at something, because we insert the default tempo and meter during
1376            TempoMap construction.
1377
1378            now see if we can find better candidates.
1379         */
1380
1381         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1382
1383                 if ((*i)->frame() > frame) {
1384                         break;
1385                 }
1386
1387                 m.set_metric(*i);
1388
1389                 if (last) {
1390                         *last = i;
1391                 }
1392         }
1393
1394         return m;
1395 }
1396
1397 /* XX meters only */
1398 TempoMetric
1399 TempoMap::metric_at (BBT_Time bbt) const
1400 {
1401         Glib::Threads::RWLock::ReaderLock lm (lock);
1402         TempoMetric m (first_meter(), first_tempo());
1403
1404         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1405            at something, because we insert the default tempo and meter during
1406            TempoMap construction.
1407
1408            now see if we can find better candidates.
1409         */
1410
1411         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1412                 MeterSection* mw;
1413                 if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
1414                         BBT_Time section_start (mw->bbt());
1415
1416                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1417                                 break;
1418                         }
1419
1420                         m.set_metric (*i);
1421                 }
1422         }
1423
1424         return m;
1425 }
1426
1427 double
1428 TempoMap::beat_at_frame (const framecnt_t& frame) const
1429 {
1430         Glib::Threads::RWLock::ReaderLock lm (lock);
1431         return beat_at_frame_locked (_metrics, frame);
1432 }
1433
1434 /* meter / tempo section based */
1435 double
1436 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1437 {
1438         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
1439         MeterSection* prev_m = 0;
1440         MeterSection* next_m = 0;
1441
1442         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1443                 MeterSection* m;
1444                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1445                         if (prev_m && m->frame() > frame) {
1446                                 next_m = m;
1447                                 break;
1448                         }
1449                         prev_m = m;
1450                 }
1451         }
1452         if (frame < prev_m->frame()) {
1453                 return 0.0;
1454         }
1455         const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
1456
1457         /* audio locked meters fake their beat */
1458         if (next_m && next_m->beat() < beat) {
1459                 return next_m->beat();
1460         }
1461
1462         return beat;
1463 }
1464
1465 framecnt_t
1466 TempoMap::frame_at_beat (const double& beat) const
1467 {
1468         Glib::Threads::RWLock::ReaderLock lm (lock);
1469         return frame_at_beat_locked (_metrics, beat);
1470 }
1471
1472 /* meter & tempo section based */
1473 framecnt_t
1474 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1475 {
1476         MeterSection* prev_m = 0;
1477         TempoSection* prev_t = 0;
1478
1479         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1480                 MeterSection* m;
1481                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1482                         if (prev_m && m->beat() > beat) {
1483                                 break;
1484                         }
1485                         prev_m = m;
1486                 }
1487         }
1488
1489         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1490                 TempoSection* t;
1491                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1492                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
1493                                 break;
1494                         }
1495                         prev_t = t;
1496                 }
1497
1498         }
1499
1500         return prev_t->frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
1501 }
1502
1503 Tempo
1504 TempoMap::tempo_at_frame (const framepos_t& frame) const
1505 {
1506         Glib::Threads::RWLock::ReaderLock lm (lock);
1507         return tempo_at_frame_locked (_metrics, frame);
1508 }
1509
1510 Tempo
1511 TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1512 {
1513         TempoSection* prev_t = 0;
1514
1515         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1516                 TempoSection* t;
1517                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1518                         if (!t->active()) {
1519                                 continue;
1520                         }
1521                         if ((prev_t) && t->frame() > frame) {
1522                                 /* t is the section past frame */
1523                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
1524                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
1525                                 return ret_tempo;
1526                         }
1527                         prev_t = t;
1528                 }
1529         }
1530
1531         const double ret = prev_t->beats_per_minute();
1532         const Tempo ret_tempo (ret, prev_t->note_type ());
1533
1534         return ret_tempo;
1535 }
1536
1537 /** returns the frame at which the supplied tempo occurs, or
1538  *  the frame of the last tempo section (search exhausted)
1539  *  only the position of the first occurence will be returned
1540  *  (extend me)
1541 */
1542 framepos_t
1543 TempoMap::frame_at_tempo (const Tempo& tempo) const
1544 {
1545         Glib::Threads::RWLock::ReaderLock lm (lock);
1546         return frame_at_tempo_locked (_metrics, tempo);
1547 }
1548
1549
1550 framepos_t
1551 TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1552 {
1553         TempoSection* prev_t = 0;
1554         const double tempo_ppm = tempo.beats_per_minute() / tempo.note_type();
1555
1556         Metrics::const_iterator i;
1557
1558         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
1559                 TempoSection* t;
1560                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1561
1562                         if (!t->active()) {
1563                                 continue;
1564                         }
1565
1566                         const double t_ppm = t->beats_per_minute() / t->note_type();
1567
1568                         if (t_ppm == tempo_ppm) {
1569                                 return t->frame();
1570                         }
1571
1572                         if (prev_t) {
1573                                 const double prev_t_ppm = prev_t->beats_per_minute() / prev_t->note_type();
1574
1575                                 if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) {
1576                                         const framepos_t ret_frame = prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate);
1577                                         return ret_frame;
1578                                 }
1579                         }
1580                         prev_t = t;
1581                 }
1582         }
1583
1584         return prev_t->frame();
1585 }
1586
1587 /** more precise than doing tempo_at_frame (frame_at_beat (b)),
1588  *  as there is no intermediate frame rounding.
1589  */
1590 Tempo
1591 TempoMap::tempo_at_beat (const double& beat) const
1592 {
1593         Glib::Threads::RWLock::ReaderLock lm (lock);
1594         const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
1595         const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
1596         const double note_type = prev_t->note_type();
1597
1598         return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()) * note_type, note_type);
1599 }
1600
1601 double
1602 TempoMap::pulse_at_beat (const double& beat) const
1603 {
1604         Glib::Threads::RWLock::ReaderLock lm (lock);
1605         return pulse_at_beat_locked (_metrics, beat);
1606 }
1607
1608 double
1609 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1610 {
1611         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1612
1613         return prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1614 }
1615
1616 double
1617 TempoMap::beat_at_pulse (const double& pulse) const
1618 {
1619         Glib::Threads::RWLock::ReaderLock lm (lock);
1620         return beat_at_pulse_locked (_metrics, pulse);
1621 }
1622
1623 double
1624 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1625 {
1626         MeterSection* prev_m = 0;
1627
1628         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1629                 MeterSection* m;
1630                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1631                         if (prev_m && m->pulse() > pulse) {
1632                                 if (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > m->beat()) {
1633                                         break;
1634                                 }
1635                         }
1636                         prev_m = m;
1637                 }
1638         }
1639
1640         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1641         return ret;
1642 }
1643
1644 double
1645 TempoMap::pulse_at_frame (const framecnt_t& frame) const
1646 {
1647         Glib::Threads::RWLock::ReaderLock lm (lock);
1648         return pulse_at_frame_locked (_metrics, frame);
1649 }
1650
1651 /* tempo section based */
1652 double
1653 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1654 {
1655         /* HOLD (at least) THE READER LOCK */
1656         TempoSection* prev_t = 0;
1657
1658         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1659                 TempoSection* t;
1660                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1661                         if (!t->active()) {
1662                                 continue;
1663                         }
1664                         if (prev_t && t->frame() > frame) {
1665                                 /*the previous ts is the one containing the frame */
1666                                 const double ret = prev_t->pulse_at_frame (frame, _frame_rate);
1667                                 return ret;
1668                         }
1669                         prev_t = t;
1670                 }
1671         }
1672
1673         /* treated as constant for this ts */
1674         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1675
1676         return pulses_in_section + prev_t->pulse();
1677 }
1678
1679 framecnt_t
1680 TempoMap::frame_at_pulse (const double& pulse) const
1681 {
1682         Glib::Threads::RWLock::ReaderLock lm (lock);
1683         return frame_at_pulse_locked (_metrics, pulse);
1684 }
1685
1686 /* tempo section based */
1687 framecnt_t
1688 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1689 {
1690         /* HOLD THE READER LOCK */
1691
1692         const TempoSection* prev_t = 0;
1693
1694         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1695                 TempoSection* t;
1696
1697                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1698                         if (!t->active()) {
1699                                 continue;
1700                         }
1701                         if (prev_t && t->pulse() > pulse) {
1702                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1703                         }
1704
1705                         prev_t = t;
1706                 }
1707         }
1708         /* must be treated as constant, irrespective of _type */
1709         double const pulses_in_section = pulse - prev_t->pulse();
1710         double const dtime = pulses_in_section * prev_t->frames_per_pulse (_frame_rate);
1711
1712         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_t->frame();
1713
1714         return ret;
1715 }
1716
1717 double
1718 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1719 {
1720         Glib::Threads::RWLock::ReaderLock lm (lock);
1721         return beat_at_bbt_locked (_metrics, bbt);
1722 }
1723
1724
1725 double
1726 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1727 {
1728         /* CALLER HOLDS READ LOCK */
1729
1730         MeterSection* prev_m = 0;
1731
1732         /* because audio-locked meters have 'fake' integral beats,
1733            there is no pulse offset here.
1734         */
1735         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1736                 MeterSection* m;
1737                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1738                         if (prev_m) {
1739                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1740                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1741                                         break;
1742                                 }
1743                         }
1744                         prev_m = m;
1745                 }
1746         }
1747
1748         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1749         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1750         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1751
1752         return ret;
1753 }
1754
1755 Timecode::BBT_Time
1756 TempoMap::bbt_at_beat (const double& beats)
1757 {
1758         Glib::Threads::RWLock::ReaderLock lm (lock);
1759         return bbt_at_beat_locked (_metrics, beats);
1760 }
1761
1762 Timecode::BBT_Time
1763 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1764 {
1765         /* CALLER HOLDS READ LOCK */
1766         MeterSection* prev_m = 0;
1767         const double beats = max (0.0, b);
1768
1769         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1770                 MeterSection* m = 0;
1771
1772                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1773                         if (prev_m) {
1774                                 if (m->beat() > beats) {
1775                                         /* this is the meter after the one our beat is on*/
1776                                         break;
1777                                 }
1778                         }
1779
1780                         prev_m = m;
1781                 }
1782         }
1783
1784         const double beats_in_ms = beats - prev_m->beat();
1785         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1786         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1787         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1788         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1789
1790         BBT_Time ret;
1791
1792         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1793         ret.beats = (uint32_t) floor (remaining_beats);
1794         ret.bars = total_bars;
1795
1796         /* 0 0 0 to 1 1 0 - based mapping*/
1797         ++ret.bars;
1798         ++ret.beats;
1799
1800         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1801                 ++ret.beats;
1802                 ret.ticks -= BBT_Time::ticks_per_beat;
1803         }
1804
1805         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1806                 ++ret.bars;
1807                 ret.beats = 1;
1808         }
1809
1810         return ret;
1811 }
1812
1813 double
1814 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1815 {
1816         Glib::Threads::RWLock::ReaderLock lm (lock);
1817
1818         return pulse_at_bbt_locked (_metrics, bbt);
1819 }
1820
1821 double
1822 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1823 {
1824         /* CALLER HOLDS READ LOCK */
1825
1826         MeterSection* prev_m = 0;
1827
1828         /* because audio-locked meters have 'fake' integral beats,
1829            there is no pulse offset here.
1830         */
1831         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1832                 MeterSection* m;
1833                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1834                         if (prev_m) {
1835                                 if (m->bbt().bars > bbt.bars) {
1836                                         break;
1837                                 }
1838                         }
1839                         prev_m = m;
1840                 }
1841         }
1842
1843         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1844         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1845         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1846
1847         return ret;
1848 }
1849
1850 Timecode::BBT_Time
1851 TempoMap::bbt_at_pulse (const double& pulse)
1852 {
1853         Glib::Threads::RWLock::ReaderLock lm (lock);
1854
1855         return bbt_at_pulse_locked (_metrics, pulse);
1856 }
1857
1858 Timecode::BBT_Time
1859 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1860 {
1861         MeterSection* prev_m = 0;
1862
1863         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1864                 MeterSection* m = 0;
1865
1866                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1867
1868                         if (prev_m) {
1869                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1870                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1871                                         /* this is the meter after the one our beat is on*/
1872                                         break;
1873                                 }
1874                         }
1875
1876                         prev_m = m;
1877                 }
1878         }
1879
1880         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1881         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1882         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1883         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1884         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1885
1886         BBT_Time ret;
1887
1888         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1889         ret.beats = (uint32_t) floor (remaining_beats);
1890         ret.bars = total_bars;
1891
1892         /* 0 0 0 to 1 1 0 mapping*/
1893         ++ret.bars;
1894         ++ret.beats;
1895
1896         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1897                 ++ret.beats;
1898                 ret.ticks -= BBT_Time::ticks_per_beat;
1899         }
1900
1901         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1902                 ++ret.bars;
1903                 ret.beats = 1;
1904         }
1905
1906         return ret;
1907 }
1908
1909 BBT_Time
1910 TempoMap::bbt_at_frame (framepos_t frame)
1911 {
1912         if (frame < 0) {
1913                 BBT_Time bbt;
1914                 bbt.bars = 1;
1915                 bbt.beats = 1;
1916                 bbt.ticks = 0;
1917                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1918                 return bbt;
1919         }
1920         Glib::Threads::RWLock::ReaderLock lm (lock);
1921
1922         return bbt_at_frame_locked (_metrics, frame);
1923 }
1924
1925 BBT_Time
1926 TempoMap::bbt_at_frame_rt (framepos_t frame)
1927 {
1928         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1929
1930         if (!lm.locked()) {
1931                 throw std::logic_error ("TempoMap::bbt_time_rt() could not lock tempo map");
1932         }
1933
1934         return bbt_at_frame_locked (_metrics, frame);
1935 }
1936
1937 Timecode::BBT_Time
1938 TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1939 {
1940         if (frame < 0) {
1941                 BBT_Time bbt;
1942                 bbt.bars = 1;
1943                 bbt.beats = 1;
1944                 bbt.ticks = 0;
1945                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1946                 return bbt;
1947         }
1948
1949         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
1950         MeterSection* prev_m = 0;
1951         MeterSection* next_m = 0;
1952
1953         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1954                 MeterSection* m;
1955                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1956                         if (prev_m && m->frame() > frame) {
1957                                 next_m = m;
1958                                 break;
1959                         }
1960                         prev_m = m;
1961                 }
1962         }
1963
1964         double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
1965
1966         /* handle frame before first meter */
1967         if (frame < prev_m->frame()) {
1968                 beat = 0.0;
1969         }
1970         /* audio locked meters fake their beat */
1971         if (next_m && next_m->beat() < beat) {
1972                 beat = next_m->beat();
1973         }
1974
1975         beat = max (0.0, beat);
1976
1977         const double beats_in_ms = beat - prev_m->beat();
1978         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1979         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1980         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1981         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1982
1983         BBT_Time ret;
1984
1985         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1986         ret.beats = (uint32_t) floor (remaining_beats);
1987         ret.bars = total_bars;
1988
1989         /* 0 0 0 to 1 1 0 - based mapping*/
1990         ++ret.bars;
1991         ++ret.beats;
1992
1993         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1994                 ++ret.beats;
1995                 ret.ticks -= BBT_Time::ticks_per_beat;
1996         }
1997
1998         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1999                 ++ret.bars;
2000                 ret.beats = 1;
2001         }
2002
2003         return ret;
2004 }
2005
2006 framepos_t
2007 TempoMap::frame_at_bbt (const BBT_Time& bbt)
2008 {
2009         if (bbt.bars < 1) {
2010                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
2011                 return 0;
2012         }
2013
2014         if (bbt.beats < 1) {
2015                 throw std::logic_error ("beats are counted from one");
2016         }
2017         Glib::Threads::RWLock::ReaderLock lm (lock);
2018
2019         return frame_at_bbt_locked (_metrics, bbt);
2020 }
2021
2022 /* meter & tempo section based */
2023 framepos_t
2024 TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
2025 {
2026         /* HOLD THE READER LOCK */
2027
2028         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
2029         return ret;
2030 }
2031
2032 bool
2033 TempoMap::check_solved (const Metrics& metrics) const
2034 {
2035         TempoSection* prev_t = 0;
2036         MeterSection* prev_m = 0;
2037
2038         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2039                 TempoSection* t;
2040                 MeterSection* m;
2041                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2042                         if (!t->active()) {
2043                                 continue;
2044                         }
2045                         if (prev_t) {
2046                                 /* check ordering */
2047                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
2048                                         return false;
2049                                 }
2050
2051                                 /* precision check ensures tempo and frames align.*/
2052                                 if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
2053                                         if (!t->locked_to_meter()) {
2054                                                 return false;
2055                                         }
2056                                 }
2057
2058                                 /* gradient limit - who knows what it should be?
2059                                    things are also ok (if a little chaotic) without this
2060                                 */
2061                                 if (fabs (prev_t->c_func()) > 1000.0) {
2062                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
2063                                         return false;
2064                                 }
2065                         }
2066                         prev_t = t;
2067                 }
2068
2069                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2070                         if (prev_m && m->position_lock_style() == AudioTime) {
2071                                 TempoSection* t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (metrics, m->frame() - 1));
2072                                 const double nascent_m_pulse = ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
2073                                 const framepos_t nascent_m_frame = t->frame_at_pulse (nascent_m_pulse, _frame_rate);
2074
2075                                 if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
2076                                         return false;
2077                                 }
2078                         }
2079
2080                         prev_m = m;
2081                 }
2082
2083         }
2084
2085         return true;
2086 }
2087
2088 bool
2089 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
2090 {
2091         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2092                 TempoSection* t;
2093                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2094                         if (!t->movable()) {
2095                                 t->set_active (true);
2096                                 continue;
2097                         }
2098                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
2099                                 t->set_active (false);
2100                                 t->set_pulse (0.0);
2101                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
2102                                 t->set_active (true);
2103                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
2104                                 return false;
2105                         }
2106                 }
2107         }
2108         return true;
2109 }
2110
2111 bool
2112 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
2113 {
2114         TempoSection* prev_t = 0;
2115         TempoSection* section_prev = 0;
2116         framepos_t first_m_frame = 0;
2117
2118         /* can't move a tempo before the first meter */
2119         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2120                 MeterSection* m;
2121                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2122                         if (!m->movable()) {
2123                                 first_m_frame = m->frame();
2124                                 break;
2125                         }
2126                 }
2127         }
2128         if (section->movable() && frame <= first_m_frame) {
2129                 return false;
2130         }
2131
2132         section->set_active (true);
2133         section->set_frame (frame);
2134
2135         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2136                 TempoSection* t;
2137                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2138
2139                         if (!t->active()) {
2140                                 continue;
2141                         }
2142                         if (prev_t) {
2143                                 if (t == section) {
2144                                         section_prev = prev_t;
2145                                         if (t->locked_to_meter()) {
2146                                                 prev_t = t;
2147                                         }
2148                                         continue;
2149                                 }
2150                                 if (t->position_lock_style() == MusicTime) {
2151                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2152                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2153                                 } else {
2154                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2155                                         if (!t->locked_to_meter()) {
2156                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2157                                         }
2158                                 }
2159                         }
2160                         prev_t = t;
2161                 }
2162         }
2163
2164         if (section_prev) {
2165                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
2166                 if (!section->locked_to_meter()) {
2167                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2168                 }
2169         }
2170
2171 #if (0)
2172         recompute_tempos (imaginary);
2173
2174         if (check_solved (imaginary)) {
2175                 return true;
2176         } else {
2177                 dunp (imaginary, std::cout);
2178         }
2179 #endif
2180
2181         MetricSectionFrameSorter fcmp;
2182         imaginary.sort (fcmp);
2183
2184         recompute_tempos (imaginary);
2185
2186         if (check_solved (imaginary)) {
2187                 return true;
2188         }
2189
2190         return false;
2191 }
2192
2193 bool
2194 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2195 {
2196         TempoSection* prev_t = 0;
2197         TempoSection* section_prev = 0;
2198
2199         section->set_pulse (pulse);
2200
2201         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2202                 TempoSection* t;
2203                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2204                         if (!t->active()) {
2205                                 continue;
2206                         }
2207                         if (!t->movable()) {
2208                                 t->set_pulse (0.0);
2209                                 prev_t = t;
2210                                 continue;
2211                         }
2212                         if (prev_t) {
2213                                 if (t == section) {
2214                                         section_prev = prev_t;
2215                                         continue;
2216                                 }
2217                                 if (t->position_lock_style() == MusicTime) {
2218                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2219                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2220                                 } else {
2221                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2222                                         if (!t->locked_to_meter()) {
2223                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2224                                         }
2225                                 }
2226                         }
2227                         prev_t = t;
2228                 }
2229         }
2230
2231         if (section_prev) {
2232                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
2233                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2234         }
2235
2236 #if (0)
2237         recompute_tempos (imaginary);
2238
2239         if (check_solved (imaginary)) {
2240                 return true;
2241         } else {
2242                 dunp (imaginary, std::cout);
2243         }
2244 #endif
2245
2246         MetricSectionSorter cmp;
2247         imaginary.sort (cmp);
2248
2249         recompute_tempos (imaginary);
2250         /* Reordering
2251          * XX need a restriction here, but only for this case,
2252          * as audio locked tempos don't interact in the same way.
2253          *
2254          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2255          * e.g.
2256          * |50 bpm                        |250 bpm |60 bpm
2257          *                drag 250 to the pulse after 60->
2258          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2259          */
2260         if (check_solved (imaginary)) {
2261                 return true;
2262         }
2263
2264         return false;
2265 }
2266
2267 bool
2268 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2269 {
2270         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2271         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2272         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2273                 return false;
2274         }
2275
2276         if (!section->movable()) {
2277                 /* lock the first tempo to our first meter */
2278                 if (!set_active_tempos (imaginary, frame)) {
2279                         return false;
2280                 }
2281         }
2282
2283         TempoSection* meter_locked_tempo = 0;
2284
2285         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2286                 TempoSection* t;
2287                 if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2288                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2289                                 meter_locked_tempo = t;
2290                                 break;
2291                         }
2292                 }
2293         }
2294
2295         if (!meter_locked_tempo) {
2296                 return false;
2297         }
2298
2299         MeterSection* prev_m = 0;
2300         Metrics future_map;
2301         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2302         bool solved = false;
2303
2304         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2305                 MeterSection* m;
2306                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2307                         if (m == section){
2308                                 if (prev_m && section->movable()) {
2309                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2310                                         if (beats + prev_m->beat() < section->beat()) {
2311                                                 /* set the frame/pulse corresponding to its musical position,
2312                                                  * as an earlier time than this has been requested.
2313                                                 */
2314                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2315                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2316
2317                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2318
2319                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2320                                                         meter_locked_tempo->set_pulse (new_pulse);
2321                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2322                                                         section->set_frame (smallest_frame);
2323                                                         section->set_pulse (new_pulse);
2324                                                 } else {
2325                                                         solved = false;
2326                                                 }
2327
2328                                                 Metrics::const_iterator d = future_map.begin();
2329                                                 while (d != future_map.end()) {
2330                                                         delete (*d);
2331                                                         ++d;
2332                                                 }
2333
2334                                                 if (!solved) {
2335                                                         return false;
2336                                                 }
2337                                         } else {
2338                                                 /* all is ok. set section's locked tempo if allowed.
2339                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2340                                                    XX this check could possibly go. its never actually happened here.
2341                                                 */
2342                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2343                                                 meter_copy->set_frame (frame);
2344
2345                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2346                                                         section->set_frame (frame);
2347                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2348                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2349                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2350                                                 } else {
2351                                                         solved = false;
2352                                                 }
2353
2354                                                 Metrics::const_iterator d = future_map.begin();
2355                                                 while (d != future_map.end()) {
2356                                                         delete (*d);
2357                                                         ++d;
2358                                                 }
2359
2360                                                 if (!solved) {
2361                                                         return false;
2362                                                 }
2363                                         }
2364                                 } else {
2365                                         /* not movable (first meter atm) */
2366
2367                                         tempo_copy->set_frame (frame);
2368                                         tempo_copy->set_pulse (0.0);
2369
2370                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2371                                                 section->set_frame (frame);
2372                                                 meter_locked_tempo->set_frame (frame);
2373                                                 meter_locked_tempo->set_pulse (0.0);
2374                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2375                                         } else {
2376                                                 solved = false;
2377                                         }
2378
2379                                         Metrics::const_iterator d = future_map.begin();
2380                                         while (d != future_map.end()) {
2381                                                 delete (*d);
2382                                                 ++d;
2383                                         }
2384
2385                                         if (!solved) {
2386                                                 return false;
2387                                         }
2388
2389                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2390                                         section->set_beat (b_bbt);
2391                                         section->set_pulse (0.0);
2392
2393                                 }
2394                                 break;
2395                         }
2396
2397                         prev_m = m;
2398                 }
2399         }
2400
2401         MetricSectionFrameSorter fcmp;
2402         imaginary.sort (fcmp);
2403
2404         recompute_meters (imaginary);
2405
2406         return true;
2407 }
2408
2409 bool
2410 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2411 {
2412         /* disallow setting section to an existing meter's bbt */
2413         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2414                 MeterSection* m;
2415                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2416                         if (m != section && m->bbt().bars == when.bars) {
2417                                 return false;
2418                         }
2419                 }
2420         }
2421
2422         MeterSection* prev_m = 0;
2423         MeterSection* section_prev = 0;
2424
2425         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2426                 MeterSection* m;
2427                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2428                         pair<double, BBT_Time> b_bbt;
2429                         double new_pulse = 0.0;
2430
2431                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2432                                 section_prev = prev_m;
2433                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2434                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2435                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2436
2437                                 section->set_beat (b_bbt);
2438                                 section->set_pulse (pulse);
2439                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2440                                 prev_m = section;
2441                                 continue;
2442                         }
2443
2444                         if (m->position_lock_style() == AudioTime) {
2445                                 TempoSection* meter_locked_tempo = 0;
2446
2447                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2448                                         TempoSection* t;
2449                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2450                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2451                                                         meter_locked_tempo = t;
2452                                                         break;
2453                                                 }
2454                                         }
2455                                 }
2456
2457                                 if (!meter_locked_tempo) {
2458                                         return false;
2459                                 }
2460
2461                                 if (prev_m) {
2462                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2463
2464                                         if (beats + prev_m->beat() != m->beat()) {
2465                                                 /* tempo/ meter change caused a change in beat (bar). */
2466                                                 b_bbt = make_pair (beats + prev_m->beat()
2467                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2468                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2469                                         } else if (m->movable()) {
2470                                                 b_bbt = make_pair (m->beat(), m->bbt());
2471                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2472                                         }
2473                                 } else {
2474                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2475                                 }
2476
2477                                 meter_locked_tempo->set_pulse (new_pulse);
2478                                 m->set_beat (b_bbt);
2479                                 m->set_pulse (new_pulse);
2480
2481                         } else {
2482                                 /* MusicTime */
2483                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2484                                 if (beats + prev_m->beat() != m->beat()) {
2485                                         /* tempo/ meter change caused a change in beat (bar). */
2486                                         b_bbt = make_pair (beats + prev_m->beat()
2487                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2488                                 } else {
2489                                         b_bbt = make_pair (beats + prev_m->beat()
2490                                                            , m->bbt());
2491                                 }
2492                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2493                                 m->set_beat (b_bbt);
2494                                 m->set_pulse (new_pulse);
2495                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2496                         }
2497
2498                         prev_m = m;
2499                 }
2500         }
2501
2502         if (!section_prev) {
2503
2504                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2505                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2506                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2507
2508                 section->set_beat (b_bbt);
2509                 section->set_pulse (pulse);
2510                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2511         }
2512
2513         MetricSectionSorter cmp;
2514         imaginary.sort (cmp);
2515
2516         recompute_meters (imaginary);
2517
2518         return true;
2519 }
2520
2521 /** places a copy of _metrics into copy and returns a pointer
2522  *  to section's equivalent in copy.
2523  */
2524 TempoSection*
2525 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2526 {
2527         TempoSection* ret = 0;
2528
2529         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2530                 TempoSection* t;
2531                 MeterSection* m;
2532                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2533                         if (t == section) {
2534                                 ret = new TempoSection (*t);
2535                                 copy.push_back (ret);
2536                                 continue;
2537                         }
2538
2539                         TempoSection* cp = new TempoSection (*t);
2540                         copy.push_back (cp);
2541                 }
2542                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2543                         MeterSection* cp = new MeterSection (*m);
2544                         copy.push_back (cp);
2545                 }
2546         }
2547
2548         return ret;
2549 }
2550
2551 MeterSection*
2552 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2553 {
2554         MeterSection* ret = 0;
2555
2556         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2557                 TempoSection* t;
2558                 MeterSection* m;
2559                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2560                         TempoSection* cp = new TempoSection (*t);
2561                         copy.push_back (cp);
2562                 }
2563
2564                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2565                         if (m == section) {
2566                                 ret = new MeterSection (*m);
2567                                 copy.push_back (ret);
2568                                 continue;
2569                         }
2570                         MeterSection* cp = new MeterSection (*m);
2571                         copy.push_back (cp);
2572                 }
2573         }
2574
2575         return ret;
2576 }
2577
2578 /** answers the question "is this a valid beat position for this tempo section?".
2579  *  it returns true if the tempo section can be moved to the requested bbt position,
2580  *  leaving the tempo map in a solved state.
2581  * @param section the tempo section to be moved
2582  * @param bbt the requested new position for the tempo section
2583  * @return true if the tempo section can be moved to the position, otherwise false.
2584  */
2585 bool
2586 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2587 {
2588         Metrics copy;
2589         TempoSection* tempo_copy = 0;
2590
2591         {
2592                 Glib::Threads::RWLock::ReaderLock lm (lock);
2593                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2594                 if (!tempo_copy) {
2595                         return false;
2596                 }
2597         }
2598
2599         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2600
2601         Metrics::const_iterator d = copy.begin();
2602         while (d != copy.end()) {
2603                 delete (*d);
2604                 ++d;
2605         }
2606
2607         return ret;
2608 }
2609
2610 /**
2611 * This is for a gui that needs to know the pulse or frame of a tempo section if it were to be moved to some bbt time,
2612 * taking any possible reordering as a consequence of this into account.
2613 * @param section - the section to be altered
2614 * @param bbt - the bbt where the altered tempo will fall
2615 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2616 */
2617 pair<double, framepos_t>
2618 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2619 {
2620         Metrics future_map;
2621         pair<double, framepos_t> ret = make_pair (0.0, 0);
2622
2623         Glib::Threads::RWLock::ReaderLock lm (lock);
2624
2625         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2626
2627         const double beat = beat_at_bbt_locked (future_map, bbt);
2628
2629         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2630                 ret.first = tempo_copy->pulse();
2631                 ret.second = tempo_copy->frame();
2632         } else {
2633                 ret.first = section->pulse();
2634                 ret.second = section->frame();
2635         }
2636
2637         Metrics::const_iterator d = future_map.begin();
2638         while (d != future_map.end()) {
2639                 delete (*d);
2640                 ++d;
2641         }
2642         return ret;
2643 }
2644
2645 void
2646 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame, const int& sub_num)
2647 {
2648         Metrics future_map;
2649         bool was_musical = ts->position_lock_style() == MusicTime;
2650
2651         if (sub_num == 0 && was_musical) {
2652                 /* if we're not snapping to music,
2653                    AudioTime and MusicTime may be treated identically.
2654                 */
2655                 ts->set_position_lock_style (AudioTime);
2656         }
2657
2658         if (ts->position_lock_style() == MusicTime) {
2659                 {
2660                         /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
2661                         Glib::Threads::RWLock::WriterLock lm (lock);
2662                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2663                         const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
2664                         double pulse = pulse_at_beat_locked (future_map, beat);
2665
2666                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2667                                 solve_map_pulse (_metrics, ts, pulse);
2668                                 recompute_meters (_metrics);
2669                         }
2670                 }
2671
2672         } else {
2673
2674                 {
2675                         Glib::Threads::RWLock::WriterLock lm (lock);
2676                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2677                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2678                                 solve_map_frame (_metrics, ts, frame);
2679                                 recompute_meters (_metrics);
2680                         }
2681                 }
2682         }
2683
2684         if (sub_num == 0 && was_musical) {
2685                 ts->set_position_lock_style (MusicTime);
2686         }
2687
2688         Metrics::const_iterator d = future_map.begin();
2689         while (d != future_map.end()) {
2690                 delete (*d);
2691                 ++d;
2692         }
2693
2694         MetricPositionChanged (); // Emit Signal
2695 }
2696
2697 void
2698 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2699 {
2700         Metrics future_map;
2701
2702         if (ms->position_lock_style() == AudioTime) {
2703
2704                 {
2705                         Glib::Threads::RWLock::WriterLock lm (lock);
2706                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2707
2708                         if (solve_map_frame (future_map, copy, frame)) {
2709                                 solve_map_frame (_metrics, ms, frame);
2710                                 recompute_tempos (_metrics);
2711                         }
2712                 }
2713         } else {
2714                 {
2715                         Glib::Threads::RWLock::WriterLock lm (lock);
2716                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2717
2718                         const double beat = beat_at_frame_locked (_metrics, frame);
2719                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2720
2721                         if (solve_map_bbt (future_map, copy, bbt)) {
2722                                 solve_map_bbt (_metrics, ms, bbt);
2723                                 recompute_tempos (_metrics);
2724                         }
2725                 }
2726         }
2727
2728         Metrics::const_iterator d = future_map.begin();
2729         while (d != future_map.end()) {
2730                 delete (*d);
2731                 ++d;
2732         }
2733
2734         MetricPositionChanged (); // Emit Signal
2735 }
2736
2737 bool
2738 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2739 {
2740         Metrics future_map;
2741         bool can_solve = false;
2742         {
2743                 Glib::Threads::RWLock::WriterLock lm (lock);
2744                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2745                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2746                 recompute_tempos (future_map);
2747
2748                 if (check_solved (future_map)) {
2749                         ts->set_beats_per_minute (bpm.beats_per_minute());
2750                         recompute_map (_metrics);
2751                         can_solve = true;
2752                 }
2753         }
2754
2755         Metrics::const_iterator d = future_map.begin();
2756         while (d != future_map.end()) {
2757                 delete (*d);
2758                 ++d;
2759         }
2760         if (can_solve) {
2761                 MetricPositionChanged (); // Emit Signal
2762         }
2763         return can_solve;
2764 }
2765
2766 void
2767 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2768 {
2769         /*
2770           Ts (future prev_t)   Tnext
2771           |                    |
2772           |     [drag^]        |
2773           |----------|----------
2774                 e_f  pulse(frame)
2775         */
2776
2777         Metrics future_map;
2778
2779         {
2780                 Glib::Threads::RWLock::WriterLock lm (lock);
2781
2782                 if (!ts) {
2783                         return;
2784                 }
2785
2786                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2787                 TempoSection* prev_to_prev_t = 0;
2788                 const frameoffset_t fr_off = end_frame - frame;
2789
2790                 if (prev_t && prev_t->pulse() > 0.0) {
2791                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2792                 }
2793
2794                 TempoSection* next_t = 0;
2795                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2796                         TempoSection* t = 0;
2797                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2798                                 if (t->frame() > ts->frame()) {
2799                                         next_t = t;
2800                                         break;
2801                                 }
2802                         }
2803                 }
2804                 /* minimum allowed measurement distance in frames */
2805                 const framepos_t min_dframe = 2;
2806
2807                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2808                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2809                 */
2810                 double contribution = 0.0;
2811
2812                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2813                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2814                 }
2815
2816                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2817
2818                 const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2819                 const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2820
2821                 double new_bpm;
2822
2823                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2824
2825                         if (prev_t->position_lock_style() == MusicTime) {
2826                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2827                                         if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
2828
2829                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2830                                                                                         / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2831                                         } else {
2832                                                 new_bpm = prev_t->beats_per_minute();
2833                                         }
2834                                 } else {
2835                                         /* prev to prev is irrelevant */
2836
2837                                         if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
2838                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2839                                         } else {
2840                                                 new_bpm = prev_t->beats_per_minute();
2841                                         }
2842                                 }
2843                         } else {
2844                                 /* AudioTime */
2845                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2846                                         if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
2847
2848                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2849                                                                                         / (double) ((end_frame) - prev_to_prev_t->frame()));
2850                                         } else {
2851                                                 new_bpm = prev_t->beats_per_minute();
2852                                         }
2853                                 } else {
2854                                         /* prev_to_prev_t is irrelevant */
2855
2856                                         if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
2857                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2858                                         } else {
2859                                                 new_bpm = prev_t->beats_per_minute();
2860                                         }
2861                                 }
2862                         }
2863                 } else {
2864
2865                         double frame_ratio = 1.0;
2866                         double pulse_ratio = 1.0;
2867                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2868
2869                         if (prev_to_prev_t) {
2870                                 if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
2871                                         frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2872                                 }
2873                                 if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
2874                                         pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2875                                 }
2876                         } else {
2877                                 if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
2878                                         frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2879                                 }
2880                                 pulse_ratio = (start_pulse / end_pulse);
2881                         }
2882                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2883                 }
2884
2885                 /* don't clamp and proceed here.
2886                    testing has revealed that this can go negative,
2887                    which is an entirely different thing to just being too low.
2888                 */
2889                 if (new_bpm < 0.5) {
2890                         return;
2891                 }
2892                 new_bpm = min (new_bpm, (double) 1000.0);
2893                 prev_t->set_beats_per_minute (new_bpm);
2894                 recompute_tempos (future_map);
2895                 recompute_meters (future_map);
2896
2897                 if (check_solved (future_map)) {
2898                         ts->set_beats_per_minute (new_bpm);
2899                         recompute_tempos (_metrics);
2900                         recompute_meters (_metrics);
2901                 }
2902         }
2903
2904         Metrics::const_iterator d = future_map.begin();
2905         while (d != future_map.end()) {
2906                 delete (*d);
2907                 ++d;
2908         }
2909
2910         MetricPositionChanged (); // Emit Signal
2911 }
2912
2913 double
2914 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t& sub_num)
2915 {
2916         Glib::Threads::RWLock::ReaderLock lm (lock);
2917
2918         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
2919 }
2920
2921 double
2922 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t& sub_num)
2923 {
2924         double beat = beat_at_frame_locked (metrics, frame);
2925         if (sub_num > 1) {
2926                 beat = floor (beat) + (floor (((beat - floor (beat)) * (double) sub_num) + 0.5) / sub_num);
2927         } else if (sub_num == 1) {
2928                 /* snap to beat */
2929                 beat = floor (beat + 0.5);
2930         } else if (sub_num == -1) {
2931                 /* snap to  bar */
2932                 Timecode::BBT_Time bbt = bbt_at_beat_locked (metrics, beat);
2933                 bbt.beats = 1;
2934                 bbt.ticks = 0;
2935                 beat = beat_at_bbt_locked (metrics, bbt);
2936         }
2937         return beat;
2938 }
2939
2940 framecnt_t
2941 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2942 {
2943         Glib::Threads::RWLock::ReaderLock lm (lock);
2944
2945         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2946         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2947         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2948
2949         return frame_at_beat_locked (_metrics, total_beats);
2950 }
2951
2952 framepos_t
2953 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2954 {
2955         return round_to_type (fr, dir, Bar);
2956 }
2957
2958 framepos_t
2959 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2960 {
2961         return round_to_type (fr, dir, Beat);
2962 }
2963
2964 framepos_t
2965 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2966 {
2967         Glib::Threads::RWLock::ReaderLock lm (lock);
2968         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2969         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2970         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2971
2972         ticks -= beats * BBT_Time::ticks_per_beat;
2973
2974         if (dir > 0) {
2975                 /* round to next (or same iff dir == RoundUpMaybe) */
2976
2977                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2978
2979                 if (mod == 0 && dir == RoundUpMaybe) {
2980                         /* right on the subdivision, which is fine, so do nothing */
2981
2982                 } else if (mod == 0) {
2983                         /* right on the subdivision, so the difference is just the subdivision ticks */
2984                         ticks += ticks_one_subdivisions_worth;
2985
2986                 } else {
2987                         /* not on subdivision, compute distance to next subdivision */
2988
2989                         ticks += ticks_one_subdivisions_worth - mod;
2990                 }
2991
2992                 if (ticks >= BBT_Time::ticks_per_beat) {
2993                         ticks -= BBT_Time::ticks_per_beat;
2994                 }
2995         } else if (dir < 0) {
2996
2997                 /* round to previous (or same iff dir == RoundDownMaybe) */
2998
2999                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3000
3001                 if (difference == 0 && dir == RoundDownAlways) {
3002                         /* right on the subdivision, but force-rounding down,
3003                            so the difference is just the subdivision ticks */
3004                         difference = ticks_one_subdivisions_worth;
3005                 }
3006
3007                 if (ticks < difference) {
3008                         ticks = BBT_Time::ticks_per_beat - ticks;
3009                 } else {
3010                         ticks -= difference;
3011                 }
3012
3013         } else {
3014                 /* round to nearest */
3015                 double rem;
3016
3017                 /* compute the distance to the previous and next subdivision */
3018
3019                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3020
3021                         /* closer to the next subdivision, so shift forward */
3022
3023                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3024
3025                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3026
3027                         if (ticks > BBT_Time::ticks_per_beat) {
3028                                 ++beats;
3029                                 ticks -= BBT_Time::ticks_per_beat;
3030                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3031                         }
3032
3033                 } else if (rem > 0) {
3034
3035                         /* closer to previous subdivision, so shift backward */
3036
3037                         if (rem > ticks) {
3038                                 if (beats == 0) {
3039                                         /* can't go backwards past zero, so ... */
3040                                         return 0;
3041                                 }
3042                                 /* step back to previous beat */
3043                                 --beats;
3044                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3045                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3046                         } else {
3047                                 ticks = lrint (ticks - rem);
3048                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3049                         }
3050                 } else {
3051                         /* on the subdivision, do nothing */
3052                 }
3053         }
3054
3055         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
3056
3057         return ret_frame;
3058 }
3059
3060 framepos_t
3061 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
3062 {
3063         Glib::Threads::RWLock::ReaderLock lm (lock);
3064
3065         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
3066         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
3067
3068         switch (type) {
3069         case Bar:
3070                 if (dir < 0) {
3071                         /* find bar previous to 'frame' */
3072                         bbt.beats = 1;
3073                         bbt.ticks = 0;
3074                         return frame_at_bbt_locked (_metrics, bbt);
3075
3076                 } else if (dir > 0) {
3077                         /* find bar following 'frame' */
3078                         ++bbt.bars;
3079                         bbt.beats = 1;
3080                         bbt.ticks = 0;
3081                         return frame_at_bbt_locked (_metrics, bbt);
3082                 } else {
3083                         /* true rounding: find nearest bar */
3084                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
3085                         bbt.beats = 1;
3086                         bbt.ticks = 0;
3087                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
3088                         ++bbt.bars;
3089                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
3090
3091                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
3092                                 return next_ft;
3093                         } else {
3094                                 return prev_ft;
3095                         }
3096                 }
3097
3098                 break;
3099
3100         case Beat:
3101                 if (dir < 0) {
3102                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
3103                 } else if (dir > 0) {
3104                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
3105                 } else {
3106                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
3107                 }
3108                 break;
3109         }
3110
3111         return 0;
3112 }
3113
3114 void
3115 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
3116                     framepos_t lower, framepos_t upper)
3117 {
3118         Glib::Threads::RWLock::ReaderLock lm (lock);
3119         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
3120         framecnt_t pos = 0;
3121         /* although the map handles negative beats, bbt doesn't. */
3122         if (cnt < 0.0) {
3123                 cnt = 0.0;
3124         }
3125
3126         if (frame_at_beat_locked (_metrics, cnt) >= upper) {
3127                 return;
3128         }
3129
3130         while (pos < upper) {
3131                 pos = frame_at_beat_locked (_metrics, cnt);
3132                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
3133                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
3134                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
3135                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
3136                 ++cnt;
3137         }
3138 }
3139
3140 const TempoSection&
3141 TempoMap::tempo_section_at_frame (framepos_t frame) const
3142 {
3143         Glib::Threads::RWLock::ReaderLock lm (lock);
3144         return tempo_section_at_frame_locked (_metrics, frame);
3145 }
3146
3147 const TempoSection&
3148 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3149 {
3150         Metrics::const_iterator i;
3151         TempoSection* prev = 0;
3152
3153         for (i = metrics.begin(); i != metrics.end(); ++i) {
3154                 TempoSection* t;
3155
3156                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3157                         if (!t->active()) {
3158                                 continue;
3159                         }
3160                         if (prev && t->frame() > frame) {
3161                                 break;
3162                         }
3163
3164                         prev = t;
3165                 }
3166         }
3167
3168         if (prev == 0) {
3169                 fatal << endmsg;
3170                 abort(); /*NOTREACHED*/
3171         }
3172
3173         return *prev;
3174 }
3175
3176 const TempoSection&
3177 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3178 {
3179         TempoSection* prev_t = 0;
3180         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
3181
3182         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3183                 TempoSection* t;
3184                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3185                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
3186                                 break;
3187                         }
3188                         prev_t = t;
3189                 }
3190
3191         }
3192         return *prev_t;
3193 }
3194
3195 /* don't use this to calculate length (the tempo is only correct for this frame).
3196    do that stuff based on the beat_at_frame and frame_at_beat api
3197 */
3198 double
3199 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3200 {
3201         Glib::Threads::RWLock::ReaderLock lm (lock);
3202
3203         const TempoSection* ts_at = &tempo_section_at_frame_locked (_metrics, frame);
3204         const TempoSection* ts_after = 0;
3205         Metrics::const_iterator i;
3206
3207         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3208                 TempoSection* t;
3209
3210                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3211                         if (!t->active()) {
3212                                 continue;
3213                         }
3214                         if ((*i)->frame() > frame) {
3215                                 ts_after = t;
3216                                 break;
3217                         }
3218                 }
3219         }
3220
3221         if (ts_after) {
3222                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * ts_at->note_type());
3223         }
3224         /* must be treated as constant tempo */
3225         return ts_at->frames_per_beat (_frame_rate);
3226 }
3227
3228 const MeterSection&
3229 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3230 {
3231         Metrics::const_iterator i;
3232         MeterSection* prev = 0;
3233
3234         for (i = metrics.begin(); i != metrics.end(); ++i) {
3235                 MeterSection* m;
3236
3237                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3238
3239                         if (prev && (*i)->frame() > frame) {
3240                                 break;
3241                         }
3242
3243                         prev = m;
3244                 }
3245         }
3246
3247         if (prev == 0) {
3248                 fatal << endmsg;
3249                 abort(); /*NOTREACHED*/
3250         }
3251
3252         return *prev;
3253 }
3254
3255
3256 const MeterSection&
3257 TempoMap::meter_section_at_frame (framepos_t frame) const
3258 {
3259         Glib::Threads::RWLock::ReaderLock lm (lock);
3260         return meter_section_at_frame_locked (_metrics, frame);
3261 }
3262
3263 const MeterSection&
3264 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3265 {
3266         MeterSection* prev_m = 0;
3267
3268         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3269                 MeterSection* m;
3270                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3271                         if (prev_m && m->beat() > beat) {
3272                                 break;
3273                         }
3274                         prev_m = m;
3275                 }
3276
3277         }
3278         return *prev_m;
3279 }
3280
3281 const MeterSection&
3282 TempoMap::meter_section_at_beat (double beat) const
3283 {
3284         Glib::Threads::RWLock::ReaderLock lm (lock);
3285         return meter_section_at_beat_locked (_metrics, beat);
3286 }
3287
3288 const Meter&
3289 TempoMap::meter_at_frame (framepos_t frame) const
3290 {
3291         TempoMetric m (metric_at (frame));
3292         return m.meter();
3293 }
3294
3295 void
3296 TempoMap::fix_legacy_session ()
3297 {
3298         MeterSection* prev_m = 0;
3299         TempoSection* prev_t = 0;
3300
3301         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3302                 MeterSection* m;
3303                 TempoSection* t;
3304
3305                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3306                         if (!m->movable()) {
3307                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3308                                 m->set_beat (bbt);
3309                                 m->set_pulse (0.0);
3310                                 m->set_frame (0);
3311                                 m->set_position_lock_style (AudioTime);
3312                                 prev_m = m;
3313                                 continue;
3314                         }
3315                         if (prev_m) {
3316                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3317                                                                           + (m->bbt().beats - 1)
3318                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3319                                                                           , m->bbt());
3320                                 m->set_beat (start);
3321                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3322                                         + (m->bbt().beats - 1)
3323                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3324                                 m->set_pulse (start_beat / prev_m->note_divisor());
3325                         }
3326                         prev_m = m;
3327                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3328
3329                         if (!t->active()) {
3330                                 continue;
3331                         }
3332
3333                         if (!t->movable()) {
3334                                 t->set_pulse (0.0);
3335                                 t->set_frame (0);
3336                                 t->set_position_lock_style (AudioTime);
3337                                 prev_t = t;
3338                                 continue;
3339                         }
3340
3341                         if (prev_t) {
3342                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3343                                         + (t->legacy_bbt().beats - 1)
3344                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3345                                 if (prev_m) {
3346                                         t->set_pulse (beat / prev_m->note_divisor());
3347                                 } else {
3348                                         /* really shouldn't happen but.. */
3349                                         t->set_pulse (beat / 4.0);
3350                                 }
3351                         }
3352                         prev_t = t;
3353                 }
3354         }
3355 }
3356
3357 XMLNode&
3358 TempoMap::get_state ()
3359 {
3360         Metrics::const_iterator i;
3361         XMLNode *root = new XMLNode ("TempoMap");
3362
3363         {
3364                 Glib::Threads::RWLock::ReaderLock lm (lock);
3365                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3366                         root->add_child_nocopy ((*i)->get_state());
3367                 }
3368         }
3369
3370         return *root;
3371 }
3372
3373 int
3374 TempoMap::set_state (const XMLNode& node, int /*version*/)
3375 {
3376         {
3377                 Glib::Threads::RWLock::WriterLock lm (lock);
3378
3379                 XMLNodeList nlist;
3380                 XMLNodeConstIterator niter;
3381                 Metrics old_metrics (_metrics);
3382                 _metrics.clear();
3383
3384                 nlist = node.children();
3385
3386                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3387                         XMLNode* child = *niter;
3388
3389                         if (child->name() == TempoSection::xml_state_node_name) {
3390
3391                                 try {
3392                                         TempoSection* ts = new TempoSection (*child);
3393                                         _metrics.push_back (ts);
3394                                 }
3395
3396                                 catch (failed_constructor& err){
3397                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3398                                         _metrics = old_metrics;
3399                                         break;
3400                                 }
3401
3402                         } else if (child->name() == MeterSection::xml_state_node_name) {
3403
3404                                 try {
3405                                         MeterSection* ms = new MeterSection (*child);
3406                                         _metrics.push_back (ms);
3407                                 }
3408
3409                                 catch (failed_constructor& err) {
3410                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3411                                         _metrics = old_metrics;
3412                                         break;
3413                                 }
3414                         }
3415                 }
3416
3417                 if (niter == nlist.end()) {
3418                         MetricSectionSorter cmp;
3419                         _metrics.sort (cmp);
3420                 }
3421
3422                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3423                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3424                         TempoSection* t;
3425                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3426                                 if (t->legacy_bbt().bars != 0) {
3427                                         fix_legacy_session();
3428                                         break;
3429                                 }
3430                                 break;
3431                         }
3432                 }
3433
3434                 /* check for multiple tempo/meters at the same location, which
3435                    ardour2 somehow allowed.
3436                 */
3437
3438                 Metrics::iterator prev = _metrics.end();
3439                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3440                         if (prev != _metrics.end()) {
3441                                 MeterSection* ms;
3442                                 MeterSection* prev_m;
3443                                 TempoSection* ts;
3444                                 TempoSection* prev_t;
3445                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3446                                         if (prev_m->pulse() == ms->pulse()) {
3447                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3448                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3449                                                 return -1;
3450                                         }
3451                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3452                                         if (prev_t->pulse() == ts->pulse()) {
3453                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3454                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3455                                                 return -1;
3456                                         }
3457                                 }
3458                         }
3459                         prev = i;
3460                 }
3461
3462                 recompute_map (_metrics);
3463         }
3464
3465         PropertyChanged (PropertyChange ());
3466
3467         return 0;
3468 }
3469
3470 void
3471 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3472 {
3473         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3474         const MeterSection* m;
3475         const TempoSection* t;
3476         const TempoSection* prev_t = 0;
3477
3478         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3479
3480                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3481                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3482                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3483                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3484                         if (prev_t) {
3485                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3486                                 o << "calculated   : " << prev_t->tempo_at_pulse (t->pulse()) *  prev_t->note_type() << " | " << prev_t->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) <<  " | " << prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
3487                         }
3488                         prev_t = t;
3489                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3490                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3491                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3492                 }
3493         }
3494         o << "------" << std::endl;
3495 }
3496
3497 int
3498 TempoMap::n_tempos() const
3499 {
3500         Glib::Threads::RWLock::ReaderLock lm (lock);
3501         int cnt = 0;
3502
3503         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3504                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3505                         cnt++;
3506                 }
3507         }
3508
3509         return cnt;
3510 }
3511
3512 int
3513 TempoMap::n_meters() const
3514 {
3515         Glib::Threads::RWLock::ReaderLock lm (lock);
3516         int cnt = 0;
3517
3518         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3519                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3520                         cnt++;
3521                 }
3522         }
3523
3524         return cnt;
3525 }
3526
3527 void
3528 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3529 {
3530         {
3531                 Glib::Threads::RWLock::WriterLock lm (lock);
3532                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3533                         if ((*i)->frame() >= where && (*i)->movable ()) {
3534                                 (*i)->set_frame ((*i)->frame() + amount);
3535                         }
3536                 }
3537
3538                 /* now reset the BBT time of all metrics, based on their new
3539                  * audio time. This is the only place where we do this reverse
3540                  * timestamp.
3541                  */
3542
3543                 Metrics::iterator i;
3544                 const MeterSection* meter;
3545                 const TempoSection* tempo;
3546                 MeterSection *m;
3547                 TempoSection *t;
3548
3549                 meter = &first_meter ();
3550                 tempo = &first_tempo ();
3551
3552                 BBT_Time start;
3553                 BBT_Time end;
3554
3555                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3556
3557                 bool first = true;
3558                 MetricSection* prev = 0;
3559
3560                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3561
3562                         BBT_Time bbt;
3563                         //TempoMetric metric (*meter, *tempo);
3564                         MeterSection* ms = const_cast<MeterSection*>(meter);
3565                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3566                         if (prev) {
3567                                 if (ts){
3568                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3569                                                 if (!t->active()) {
3570                                                         continue;
3571                                                 }
3572                                                 ts->set_pulse (t->pulse());
3573                                         }
3574                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3575                                                 ts->set_pulse (m->pulse());
3576                                         }
3577                                         ts->set_frame (prev->frame());
3578
3579                                 }
3580                                 if (ms) {
3581                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3582                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3583                                                 ms->set_beat (start);
3584                                                 ms->set_pulse (m->pulse());
3585                                         }
3586                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3587                                                 if (!t->active()) {
3588                                                         continue;
3589                                                 }
3590                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3591                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3592                                                 ms->set_beat (start);
3593                                                 ms->set_pulse (t->pulse());
3594                                         }
3595                                         ms->set_frame (prev->frame());
3596                                 }
3597
3598                         } else {
3599                                 // metric will be at frames=0 bbt=1|1|0 by default
3600                                 // which is correct for our purpose
3601                         }
3602
3603                         // cerr << bbt << endl;
3604
3605                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3606                                 if (!t->active()) {
3607                                         continue;
3608                                 }
3609                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3610                                 tempo = t;
3611                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3612                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3613                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3614
3615                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3616
3617                                 if (first) {
3618                                         first = false;
3619                                 } else {
3620
3621                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3622                                                 /* round up to next beat */
3623                                                 bbt.beats += 1;
3624                                         }
3625
3626                                         bbt.ticks = 0;
3627
3628                                         if (bbt.beats != 1) {
3629                                                 /* round up to next bar */
3630                                                 bbt.bars += 1;
3631                                                 bbt.beats = 1;
3632                                         }
3633                                 }
3634                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3635                                 m->set_beat (start);
3636                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3637                                 meter = m;
3638                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3639                         } else {
3640                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3641                                 abort(); /*NOTREACHED*/
3642                         }
3643
3644                         prev = (*i);
3645                 }
3646
3647                 recompute_map (_metrics);
3648         }
3649
3650
3651         PropertyChanged (PropertyChange ());
3652 }
3653 bool
3654 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3655 {
3656         bool moved = false;
3657
3658         std::list<MetricSection*> metric_kill_list;
3659
3660         TempoSection* last_tempo = NULL;
3661         MeterSection* last_meter = NULL;
3662         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3663         bool meter_after = false; // is there a meter marker likewise?
3664         {
3665                 Glib::Threads::RWLock::WriterLock lm (lock);
3666                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3667                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3668                                 metric_kill_list.push_back(*i);
3669                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3670                                 if (lt)
3671                                         last_tempo = lt;
3672                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3673                                 if (lm)
3674                                         last_meter = lm;
3675                         }
3676                         else if ((*i)->frame() >= where) {
3677                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3678                                 (*i)->set_frame ((*i)->frame() - amount);
3679                                 if ((*i)->frame() == where) {
3680                                         // marker was immediately after end of range
3681                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3682                                         meter_after = dynamic_cast<MeterSection*> (*i);
3683                                 }
3684                                 moved = true;
3685                         }
3686                 }
3687
3688                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3689                 if (last_tempo && !tempo_after) {
3690                         metric_kill_list.remove(last_tempo);
3691                         last_tempo->set_frame(where);
3692                         moved = true;
3693                 }
3694                 if (last_meter && !meter_after) {
3695                         metric_kill_list.remove(last_meter);
3696                         last_meter->set_frame(where);
3697                         moved = true;
3698                 }
3699
3700                 //remove all the remaining metrics
3701                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3702                         _metrics.remove(*i);
3703                         moved = true;
3704                 }
3705
3706                 if (moved) {
3707                         recompute_map (_metrics);
3708                 }
3709         }
3710         PropertyChanged (PropertyChange ());
3711         return moved;
3712 }
3713
3714 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3715  *  pos can be -ve, if required.
3716  */
3717 framepos_t
3718 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3719 {
3720         Glib::Threads::RWLock::ReaderLock lm (lock);
3721
3722         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) + beats.to_double());
3723 }
3724
3725 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3726 framepos_t
3727 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3728 {
3729         Glib::Threads::RWLock::ReaderLock lm (lock);
3730
3731         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
3732 }
3733
3734 /** Add the BBT interval op to pos and return the result */
3735 framepos_t
3736 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3737 {
3738         Glib::Threads::RWLock::ReaderLock lm (lock);
3739
3740         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3741         pos_bbt.ticks += op.ticks;
3742         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3743                 ++pos_bbt.beats;
3744                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3745         }
3746         pos_bbt.beats += op.beats;
3747         /* the meter in effect will start on the bar */
3748         double divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3749         while (pos_bbt.beats >= divisions_per_bar + 1) {
3750                 ++pos_bbt.bars;
3751                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3752                 pos_bbt.beats -= divisions_per_bar;
3753         }
3754         pos_bbt.bars += op.bars;
3755
3756         return frame_at_bbt_locked (_metrics, pos_bbt);
3757 }
3758
3759 /** Count the number of beats that are equivalent to distance when going forward,
3760     starting at pos.
3761 */
3762 Evoral::Beats
3763 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3764 {
3765         Glib::Threads::RWLock::ReaderLock lm (lock);
3766
3767         return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
3768 }
3769
3770 struct bbtcmp {
3771     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3772             return a < b;
3773     }
3774 };
3775
3776 std::ostream&
3777 operator<< (std::ostream& o, const Meter& m) {
3778         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3779 }
3780
3781 std::ostream&
3782 operator<< (std::ostream& o, const Tempo& t) {
3783         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3784 }
3785
3786 std::ostream&
3787 operator<< (std::ostream& o, const MetricSection& section) {
3788
3789         o << "MetricSection @ " << section.frame() << ' ';
3790
3791         const TempoSection* ts;
3792         const MeterSection* ms;
3793
3794         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3795                 o << *((const Tempo*) ts);
3796         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3797                 o << *((const Meter*) ms);
3798         }
3799
3800         return o;
3801 }