Fix locking bug in tempo map.
[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 "pbd/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, true)
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), "%lf", 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), "%lf", _beats_per_minute);
187         root->add_property ("beats-per-minute", buf);
188         snprintf (buf, sizeof (buf), "%lf", _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 whole 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 /* pulse 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 pulse */
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, false), 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), "%lf", _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), "%lf", _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   Meter divides pulse into measures and beats.
594
595   TempoSection - provides pulse in the form of beats_per_minute() - the number of quarter notes in one minute.
596   Note that 'beats' in Tempo::beats_per_minute() are quarter notes (pulse based). In the rest of tempo map,
597   'beat' usually refers to accumulated BBT beats (pulse and meter based).
598
599   MeterSecion - divides pulse into measures (via divisions_per_bar) and beats (via note_divisor).
600
601   Both tempo and meter have a pulse position and a frame position.
602   Meters also have a beat position, which is always 0.0 for the first one.
603   TempoSection and MeterSection may be locked to either audio or music (position lock style).
604   The lock style determines the 'true' position of the section wich is used to calculate the other postion parameters of the section.
605
606   The first tempo and first meter are special. they must move together, and must be locked to audio.
607   Audio locked tempos which lie before the first meter are made inactive.
608   They will be re-activated if the first meter is again placed before them.
609
610   With tempo sections potentially being ramped, meters provide a way of mapping beats to whole pulses without
611   referring to the tempo function(s) involved as the distance in whole pulses between a meter and a subsequent beat is
612   sb->beat() - meter->beat() / meter->note_divisor().
613   Because every meter falls on a known pulse, (derived from its bar), the rest is easy as the duration in pulses between
614   two meters is of course
615   (meater_b->bar - meter_a->bar) * meter_a->divisions_per_bar / meter_a->note_divisor.
616
617   Beat calculations are based on meter sections and all pulse and tempo calculations are based on tempo sections.
618   Beat to frame conversion of course requires the use of meter and tempo.
619
620   Remembering that ramped tempo sections interact, it is important to avoid referring to any other tempos when moving tempo sections,
621   Here, beats (meters) are used to determine the new pulse (see predict_tempo_position())
622
623   Recomputing the map is the process where the 'missing' position
624   (tempo pulse or meter pulse & beat in the case of AudioTime, frame for MusicTime) is calculated.
625   We construct the tempo map by first using the frame or pulse position (depending on position lock style) of each tempo.
626   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).
627
628   Having done this, we can now find any musical duration by selecting the tempo and meter covering the position (or tempo) in question
629   and querying its appropriate meter/tempo.
630
631   It is important to keep the _metrics in an order that makes sense.
632   Because ramped MusicTime and AudioTime tempos can interact with each other,
633   reordering is frequent. Care must be taken to keep _metrics in a solved state.
634   Solved means ordered by frame or pulse with frame-accurate precision (see check_solved()).
635
636   Music and Audio
637
638   Music and audio-locked objects may seem interchangeable on the surface, but when translating
639   between audio samples and beat, remember that a sample is only a quantised approximation
640   of the actual time (in minutes) of a beat.
641   Thus if a gui user points to the frame occupying the start of a music-locked object on 1|3|0, it does not
642   mean that this frame is the actual location in time of 1|3|0.
643
644   You cannot use a frame measurement to determine beat distance except under special circumstances
645   (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).
646
647   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
648   sample space the user is operating at to be translated correctly to the object.
649
650   The current approach is to interpret the supplied frame using the grid division the user has currently selected.
651   If the user has no musical grid set, they are actually operating in sample space (even SMPTE frames are rounded to audio frame), so
652   the supplied audio frame is interpreted as the desired musical location (beat_at_frame()).
653
654   tldr: Beat, being a function of time, has nothing to do with sample rate, but time quantization can get in the way of precision.
655
656   When frame_at_beat() is called, the position calculation is performed in pulses and minutes.
657   The result is rounded to audio frames.
658   When beat_at_frame() is called, the frame is converted to minutes, with no rounding performed on the result.
659
660   So :
661   frame_at_beat (beat_at_frame (frame)) == frame
662   but :
663   beat_at_frame (frame_at_beat (beat)) != beat due to the time quantization of frame_at_beat().
664
665   Doing the second one will result in a beat distance error of up to 0.5 audio samples.
666   So instead work in pulses and/or beats and only use beat position to caclulate frame position (e.g. after tempo change).
667   For audio-locked objects, use frame position to calculate beat position.
668
669   The above pointless example would then do:
670   beat_at_pulse (pulse_at_beat (beat)) to avoid rounding.
671
672 */
673 struct MetricSectionSorter {
674     bool operator() (const MetricSection* a, const MetricSection* b) {
675             return a->pulse() < b->pulse();
676     }
677 };
678
679 struct MetricSectionFrameSorter {
680     bool operator() (const MetricSection* a, const MetricSection* b) {
681             return a->frame() < b->frame();
682     }
683 };
684
685 TempoMap::TempoMap (framecnt_t fr)
686 {
687         _frame_rate = fr;
688         BBT_Time start (1, 1, 0);
689
690         TempoSection *t = new TempoSection (0.0, 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime);
691         MeterSection *m = new MeterSection (0.0, 0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime);
692
693         t->set_movable (false);
694         m->set_movable (false);
695
696         /* note: frame time is correct (zero) for both of these */
697
698         _metrics.push_back (t);
699         _metrics.push_back (m);
700
701 }
702
703 TempoMap::~TempoMap ()
704 {
705         Metrics::const_iterator d = _metrics.begin();
706         while (d != _metrics.end()) {
707                 delete (*d);
708                 ++d;
709         }
710         _metrics.clear();
711 }
712
713 void
714 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
715 {
716         bool removed = false;
717
718         {
719                 Glib::Threads::RWLock::WriterLock lm (lock);
720                 if ((removed = remove_tempo_locked (tempo))) {
721                         if (complete_operation) {
722                                 recompute_map (_metrics);
723                         }
724                 }
725         }
726
727         if (removed && complete_operation) {
728                 PropertyChanged (PropertyChange ());
729         }
730 }
731
732 bool
733 TempoMap::remove_tempo_locked (const TempoSection& tempo)
734 {
735         Metrics::iterator i;
736
737         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
738                 if (dynamic_cast<TempoSection*> (*i) != 0) {
739                         if (tempo.frame() == (*i)->frame()) {
740                                 if ((*i)->movable()) {
741                                         delete (*i);
742                                         _metrics.erase (i);
743                                         return true;
744                                 }
745                         }
746                 }
747         }
748
749         return false;
750 }
751
752 void
753 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
754 {
755         bool removed = false;
756
757         {
758                 Glib::Threads::RWLock::WriterLock lm (lock);
759                 if ((removed = remove_meter_locked (tempo))) {
760                         if (complete_operation) {
761                                 recompute_map (_metrics);
762                         }
763                 }
764         }
765
766         if (removed && complete_operation) {
767                 PropertyChanged (PropertyChange ());
768         }
769 }
770
771 bool
772 TempoMap::remove_meter_locked (const MeterSection& meter)
773 {
774
775         if (meter.position_lock_style() == AudioTime) {
776                 /* remove meter-locked tempo */
777                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
778                         TempoSection* t = 0;
779                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
780                                 if (t->locked_to_meter() && meter.frame() == (*i)->frame()) {
781                                         delete (*i);
782                                         _metrics.erase (i);
783                                         break;
784                                 }
785                         }
786                 }
787         }
788
789         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
790                 if (dynamic_cast<MeterSection*> (*i) != 0) {
791                         if (meter.frame() == (*i)->frame()) {
792                                 if ((*i)->movable()) {
793                                         delete (*i);
794                                         _metrics.erase (i);
795                                         return true;
796                                 }
797                         }
798                 }
799         }
800
801         return false;
802 }
803
804 void
805 TempoMap::do_insert (MetricSection* section)
806 {
807         bool need_add = true;
808         /* we only allow new meters to be inserted on beat 1 of an existing
809          * measure.
810          */
811         MeterSection* m = 0;
812         if ((m = dynamic_cast<MeterSection*>(section)) != 0) {
813
814                 if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
815
816                         pair<double, BBT_Time> corrected = make_pair (m->beat(), m->bbt());
817                         corrected.second.beats = 1;
818                         corrected.second.ticks = 0;
819                         corrected.first = beat_at_bbt_locked (_metrics, corrected.second);
820                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
821                                                    m->bbt(), corrected.second) << endmsg;
822                         //m->set_pulse (corrected);
823                 }
824         }
825
826         /* Look for any existing MetricSection that is of the same type and
827            in the same bar as the new one, and remove it before adding
828            the new one. Note that this means that if we find a matching,
829            existing section, we can break out of the loop since we're
830            guaranteed that there is only one such match.
831         */
832
833         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
834
835                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
836                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
837                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
838                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
839
840                 if (tempo && insert_tempo) {
841
842                         /* Tempo sections */
843                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
844                         if ((ipm && tempo->pulse() == insert_tempo->pulse()) || (!ipm && tempo->frame() == insert_tempo->frame())) {
845
846                                 if (!tempo->movable()) {
847
848                                         /* can't (re)move this section, so overwrite
849                                          * its data content (but not its properties as
850                                          * a section).
851                                          */
852
853                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo));
854                                         (*i)->set_position_lock_style (AudioTime);
855                                         TempoSection* t;
856                                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
857                                                 t->set_type (insert_tempo->type());
858                                         }
859                                         need_add = false;
860                                 } else {
861                                         delete (*i);
862                                         _metrics.erase (i);
863                                 }
864                                 break;
865                         }
866
867                 } else if (meter && insert_meter) {
868
869                         /* Meter Sections */
870
871                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
872
873                         if ((ipm && meter->beat() == insert_meter->beat()) || (!ipm && meter->frame() == insert_meter->frame())) {
874
875                                 if (!meter->movable()) {
876
877                                         /* can't (re)move this section, so overwrite
878                                          * its data content (but not its properties as
879                                          * a section
880                                          */
881
882                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
883                                         (*i)->set_position_lock_style (AudioTime);
884                                         need_add = false;
885                                 } else {
886                                         delete (*i);
887                                         _metrics.erase (i);
888                                 }
889
890                                 break;
891                         }
892                 } else {
893                         /* non-matching types, so we don't care */
894                 }
895         }
896
897         /* Add the given MetricSection, if we didn't just reset an existing
898          * one above
899          */
900
901         if (need_add) {
902                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
903                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
904                 Metrics::iterator i;
905                 if (insert_meter) {
906                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
907                                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
908
909                                 if (meter) {
910                                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
911                                         if ((ipm && meter->beat() > insert_meter->beat()) || (!ipm && meter->frame() > insert_meter->frame())) {
912                                                 break;
913                                         }
914                                 }
915                         }
916                 } else if (insert_tempo) {
917                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
918                                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
919
920                                 if (tempo) {
921                                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
922                                         if ((ipm && tempo->pulse() > insert_tempo->pulse()) || (!ipm && tempo->frame() > insert_tempo->frame())) {
923                                                 break;
924                                         }
925                                 }
926                         }
927                 }
928
929                 _metrics.insert (i, section);
930                 //dump (_metrics, std::cout);
931         }
932 }
933
934 TempoSection*
935 TempoMap::add_tempo (const Tempo& tempo, const double& pulse, const framepos_t& frame, ARDOUR::TempoSection::Type type, PositionLockStyle pls)
936 {
937         TempoSection* ts = 0;
938         {
939                 Glib::Threads::RWLock::WriterLock lm (lock);
940                 ts = add_tempo_locked (tempo, pulse, frame, type, pls, true);
941         }
942
943
944         PropertyChanged (PropertyChange ());
945
946         return ts;
947 }
948
949 void
950 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, const framepos_t& frame, TempoSection::Type type, PositionLockStyle pls)
951 {
952         const bool locked_to_meter = ts.locked_to_meter();
953
954         {
955                 Glib::Threads::RWLock::WriterLock lm (lock);
956                 TempoSection& first (first_tempo());
957                 if (ts.frame() != first.frame()) {
958                         remove_tempo_locked (ts);
959                         add_tempo_locked (tempo, pulse, frame, type, pls, true, locked_to_meter);
960                 } else {
961                         first.set_type (type);
962                         first.set_pulse (0.0);
963                         first.set_frame (frame);
964                         first.set_position_lock_style (AudioTime);
965                         {
966                                 /* cannot move the first tempo section */
967                                 *static_cast<Tempo*>(&first) = tempo;
968                                 recompute_map (_metrics);
969                         }
970                 }
971         }
972
973         PropertyChanged (PropertyChange ());
974 }
975
976 TempoSection*
977 TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, framepos_t frame
978                             , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter)
979 {
980         TempoSection* t = new TempoSection (pulse, frame, tempo.beats_per_minute(), tempo.note_type(), type, pls);
981         t->set_locked_to_meter (locked_to_meter);
982         bool solved = false;
983
984         do_insert (t);
985
986         if (recompute) {
987                 if (pls == AudioTime) {
988                         solved = solve_map_frame (_metrics, t, t->frame());
989                 } else {
990                         solved = solve_map_pulse (_metrics, t, t->pulse());
991                 }
992                 recompute_meters (_metrics);
993         }
994
995         if (!solved && recompute) {
996                 recompute_map (_metrics);
997         }
998
999         return t;
1000 }
1001
1002 MeterSection*
1003 TempoMap::add_meter (const Meter& meter, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
1004 {
1005         MeterSection* m = 0;
1006         {
1007                 Glib::Threads::RWLock::WriterLock lm (lock);
1008                 m = add_meter_locked (meter, beat, where, frame, pls, true);
1009         }
1010
1011
1012 #ifndef NDEBUG
1013         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
1014                 dump (_metrics, std::cerr);
1015         }
1016 #endif
1017
1018         PropertyChanged (PropertyChange ());
1019         return m;
1020 }
1021
1022 void
1023 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
1024 {
1025         {
1026                 Glib::Threads::RWLock::WriterLock lm (lock);
1027                 const double beat = beat_at_bbt_locked (_metrics, where);
1028
1029                 if (ms.movable()) {
1030                         remove_meter_locked (ms);
1031                         add_meter_locked (meter, beat, where, frame, pls, true);
1032                 } else {
1033                         MeterSection& first (first_meter());
1034                         TempoSection& first_t (first_tempo());
1035                         /* cannot move the first meter section */
1036                         *static_cast<Meter*>(&first) = meter;
1037                         first.set_position_lock_style (AudioTime);
1038                         first.set_pulse (0.0);
1039                         first.set_frame (frame);
1040                         pair<double, BBT_Time> beat = make_pair (0.0, BBT_Time (1, 1, 0));
1041                         first.set_beat (beat);
1042                         first_t.set_frame (first.frame());
1043                         first_t.set_pulse (0.0);
1044                         first_t.set_position_lock_style (AudioTime);
1045                         recompute_map (_metrics);
1046                 }
1047         }
1048
1049         PropertyChanged (PropertyChange ());
1050 }
1051
1052 MeterSection*
1053 TempoMap::add_meter_locked (const Meter& meter, double beat, const BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
1054 {
1055         const MeterSection& prev_m = meter_section_at_frame_locked  (_metrics, frame - 1);
1056         const double pulse = ((where.bars - prev_m.bbt().bars) * (prev_m.divisions_per_bar() / prev_m.note_divisor())) + prev_m.pulse();
1057         TempoSection* mlt = 0;
1058
1059         if (pls == AudioTime) {
1060                 /* add meter-locked tempo */
1061                 mlt = add_tempo_locked (tempo_at_frame_locked (_metrics, frame), pulse,  frame, TempoSection::Ramp, AudioTime, true, true);
1062
1063                 if (!mlt) {
1064                         return 0;
1065                 }
1066
1067         }
1068
1069         MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
1070         bool solved = false;
1071
1072         do_insert (new_meter);
1073
1074         if (recompute) {
1075
1076                 if (pls == AudioTime) {
1077                         solved = solve_map_frame (_metrics, new_meter, frame);
1078                 } else {
1079                         solved = solve_map_bbt (_metrics, new_meter, where);
1080                         /* required due to resetting the pulse of meter-locked tempi above.
1081                            Arguably  solve_map_bbt() should use solve_map_pulse (_metrics, TempoSection) instead,
1082                            but afaict this cannot cause the map to be left unsolved (these tempi are all audio locked).
1083                         */
1084                         recompute_map (_metrics);
1085                 }
1086         }
1087
1088         if (!solved && recompute) {
1089                 /* if this has failed to solve, there is little we can do other than to ensure that
1090                    the new map is recalculated.
1091                 */
1092                 warning << "Adding meter may have left the tempo map unsolved." << endmsg;
1093                 recompute_map (_metrics);
1094         }
1095
1096         return new_meter;
1097 }
1098
1099 void
1100 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
1101 {
1102         Tempo newtempo (beats_per_minute, note_type);
1103         TempoSection* t;
1104
1105         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1106                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1107                         if (!t->active()) {
1108                                 continue;
1109                         }
1110                         {
1111                                 Glib::Threads::RWLock::WriterLock lm (lock);
1112                                 *((Tempo*) t) = newtempo;
1113                                 recompute_map (_metrics);
1114                         }
1115                         PropertyChanged (PropertyChange ());
1116                         break;
1117                 }
1118         }
1119 }
1120
1121 void
1122 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
1123 {
1124         Tempo newtempo (beats_per_minute, note_type);
1125
1126         TempoSection* prev;
1127         TempoSection* first;
1128         Metrics::iterator i;
1129
1130         /* find the TempoSection immediately preceding "where"
1131          */
1132
1133         for (first = 0, i = _metrics.begin(), prev = 0; i != _metrics.end(); ++i) {
1134
1135                 if ((*i)->frame() > where) {
1136                         break;
1137                 }
1138
1139                 TempoSection* t;
1140
1141                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1142                         if (!t->active()) {
1143                                 continue;
1144                         }
1145                         if (!first) {
1146                                 first = t;
1147                         }
1148                         prev = t;
1149                 }
1150         }
1151
1152         if (!prev) {
1153                 if (!first) {
1154                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
1155                         return;
1156                 }
1157
1158                 prev = first;
1159         }
1160
1161         /* reset */
1162
1163         {
1164                 Glib::Threads::RWLock::WriterLock lm (lock);
1165                 /* cannot move the first tempo section */
1166                 *((Tempo*)prev) = newtempo;
1167                 recompute_map (_metrics);
1168         }
1169
1170         PropertyChanged (PropertyChange ());
1171 }
1172
1173 const MeterSection&
1174 TempoMap::first_meter () const
1175 {
1176         const MeterSection *m = 0;
1177
1178         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1179                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
1180                         return *m;
1181                 }
1182         }
1183
1184         fatal << _("programming error: no meter section in tempo map!") << endmsg;
1185         abort(); /*NOTREACHED*/
1186         return *m;
1187 }
1188
1189 MeterSection&
1190 TempoMap::first_meter ()
1191 {
1192         MeterSection *m = 0;
1193
1194         /* CALLER MUST HOLD LOCK */
1195
1196         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1197                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1198                         return *m;
1199                 }
1200         }
1201
1202         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1203         abort(); /*NOTREACHED*/
1204         return *m;
1205 }
1206
1207 const TempoSection&
1208 TempoMap::first_tempo () const
1209 {
1210         const TempoSection *t = 0;
1211
1212         /* CALLER MUST HOLD LOCK */
1213
1214         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1215                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1216                         if (!t->active()) {
1217                                 continue;
1218                         }
1219                         if (!t->movable()) {
1220                                 return *t;
1221                         }
1222                 }
1223         }
1224
1225         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1226         abort(); /*NOTREACHED*/
1227         return *t;
1228 }
1229
1230 TempoSection&
1231 TempoMap::first_tempo ()
1232 {
1233         TempoSection *t = 0;
1234
1235         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1236                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1237                         if (!t->active()) {
1238                                 continue;
1239                         }
1240                         if (!t->movable()) {
1241                                 return *t;
1242                         }
1243                 }
1244         }
1245
1246         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1247         abort(); /*NOTREACHED*/
1248         return *t;
1249 }
1250 void
1251 TempoMap::recompute_tempi (Metrics& metrics)
1252 {
1253         TempoSection* prev_t = 0;
1254
1255         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1256                 TempoSection* t;
1257
1258                 if ((*i)->is_tempo()) {
1259                         t = static_cast<TempoSection*> (*i);
1260                         if (!t->active()) {
1261                                 continue;
1262                         }
1263                         if (!t->movable()) {
1264                                 if (!prev_t) {
1265                                         t->set_pulse (0.0);
1266                                         prev_t = t;
1267                                         continue;
1268                                 }
1269                         }
1270                         if (prev_t) {
1271                                 if (t->position_lock_style() == AudioTime) {
1272                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate));
1273                                         if (!t->locked_to_meter()) {
1274                                                 t->set_pulse (prev_t->pulse_at_tempo (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate));
1275                                         }
1276
1277                                 } else {
1278                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate));
1279                                         t->set_frame (prev_t->frame_at_tempo (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate));
1280
1281                                 }
1282                         }
1283                         prev_t = t;
1284                 }
1285         }
1286         prev_t->set_c_func (0.0);
1287 }
1288
1289 /* tempos must be positioned correctly.
1290    the current approach is to use a meter's bbt time as its base position unit.
1291    an audio-locked meter requires a recomputation of pulse and beat (but not bbt),
1292    while a music-locked meter requires recomputations of frame pulse and beat (but not bbt)
1293 */
1294 void
1295 TempoMap::recompute_meters (Metrics& metrics)
1296 {
1297         MeterSection* meter = 0;
1298         MeterSection* prev_m = 0;
1299
1300         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1301                 if (!(*mi)->is_tempo()) {
1302                         meter = static_cast<MeterSection*> (*mi);
1303                         if (meter->position_lock_style() == AudioTime) {
1304                                 double pulse = 0.0;
1305                                 pair<double, BBT_Time> b_bbt;
1306                                 TempoSection* meter_locked_tempo = 0;
1307                                 for (Metrics::const_iterator ii = metrics.begin(); ii != metrics.end(); ++ii) {
1308                                         TempoSection* t;
1309                                         if ((*ii)->is_tempo()) {
1310                                                 t = static_cast<TempoSection*> (*ii);
1311                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
1312                                                         meter_locked_tempo = t;
1313                                                         break;
1314                                                 }
1315                                         }
1316                                 }
1317
1318                                 if (prev_m) {
1319                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1320                                         if (beats + prev_m->beat() != meter->beat()) {
1321                                                 /* reordering caused a bbt change */
1322                                                 b_bbt = make_pair (beats + prev_m->beat()
1323                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1324                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1325
1326                                         } else if (meter->movable()) {
1327                                                 b_bbt = make_pair (meter->beat(), meter->bbt());
1328                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1329                                         }
1330                                 } else {
1331                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
1332                                 }
1333                                 if (meter_locked_tempo) {
1334                                         meter_locked_tempo->set_pulse (pulse);
1335                                 }
1336                                 meter->set_beat (b_bbt);
1337                                 meter->set_pulse (pulse);
1338
1339                         } else {
1340                                 /* MusicTime */
1341                                 double pulse = 0.0;
1342                                 pair<double, BBT_Time> b_bbt;
1343                                 if (prev_m) {
1344                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1345                                         if (beats + prev_m->beat() != meter->beat()) {
1346                                                 /* reordering caused a bbt change */
1347                                                 b_bbt = make_pair (beats + prev_m->beat()
1348                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1349                                         } else {
1350                                                 b_bbt = make_pair (beats + prev_m->beat(), meter->bbt());
1351                                         }
1352                                         pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
1353                                 } else {
1354                                         /* shouldn't happen - the first is audio-locked */
1355                                         pulse = pulse_at_beat_locked (metrics, meter->beat());
1356                                         b_bbt = make_pair (meter->beat(), meter->bbt());
1357                                 }
1358
1359                                 meter->set_beat (b_bbt);
1360                                 meter->set_pulse (pulse);
1361                                 meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1362                         }
1363
1364                         prev_m = meter;
1365                 }
1366         }
1367 }
1368
1369 void
1370 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1371 {
1372         /* CALLER MUST HOLD WRITE LOCK */
1373
1374         if (end < 0) {
1375
1376                 /* we will actually stop once we hit
1377                    the last metric.
1378                 */
1379                 end = max_framepos;
1380
1381         }
1382
1383         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1384
1385         if (end == 0) {
1386                 /* silly call from Session::process() during startup
1387                  */
1388                 return;
1389         }
1390
1391         recompute_tempi (metrics);
1392         recompute_meters (metrics);
1393 }
1394
1395 TempoMetric
1396 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1397 {
1398         Glib::Threads::RWLock::ReaderLock lm (lock);
1399         TempoMetric m (first_meter(), first_tempo());
1400
1401         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1402            at something, because we insert the default tempo and meter during
1403            TempoMap construction.
1404
1405            now see if we can find better candidates.
1406         */
1407
1408         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1409
1410                 if ((*i)->frame() > frame) {
1411                         break;
1412                 }
1413
1414                 m.set_metric(*i);
1415
1416                 if (last) {
1417                         *last = i;
1418                 }
1419         }
1420
1421         return m;
1422 }
1423
1424 /* XX meters only */
1425 TempoMetric
1426 TempoMap::metric_at (BBT_Time bbt) const
1427 {
1428         Glib::Threads::RWLock::ReaderLock lm (lock);
1429         TempoMetric m (first_meter(), first_tempo());
1430
1431         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1432            at something, because we insert the default tempo and meter during
1433            TempoMap construction.
1434
1435            now see if we can find better candidates.
1436         */
1437
1438         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1439                 MeterSection* mw;
1440                 if (!(*i)->is_tempo()) {
1441                         mw = static_cast<MeterSection*> (*i);
1442                         BBT_Time section_start (mw->bbt());
1443
1444                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1445                                 break;
1446                         }
1447
1448                         m.set_metric (*i);
1449                 }
1450         }
1451
1452         return m;
1453 }
1454
1455 /** Returns the beat duration corresponding to the supplied frame, possibly returning a negative value.
1456  * @param frame The session frame position.
1457  * @return The beat duration according to the tempo map at the supplied frame.
1458  * If the supplied frame lies before the first meter, the returned beat duration will be negative.
1459  * The returned beat is obtained using the first meter and the continuation of the tempo curve (backwards).
1460  *
1461  * This function uses both tempo and meter.
1462  */
1463 double
1464 TempoMap::beat_at_frame (const framecnt_t& frame) const
1465 {
1466         Glib::Threads::RWLock::ReaderLock lm (lock);
1467         return beat_at_frame_locked (_metrics, frame);
1468 }
1469
1470 /* This function uses both tempo and meter.*/
1471 double
1472 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1473 {
1474         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
1475         MeterSection* prev_m = 0;
1476         MeterSection* next_m = 0;
1477
1478         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1479                 if (!(*i)->is_tempo()) {
1480                         if (prev_m && (*i)->frame() > frame) {
1481                                 next_m = static_cast<MeterSection*> (*i);
1482                                 break;
1483                         }
1484                         prev_m = static_cast<MeterSection*> (*i);
1485                 }
1486         }
1487
1488         const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
1489
1490         /* audio locked meters fake their beat */
1491         if (next_m && next_m->beat() < beat) {
1492                 return next_m->beat();
1493         }
1494
1495         return beat;
1496 }
1497
1498 framepos_t
1499 TempoMap::frame_at_beat (const double& beat) const
1500 {
1501         Glib::Threads::RWLock::ReaderLock lm (lock);
1502         return frame_at_beat_locked (_metrics, beat);
1503 }
1504
1505 /* meter & tempo section based */
1506 framepos_t
1507 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1508 {
1509         MeterSection* prev_m = 0;
1510         TempoSection* prev_t = 0;
1511
1512         MeterSection* m;
1513
1514         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1515                 if (!(*i)->is_tempo()) {
1516                         m = static_cast<MeterSection*> (*i);
1517                         if (prev_m && m->beat() > beat) {
1518                                 break;
1519                         }
1520                         prev_m = m;
1521                 }
1522         }
1523
1524         TempoSection* t;
1525
1526         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1527                 if ((*i)->is_tempo()) {
1528                         t = static_cast<TempoSection*> (*i);
1529                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
1530                                 break;
1531                         }
1532                         prev_t = t;
1533                 }
1534
1535         }
1536
1537         return prev_t->frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
1538 }
1539
1540 Tempo
1541 TempoMap::tempo_at_frame (const framepos_t& frame) const
1542 {
1543         Glib::Threads::RWLock::ReaderLock lm (lock);
1544         return tempo_at_frame_locked (_metrics, frame);
1545 }
1546
1547 Tempo
1548 TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1549 {
1550         TempoSection* prev_t = 0;
1551
1552         TempoSection* t;
1553
1554         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1555                 if ((*i)->is_tempo()) {
1556                         t = static_cast<TempoSection*> (*i);
1557                         if (!t->active()) {
1558                                 continue;
1559                         }
1560                         if ((prev_t) && t->frame() > frame) {
1561                                 /* t is the section past frame */
1562                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
1563                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
1564                                 return ret_tempo;
1565                         }
1566                         prev_t = t;
1567                 }
1568         }
1569
1570         const double ret = prev_t->beats_per_minute();
1571         const Tempo ret_tempo (ret, prev_t->note_type ());
1572
1573         return ret_tempo;
1574 }
1575
1576 /** returns the frame at which the supplied tempo occurs, or
1577  *  the frame of the last tempo section (search exhausted)
1578  *  only the position of the first occurence will be returned
1579  *  (extend me)
1580 */
1581 framepos_t
1582 TempoMap::frame_at_tempo (const Tempo& tempo) const
1583 {
1584         Glib::Threads::RWLock::ReaderLock lm (lock);
1585         return frame_at_tempo_locked (_metrics, tempo);
1586 }
1587
1588
1589 framepos_t
1590 TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1591 {
1592         TempoSection* prev_t = 0;
1593         const double tempo_ppm = tempo.beats_per_minute() / tempo.note_type();
1594
1595         Metrics::const_iterator i;
1596
1597         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
1598                 TempoSection* t;
1599                 if ((*i)->is_tempo()) {
1600                         t = static_cast<TempoSection*> (*i);
1601
1602                         if (!t->active()) {
1603                                 continue;
1604                         }
1605
1606                         const double t_ppm = t->beats_per_minute() / t->note_type();
1607
1608                         if (t_ppm == tempo_ppm) {
1609                                 return t->frame();
1610                         }
1611
1612                         if (prev_t) {
1613                                 const double prev_t_ppm = prev_t->beats_per_minute() / prev_t->note_type();
1614
1615                                 if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) {
1616                                         return prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate);
1617                                 }
1618                         }
1619                         prev_t = t;
1620                 }
1621         }
1622
1623         return prev_t->frame();
1624 }
1625
1626 /** more precise than doing tempo_at_frame (frame_at_beat (b)),
1627  *  as there is no intermediate frame rounding.
1628  */
1629 Tempo
1630 TempoMap::tempo_at_beat (const double& beat) const
1631 {
1632         Glib::Threads::RWLock::ReaderLock lm (lock);
1633         const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
1634         const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
1635         const double note_type = prev_t->note_type();
1636
1637         return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()) * note_type, note_type);
1638 }
1639
1640 double
1641 TempoMap::pulse_at_beat (const double& beat) const
1642 {
1643         Glib::Threads::RWLock::ReaderLock lm (lock);
1644         return pulse_at_beat_locked (_metrics, beat);
1645 }
1646
1647 double
1648 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1649 {
1650         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1651
1652         return prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1653 }
1654
1655 double
1656 TempoMap::beat_at_pulse (const double& pulse) const
1657 {
1658         Glib::Threads::RWLock::ReaderLock lm (lock);
1659         return beat_at_pulse_locked (_metrics, pulse);
1660 }
1661
1662 double
1663 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1664 {
1665         MeterSection* prev_m = 0;
1666
1667         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1668                 MeterSection* m;
1669                 if (!(*i)->is_tempo()) {
1670                         m = static_cast<MeterSection*> (*i);
1671                         if (prev_m && m->pulse() > pulse) {
1672                                 break;
1673                         }
1674                         prev_m = m;
1675                 }
1676         }
1677
1678         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1679         return ret;
1680 }
1681
1682 double
1683 TempoMap::pulse_at_frame (const framepos_t& frame) const
1684 {
1685         Glib::Threads::RWLock::ReaderLock lm (lock);
1686         return pulse_at_frame_locked (_metrics, frame);
1687 }
1688
1689 /* tempo section based */
1690 double
1691 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1692 {
1693         /* HOLD (at least) THE READER LOCK */
1694         TempoSection* prev_t = 0;
1695
1696         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1697                 TempoSection* t;
1698                 if ((*i)->is_tempo()) {
1699                         t = static_cast<TempoSection*> (*i);
1700                         if (!t->active()) {
1701                                 continue;
1702                         }
1703                         if (prev_t && t->frame() > frame) {
1704                                 /*the previous ts is the one containing the frame */
1705                                 const double ret = prev_t->pulse_at_frame (frame, _frame_rate);
1706                                 /* audio locked section in new meter*/
1707                                 if (t->pulse() < ret) {
1708                                         return t->pulse();
1709                                 }
1710                                 return ret;
1711                         }
1712                         prev_t = t;
1713                 }
1714         }
1715
1716         /* treated as constant for this ts */
1717         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1718
1719         return pulses_in_section + prev_t->pulse();
1720 }
1721
1722 framepos_t
1723 TempoMap::frame_at_pulse (const double& pulse) const
1724 {
1725         Glib::Threads::RWLock::ReaderLock lm (lock);
1726         return frame_at_pulse_locked (_metrics, pulse);
1727 }
1728
1729 /* tempo section based */
1730 framepos_t
1731 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1732 {
1733         /* HOLD THE READER LOCK */
1734
1735         const TempoSection* prev_t = 0;
1736
1737         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1738                 TempoSection* t;
1739
1740                 if ((*i)->is_tempo()) {
1741                         t = static_cast<TempoSection*> (*i);
1742                         if (!t->active()) {
1743                                 continue;
1744                         }
1745                         if (prev_t && t->pulse() > pulse) {
1746                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1747                         }
1748
1749                         prev_t = t;
1750                 }
1751         }
1752         /* must be treated as constant, irrespective of _type */
1753         double const dtime = (pulse - prev_t->pulse()) * prev_t->frames_per_pulse (_frame_rate);
1754
1755         return (framepos_t) floor (dtime) + prev_t->frame();
1756 }
1757
1758 double
1759 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1760 {
1761         Glib::Threads::RWLock::ReaderLock lm (lock);
1762         return beat_at_bbt_locked (_metrics, bbt);
1763 }
1764
1765
1766 double
1767 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1768 {
1769         /* CALLER HOLDS READ LOCK */
1770
1771         MeterSection* prev_m = 0;
1772
1773         /* because audio-locked meters have 'fake' integral beats,
1774            there is no pulse offset here.
1775         */
1776         MeterSection* m;
1777
1778         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1779                 if (!(*i)->is_tempo()) {
1780                         m = static_cast<MeterSection*> (*i);
1781                         if (prev_m) {
1782                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1783                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1784                                         break;
1785                                 }
1786                         }
1787                         prev_m = m;
1788                 }
1789         }
1790
1791         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1792         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1793         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1794
1795         return ret;
1796 }
1797
1798 Timecode::BBT_Time
1799 TempoMap::bbt_at_beat (const double& beats)
1800 {
1801         Glib::Threads::RWLock::ReaderLock lm (lock);
1802         return bbt_at_beat_locked (_metrics, beats);
1803 }
1804
1805 Timecode::BBT_Time
1806 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1807 {
1808         /* CALLER HOLDS READ LOCK */
1809         MeterSection* prev_m = 0;
1810         const double beats = max (0.0, b);
1811
1812         MeterSection* m = 0;
1813
1814         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1815                 if (!(*i)->is_tempo()) {
1816                         m = static_cast<MeterSection*> (*i);
1817                         if (prev_m) {
1818                                 if (m->beat() > beats) {
1819                                         /* this is the meter after the one our beat is on*/
1820                                         break;
1821                                 }
1822                         }
1823
1824                         prev_m = m;
1825                 }
1826         }
1827
1828         const double beats_in_ms = beats - prev_m->beat();
1829         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1830         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1831         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1832         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1833
1834         BBT_Time ret;
1835
1836         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1837         ret.beats = (uint32_t) floor (remaining_beats);
1838         ret.bars = total_bars;
1839
1840         /* 0 0 0 to 1 1 0 - based mapping*/
1841         ++ret.bars;
1842         ++ret.beats;
1843
1844         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1845                 ++ret.beats;
1846                 ret.ticks -= BBT_Time::ticks_per_beat;
1847         }
1848
1849         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1850                 ++ret.bars;
1851                 ret.beats = 1;
1852         }
1853
1854         return ret;
1855 }
1856
1857 double
1858 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1859 {
1860         Glib::Threads::RWLock::ReaderLock lm (lock);
1861
1862         return pulse_at_bbt_locked (_metrics, bbt);
1863 }
1864
1865 double
1866 TempoMap::pulse_at_bbt_rt (const Timecode::BBT_Time& bbt)
1867 {
1868         Glib::Threads::RWLock::ReaderLock lm (lock);
1869
1870         if (!lm.locked()) {
1871                 throw std::logic_error ("TempoMap::pulse_at_bbt_rt() could not lock tempo map");
1872         }
1873
1874         return pulse_at_bbt_locked (_metrics, bbt);
1875 }
1876
1877 double
1878 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1879 {
1880         /* CALLER HOLDS READ LOCK */
1881
1882         MeterSection* prev_m = 0;
1883
1884         /* because audio-locked meters have 'fake' integral beats,
1885            there is no pulse offset here.
1886         */
1887         MeterSection* m;
1888
1889         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1890                 if (!(*i)->is_tempo()) {
1891                         m = static_cast<MeterSection*> (*i);
1892                         if (prev_m) {
1893                                 if (m->bbt().bars > bbt.bars) {
1894                                         break;
1895                                 }
1896                         }
1897                         prev_m = m;
1898                 }
1899         }
1900
1901         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1902         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1903         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1904
1905         return ret;
1906 }
1907
1908 Timecode::BBT_Time
1909 TempoMap::bbt_at_pulse (const double& pulse)
1910 {
1911         Glib::Threads::RWLock::ReaderLock lm (lock);
1912
1913         return bbt_at_pulse_locked (_metrics, pulse);
1914 }
1915
1916 Timecode::BBT_Time
1917 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1918 {
1919         MeterSection* prev_m = 0;
1920
1921         MeterSection* m = 0;
1922
1923         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1924
1925                 if (!(*i)->is_tempo()) {
1926                         m = static_cast<MeterSection*> (*i);
1927
1928                         if (prev_m) {
1929                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1930                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1931                                         /* this is the meter after the one our beat is on*/
1932                                         break;
1933                                 }
1934                         }
1935
1936                         prev_m = m;
1937                 }
1938         }
1939
1940         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1941         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1942         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1943         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1944         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1945
1946         BBT_Time ret;
1947
1948         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1949         ret.beats = (uint32_t) floor (remaining_beats);
1950         ret.bars = total_bars;
1951
1952         /* 0 0 0 to 1 1 0 mapping*/
1953         ++ret.bars;
1954         ++ret.beats;
1955
1956         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1957                 ++ret.beats;
1958                 ret.ticks -= BBT_Time::ticks_per_beat;
1959         }
1960
1961         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1962                 ++ret.bars;
1963                 ret.beats = 1;
1964         }
1965
1966         return ret;
1967 }
1968
1969 BBT_Time
1970 TempoMap::bbt_at_frame (framepos_t frame)
1971 {
1972         if (frame < 0) {
1973                 BBT_Time bbt;
1974                 bbt.bars = 1;
1975                 bbt.beats = 1;
1976                 bbt.ticks = 0;
1977                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1978                 return bbt;
1979         }
1980         Glib::Threads::RWLock::ReaderLock lm (lock);
1981
1982         return bbt_at_frame_locked (_metrics, frame);
1983 }
1984
1985 BBT_Time
1986 TempoMap::bbt_at_frame_rt (framepos_t frame)
1987 {
1988         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1989
1990         if (!lm.locked()) {
1991                 throw std::logic_error ("TempoMap::bbt_at_frame_rt() could not lock tempo map");
1992         }
1993
1994         return bbt_at_frame_locked (_metrics, frame);
1995 }
1996
1997 Timecode::BBT_Time
1998 TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1999 {
2000         if (frame < 0) {
2001                 BBT_Time bbt;
2002                 bbt.bars = 1;
2003                 bbt.beats = 1;
2004                 bbt.ticks = 0;
2005                 return bbt;
2006         }
2007
2008         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
2009         MeterSection* prev_m = 0;
2010         MeterSection* next_m = 0;
2011
2012         MeterSection* m;
2013
2014         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2015                 if (!(*i)->is_tempo()) {
2016                         m = static_cast<MeterSection*> (*i);
2017                         if (prev_m && m->frame() > frame) {
2018                                 next_m = m;
2019                                 break;
2020                         }
2021                         prev_m = m;
2022                 }
2023         }
2024
2025         double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
2026
2027         /* handle frame before first meter */
2028         if (frame < prev_m->frame()) {
2029                 beat = 0.0;
2030         }
2031         /* audio locked meters fake their beat */
2032         if (next_m && next_m->beat() < beat) {
2033                 beat = next_m->beat();
2034         }
2035
2036         beat = max (0.0, beat);
2037
2038         const double beats_in_ms = beat - prev_m->beat();
2039         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2040         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2041         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2042         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2043
2044         BBT_Time ret;
2045
2046         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2047         ret.beats = (uint32_t) floor (remaining_beats);
2048         ret.bars = total_bars;
2049
2050         /* 0 0 0 to 1 1 0 - based mapping*/
2051         ++ret.bars;
2052         ++ret.beats;
2053
2054         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2055                 ++ret.beats;
2056                 ret.ticks -= BBT_Time::ticks_per_beat;
2057         }
2058
2059         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2060                 ++ret.bars;
2061                 ret.beats = 1;
2062         }
2063
2064         return ret;
2065 }
2066
2067 framepos_t
2068 TempoMap::frame_at_bbt (const BBT_Time& bbt)
2069 {
2070         if (bbt.bars < 1) {
2071                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
2072                 return 0;
2073         }
2074
2075         if (bbt.beats < 1) {
2076                 throw std::logic_error ("beats are counted from one");
2077         }
2078         Glib::Threads::RWLock::ReaderLock lm (lock);
2079
2080         return frame_at_bbt_locked (_metrics, bbt);
2081 }
2082
2083 /* meter & tempo section based */
2084 framepos_t
2085 TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
2086 {
2087         /* HOLD THE READER LOCK */
2088
2089         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
2090         return ret;
2091 }
2092
2093 /**
2094  * Returns the distance from 0 in quarter pulses at the supplied frame.
2095  *
2096  * Plugin APIs don't count ticks in the same way PROGRAM_NAME does.
2097  * We use ticks per beat whereas the rest of the world uses ticks per quarter note.
2098  * This is more or less the VST's ppqPos (a scalar you use to obtain tick position
2099  * in whatever ppqn you're using).
2100  *
2101  * @param frame The distance in frames relative to session 0 whose quarter note distance you would like.
2102  * @return The quarter note (quarter pulse) distance from session 0 to the supplied frame. Ignores meter.
2103 */
2104
2105 double
2106 TempoMap::quarter_note_at_frame (const framepos_t frame)
2107 {
2108         Glib::Threads::RWLock::ReaderLock lm (lock);
2109
2110         const double ret = quarter_note_at_frame_locked (_metrics, frame);
2111
2112         return ret;
2113 }
2114
2115 double
2116 TempoMap::quarter_note_at_frame_locked (const Metrics& metrics, const framepos_t frame) const
2117 {
2118         const double ret = pulse_at_frame_locked (metrics, frame) * 4.0;
2119
2120         return ret;
2121 }
2122
2123 double
2124 TempoMap::quarter_note_at_frame_rt (const framepos_t frame)
2125 {
2126         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2127
2128         if (!lm.locked()) {
2129                 throw std::logic_error ("TempoMap::quarter_note_at_frame_rt() could not lock tempo map");
2130         }
2131
2132         const double ret = pulse_at_frame_locked (_metrics, frame) * 4.0;
2133
2134         return ret;
2135 }
2136
2137 framepos_t
2138 TempoMap::frame_at_quarter_note (const double quarter_note)
2139 {
2140         Glib::Threads::RWLock::ReaderLock lm (lock);
2141
2142         const framepos_t ret = frame_at_quarter_note_locked (_metrics, quarter_note);
2143
2144         return ret;
2145 }
2146
2147 framepos_t
2148 TempoMap::frame_at_quarter_note_locked (const Metrics& metrics, const double quarter_note) const
2149 {
2150         const framepos_t ret = frame_at_pulse_locked (metrics, quarter_note / 4.0);
2151
2152         return ret;
2153 }
2154
2155 double
2156 TempoMap::quarter_note_at_beat (const double beat)
2157 {
2158         Glib::Threads::RWLock::ReaderLock lm (lock);
2159
2160         const double ret = quarter_note_at_beat_locked (_metrics, beat);
2161
2162         return ret;
2163 }
2164
2165 double
2166 TempoMap::quarter_note_at_beat_locked (const Metrics& metrics, const double beat) const
2167 {
2168         const double ret = pulse_at_beat_locked (metrics, beat) * 4.0;
2169
2170         return ret;
2171 }
2172
2173 double
2174 TempoMap::beat_at_quarter_note (const double quarter_note)
2175 {
2176         Glib::Threads::RWLock::ReaderLock lm (lock);
2177
2178         const double ret = beat_at_quarter_note_locked (_metrics, quarter_note);
2179
2180         return ret;
2181 }
2182 double
2183 TempoMap::beat_at_quarter_note_locked (const Metrics& metrics, const double quarter_note) const
2184 {
2185         const double ret = beat_at_pulse_locked (metrics, quarter_note / 4.0);
2186
2187         return ret;
2188 }
2189
2190 bool
2191 TempoMap::check_solved (const Metrics& metrics) const
2192 {
2193         TempoSection* prev_t = 0;
2194         MeterSection* prev_m = 0;
2195
2196         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2197                 TempoSection* t;
2198                 MeterSection* m;
2199                 if ((*i)->is_tempo()) {
2200                         t = static_cast<TempoSection*> (*i);
2201                         if (!t->active()) {
2202                                 continue;
2203                         }
2204                         if (prev_t) {
2205                                 /* check ordering */
2206                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
2207                                         return false;
2208                                 }
2209
2210                                 /* precision check ensures tempo and frames align.*/
2211                                 if (t->frame() != prev_t->frame_at_tempo (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate)) {
2212                                         if (!t->locked_to_meter()) {
2213                                                 return false;
2214                                         }
2215                                 }
2216
2217                                 /* gradient limit - who knows what it should be?
2218                                    things are also ok (if a little chaotic) without this
2219                                 */
2220                                 if (fabs (prev_t->c_func()) > 1000.0) {
2221                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
2222                                         return false;
2223                                 }
2224                         }
2225                         prev_t = t;
2226                 }
2227
2228                 if (!(*i)->is_tempo()) {
2229                         m = static_cast<MeterSection*> (*i);
2230                         if (prev_m && m->position_lock_style() == AudioTime) {
2231                                 const TempoSection* t = &tempo_section_at_frame_locked (metrics, m->frame() - 1);
2232                                 const framepos_t nascent_m_frame = t->frame_at_pulse (m->pulse(), _frame_rate);
2233                                 /* Here we check that a preceding section of music doesn't overlap a subsequent one.
2234                                    It is complicated by the fact that audio locked meters represent a discontinuity in the pulse
2235                                    (they place an exact pulse at a particular time expressed only in frames).
2236                                    This has the effect of shifting the calculated frame at the meter pulse (wrt the previous section of music)
2237                                    away from its actual frame (which is now the frame location of the exact pulse).
2238                                    This can result in the calculated frame (from the previous musical section)
2239                                    differing from the exact frame by one sample.
2240                                    Allow for that.
2241                                 */
2242                                 if (t && (nascent_m_frame > m->frame() + 1 || nascent_m_frame < 0)) {
2243                                         return false;
2244                                 }
2245                         }
2246
2247                         prev_m = m;
2248                 }
2249
2250         }
2251
2252         return true;
2253 }
2254
2255 bool
2256 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
2257 {
2258         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2259                 TempoSection* t;
2260                 if ((*i)->is_tempo()) {
2261                         t = static_cast<TempoSection*> (*i);
2262                         if (!t->movable()) {
2263                                 t->set_active (true);
2264                                 continue;
2265                         }
2266                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
2267                                 t->set_active (false);
2268                                 t->set_pulse (0.0);
2269                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
2270                                 t->set_active (true);
2271                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
2272                                 return false;
2273                         }
2274                 }
2275         }
2276         return true;
2277 }
2278
2279 bool
2280 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
2281 {
2282         TempoSection* prev_t = 0;
2283         TempoSection* section_prev = 0;
2284         framepos_t first_m_frame = 0;
2285
2286         /* can't move a tempo before the first meter */
2287         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2288                 MeterSection* m;
2289                 if (!(*i)->is_tempo()) {
2290                         m = static_cast<MeterSection*> (*i);
2291                         if (!m->movable()) {
2292                                 first_m_frame = m->frame();
2293                                 break;
2294                         }
2295                 }
2296         }
2297         if (section->movable() && frame <= first_m_frame) {
2298                 return false;
2299         }
2300
2301         section->set_active (true);
2302         section->set_frame (frame);
2303
2304         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2305                 TempoSection* t;
2306                 if ((*i)->is_tempo()) {
2307                         t = static_cast<TempoSection*> (*i);
2308
2309                         if (!t->active()) {
2310                                 continue;
2311                         }
2312                         if (prev_t) {
2313                                 if (t == section) {
2314                                         section_prev = prev_t;
2315                                         if (t->locked_to_meter()) {
2316                                                 prev_t = t;
2317                                         }
2318                                         continue;
2319                                 }
2320                                 if (t->position_lock_style() == MusicTime) {
2321                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate));
2322                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2323                                 } else {
2324                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate));
2325                                         if (!t->locked_to_meter()) {
2326                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2327                                         }
2328                                 }
2329                         }
2330                         prev_t = t;
2331                 }
2332         }
2333
2334         if (section_prev) {
2335                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->beats_per_minute() / section_prev->note_type(), frame, _frame_rate));
2336                 if (!section->locked_to_meter()) {
2337                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2338                 }
2339         }
2340
2341 #if (0)
2342         recompute_tempi (imaginary);
2343
2344         if (check_solved (imaginary)) {
2345                 return true;
2346         } else {
2347                 dunp (imaginary, std::cout);
2348         }
2349 #endif
2350
2351         MetricSectionFrameSorter fcmp;
2352         imaginary.sort (fcmp);
2353
2354         recompute_tempi (imaginary);
2355
2356         if (check_solved (imaginary)) {
2357                 return true;
2358         }
2359
2360         return false;
2361 }
2362
2363 bool
2364 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2365 {
2366         TempoSection* prev_t = 0;
2367         TempoSection* section_prev = 0;
2368
2369         section->set_pulse (pulse);
2370
2371         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2372                 TempoSection* t;
2373                 if ((*i)->is_tempo()) {
2374                         t = static_cast<TempoSection*> (*i);
2375                         if (!t->active()) {
2376                                 continue;
2377                         }
2378                         if (!t->movable()) {
2379                                 t->set_pulse (0.0);
2380                                 prev_t = t;
2381                                 continue;
2382                         }
2383                         if (prev_t) {
2384                                 if (t == section) {
2385                                         section_prev = prev_t;
2386                                         continue;
2387                                 }
2388                                 if (t->position_lock_style() == MusicTime) {
2389                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->beats_per_minute() / prev_t->note_type(), t->pulse(), _frame_rate));
2390                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2391                                 } else {
2392                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->beats_per_minute() / prev_t->note_type(), t->frame(), _frame_rate));
2393                                         if (!t->locked_to_meter()) {
2394                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2395                                         }
2396                                 }
2397                         }
2398                         prev_t = t;
2399                 }
2400         }
2401
2402         if (section_prev) {
2403                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->beats_per_minute() / section_prev->note_type(), pulse, _frame_rate));
2404                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2405         }
2406
2407 #if (0)
2408         recompute_tempi (imaginary);
2409
2410         if (check_solved (imaginary)) {
2411                 return true;
2412         } else {
2413                 dunp (imaginary, std::cout);
2414         }
2415 #endif
2416
2417         MetricSectionSorter cmp;
2418         imaginary.sort (cmp);
2419
2420         recompute_tempi (imaginary);
2421         /* Reordering
2422          * XX need a restriction here, but only for this case,
2423          * as audio locked tempos don't interact in the same way.
2424          *
2425          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2426          * e.g.
2427          * |50 bpm                        |250 bpm |60 bpm
2428          *                drag 250 to the pulse after 60->
2429          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2430          */
2431         if (check_solved (imaginary)) {
2432                 return true;
2433         }
2434
2435         return false;
2436 }
2437
2438 bool
2439 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2440 {
2441         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2442         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2443         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2444                 return false;
2445         }
2446
2447         if (!section->movable()) {
2448                 /* lock the first tempo to our first meter */
2449                 if (!set_active_tempos (imaginary, frame)) {
2450                         return false;
2451                 }
2452         }
2453
2454         TempoSection* meter_locked_tempo = 0;
2455
2456         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2457                 TempoSection* t;
2458                 if ((*ii)->is_tempo()) {
2459                         t = static_cast<TempoSection*> (*ii);
2460                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2461                                 meter_locked_tempo = t;
2462                                 break;
2463                         }
2464                 }
2465         }
2466
2467         if (!meter_locked_tempo) {
2468                 return false;
2469         }
2470
2471         MeterSection* prev_m = 0;
2472         Metrics future_map;
2473         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2474         bool solved = false;
2475
2476         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2477                 MeterSection* m;
2478                 if (!(*i)->is_tempo()) {
2479                         m = static_cast<MeterSection*> (*i);
2480                         if (m == section){
2481                                 if (prev_m && section->movable()) {
2482                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2483                                         if (beats + prev_m->beat() < section->beat()) {
2484                                                 /* set the frame/pulse corresponding to its musical position,
2485                                                  * as an earlier time than this has been requested.
2486                                                 */
2487                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2488                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2489
2490                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2491
2492                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2493                                                         meter_locked_tempo->set_pulse (new_pulse);
2494                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2495                                                         section->set_frame (smallest_frame);
2496                                                         section->set_pulse (new_pulse);
2497                                                 } else {
2498                                                         solved = false;
2499                                                 }
2500
2501                                                 Metrics::const_iterator d = future_map.begin();
2502                                                 while (d != future_map.end()) {
2503                                                         delete (*d);
2504                                                         ++d;
2505                                                 }
2506
2507                                                 if (!solved) {
2508                                                         return false;
2509                                                 }
2510                                         } else {
2511                                                 /* all is ok. set section's locked tempo if allowed.
2512                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2513                                                    XX this check could possibly go. its never actually happened here.
2514                                                 */
2515                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2516                                                 meter_copy->set_frame (frame);
2517
2518                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2519                                                         section->set_frame (frame);
2520                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2521                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2522                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2523                                                 } else {
2524                                                         solved = false;
2525                                                 }
2526
2527                                                 Metrics::const_iterator d = future_map.begin();
2528                                                 while (d != future_map.end()) {
2529                                                         delete (*d);
2530                                                         ++d;
2531                                                 }
2532
2533                                                 if (!solved) {
2534                                                         return false;
2535                                                 }
2536                                         }
2537                                 } else {
2538                                         /* not movable (first meter atm) */
2539
2540                                         tempo_copy->set_frame (frame);
2541                                         tempo_copy->set_pulse (0.0);
2542
2543                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2544                                                 section->set_frame (frame);
2545                                                 meter_locked_tempo->set_frame (frame);
2546                                                 meter_locked_tempo->set_pulse (0.0);
2547                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2548                                         } else {
2549                                                 solved = false;
2550                                         }
2551
2552                                         Metrics::const_iterator d = future_map.begin();
2553                                         while (d != future_map.end()) {
2554                                                 delete (*d);
2555                                                 ++d;
2556                                         }
2557
2558                                         if (!solved) {
2559                                                 return false;
2560                                         }
2561
2562                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2563                                         section->set_beat (b_bbt);
2564                                         section->set_pulse (0.0);
2565
2566                                 }
2567                                 break;
2568                         }
2569
2570                         prev_m = m;
2571                 }
2572         }
2573
2574         MetricSectionFrameSorter fcmp;
2575         imaginary.sort (fcmp);
2576
2577         recompute_meters (imaginary);
2578
2579         return true;
2580 }
2581
2582 bool
2583 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2584 {
2585         /* disallow setting section to an existing meter's bbt */
2586         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2587                 MeterSection* m;
2588                 if (!(*i)->is_tempo()) {
2589                         m = static_cast<MeterSection*> (*i);
2590                         if (m != section && m->bbt().bars == when.bars) {
2591                                 return false;
2592                         }
2593                 }
2594         }
2595
2596         MeterSection* prev_m = 0;
2597         MeterSection* section_prev = 0;
2598
2599         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2600                 MeterSection* m;
2601                 if (!(*i)->is_tempo()) {
2602                         m = static_cast<MeterSection*> (*i);
2603                         pair<double, BBT_Time> b_bbt;
2604                         double new_pulse = 0.0;
2605
2606                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2607                                 section_prev = prev_m;
2608                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2609                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2610                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2611
2612                                 section->set_beat (b_bbt);
2613                                 section->set_pulse (pulse);
2614                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2615                                 prev_m = section;
2616                                 continue;
2617                         }
2618
2619                         if (m->position_lock_style() == AudioTime) {
2620                                 TempoSection* meter_locked_tempo = 0;
2621
2622                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2623                                         TempoSection* t;
2624                                         if ((*ii)->is_tempo()) {
2625                                                 t = static_cast<TempoSection*> (*ii);
2626                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2627                                                         meter_locked_tempo = t;
2628                                                         break;
2629                                                 }
2630                                         }
2631                                 }
2632
2633                                 if (!meter_locked_tempo) {
2634                                         return false;
2635                                 }
2636
2637                                 if (prev_m) {
2638                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2639
2640                                         if (beats + prev_m->beat() != m->beat()) {
2641                                                 /* tempo/ meter change caused a change in beat (bar). */
2642                                                 b_bbt = make_pair (beats + prev_m->beat()
2643                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2644                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2645                                         } else if (m->movable()) {
2646                                                 b_bbt = make_pair (m->beat(), m->bbt());
2647                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2648                                         }
2649                                 } else {
2650                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2651                                 }
2652
2653                                 meter_locked_tempo->set_pulse (new_pulse);
2654                                 m->set_beat (b_bbt);
2655                                 m->set_pulse (new_pulse);
2656
2657                         } else {
2658                                 /* MusicTime */
2659                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2660                                 if (beats + prev_m->beat() != m->beat()) {
2661                                         /* tempo/ meter change caused a change in beat (bar). */
2662                                         b_bbt = make_pair (beats + prev_m->beat()
2663                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2664                                 } else {
2665                                         b_bbt = make_pair (beats + prev_m->beat()
2666                                                            , m->bbt());
2667                                 }
2668                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2669                                 m->set_beat (b_bbt);
2670                                 m->set_pulse (new_pulse);
2671                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2672                         }
2673
2674                         prev_m = m;
2675                 }
2676         }
2677
2678         if (!section_prev) {
2679
2680                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2681                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2682                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2683
2684                 section->set_beat (b_bbt);
2685                 section->set_pulse (pulse);
2686                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2687         }
2688
2689         MetricSectionSorter cmp;
2690         imaginary.sort (cmp);
2691
2692         recompute_meters (imaginary);
2693
2694         return true;
2695 }
2696
2697 /** places a copy of _metrics into copy and returns a pointer
2698  *  to section's equivalent in copy.
2699  */
2700 TempoSection*
2701 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2702 {
2703         TempoSection* ret = 0;
2704
2705         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2706                 TempoSection* t;
2707                 MeterSection* m;
2708                 if ((*i)->is_tempo()) {
2709                         t = static_cast<TempoSection*> (*i);
2710                         if (t == section) {
2711                                 ret = new TempoSection (*t);
2712                                 copy.push_back (ret);
2713                                 continue;
2714                         }
2715
2716                         TempoSection* cp = new TempoSection (*t);
2717                         copy.push_back (cp);
2718                 }
2719                 if (!(*i)->is_tempo()) {
2720                         m = static_cast<MeterSection *> (*i);
2721                         MeterSection* cp = new MeterSection (*m);
2722                         copy.push_back (cp);
2723                 }
2724         }
2725
2726         return ret;
2727 }
2728
2729 MeterSection*
2730 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2731 {
2732         MeterSection* ret = 0;
2733
2734         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2735                 TempoSection* t;
2736                 MeterSection* m;
2737                 if ((*i)->is_tempo()) {
2738                         t = static_cast<TempoSection*> (*i);
2739                         TempoSection* cp = new TempoSection (*t);
2740                         copy.push_back (cp);
2741                 }
2742
2743                 if (!(*i)->is_tempo()) {
2744                         m = static_cast<MeterSection *> (*i);
2745                         if (m == section) {
2746                                 ret = new MeterSection (*m);
2747                                 copy.push_back (ret);
2748                                 continue;
2749                         }
2750                         MeterSection* cp = new MeterSection (*m);
2751                         copy.push_back (cp);
2752                 }
2753         }
2754
2755         return ret;
2756 }
2757
2758 /** answers the question "is this a valid beat position for this tempo section?".
2759  *  it returns true if the tempo section can be moved to the requested bbt position,
2760  *  leaving the tempo map in a solved state.
2761  * @param section the tempo section to be moved
2762  * @param bbt the requested new position for the tempo section
2763  * @return true if the tempo section can be moved to the position, otherwise false.
2764  */
2765 bool
2766 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2767 {
2768         Metrics copy;
2769         TempoSection* tempo_copy = 0;
2770
2771         {
2772                 Glib::Threads::RWLock::ReaderLock lm (lock);
2773                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2774                 if (!tempo_copy) {
2775                         return false;
2776                 }
2777         }
2778
2779         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2780
2781         Metrics::const_iterator d = copy.begin();
2782         while (d != copy.end()) {
2783                 delete (*d);
2784                 ++d;
2785         }
2786
2787         return ret;
2788 }
2789
2790 /**
2791 * 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,
2792 * taking any possible reordering as a consequence of this into account.
2793 * @param section - the section to be altered
2794 * @param bbt - the bbt where the altered tempo will fall
2795 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2796 */
2797 pair<double, framepos_t>
2798 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2799 {
2800         Metrics future_map;
2801         pair<double, framepos_t> ret = make_pair (0.0, 0);
2802
2803         Glib::Threads::RWLock::ReaderLock lm (lock);
2804
2805         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2806
2807         const double beat = beat_at_bbt_locked (future_map, bbt);
2808
2809         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2810                 ret.first = tempo_copy->pulse();
2811                 ret.second = tempo_copy->frame();
2812         } else {
2813                 ret.first = section->pulse();
2814                 ret.second = section->frame();
2815         }
2816
2817         Metrics::const_iterator d = future_map.begin();
2818         while (d != future_map.end()) {
2819                 delete (*d);
2820                 ++d;
2821         }
2822         return ret;
2823 }
2824
2825 void
2826 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame, const int& sub_num)
2827 {
2828         Metrics future_map;
2829
2830         if (ts->position_lock_style() == MusicTime) {
2831                 {
2832                         /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
2833                         Glib::Threads::RWLock::WriterLock lm (lock);
2834                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2835
2836                         tempo_copy->set_position_lock_style (AudioTime);
2837
2838                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2839                                 const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
2840                                 const double pulse = pulse_at_beat_locked (future_map, beat);
2841
2842                                 if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2843                                         solve_map_pulse (_metrics, ts, pulse);
2844                                         recompute_meters (_metrics);
2845                                 }
2846                         }
2847                 }
2848
2849         } else {
2850
2851                 {
2852                         Glib::Threads::RWLock::WriterLock lm (lock);
2853                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2854
2855                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2856                                 if (sub_num != 0) {
2857                                         /* We're moving the object that defines the grid while snapping to it...
2858                                          * Placing the ts at the beat corresponding to the requested frame may shift the
2859                                          * grid in such a way that the mouse is left hovering over a completerly different division,
2860                                          * causing jittering when the mouse next moves (esp. large tempo deltas).
2861                                          * To avoid this, place the ts at the requested frame in a dummy map
2862                                          * then find the closest beat subdivision to that frame in the dummy.
2863                                          * This alters the snap behaviour slightly in that we snap to beat divisions
2864                                          * in the future map rather than the existing one.
2865                                          */
2866                                         const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
2867                                         const double pulse = pulse_at_beat_locked (future_map, beat);
2868
2869                                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2870                                                 /* snapping to a grid. force MusicTime temporarily. */
2871                                                 ts->set_position_lock_style (MusicTime);
2872                                                 solve_map_pulse (_metrics, ts, pulse);
2873                                                 ts->set_position_lock_style (AudioTime);
2874
2875                                                 recompute_meters (_metrics);
2876                                         }
2877                                 } else {
2878                                         solve_map_frame (_metrics, ts, frame);
2879                                         recompute_meters (_metrics);
2880                                 }
2881                         }
2882                 }
2883         }
2884
2885         Metrics::const_iterator d = future_map.begin();
2886         while (d != future_map.end()) {
2887                 delete (*d);
2888                 ++d;
2889         }
2890
2891         MetricPositionChanged (); // Emit Signal
2892 }
2893
2894 void
2895 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2896 {
2897         Metrics future_map;
2898
2899         if (ms->position_lock_style() == AudioTime) {
2900
2901                 {
2902                         Glib::Threads::RWLock::WriterLock lm (lock);
2903                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2904
2905                         if (solve_map_frame (future_map, copy, frame)) {
2906                                 solve_map_frame (_metrics, ms, frame);
2907                                 recompute_tempi (_metrics);
2908                         }
2909                 }
2910         } else {
2911                 {
2912                         Glib::Threads::RWLock::WriterLock lm (lock);
2913                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2914
2915                         const double beat = beat_at_frame_locked (_metrics, frame);
2916                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2917
2918                         if (solve_map_bbt (future_map, copy, bbt)) {
2919                                 solve_map_bbt (_metrics, ms, bbt);
2920                                 recompute_tempi (_metrics);
2921                         }
2922                 }
2923         }
2924
2925         Metrics::const_iterator d = future_map.begin();
2926         while (d != future_map.end()) {
2927                 delete (*d);
2928                 ++d;
2929         }
2930
2931         MetricPositionChanged (); // Emit Signal
2932 }
2933
2934 bool
2935 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2936 {
2937         Metrics future_map;
2938         bool can_solve = false;
2939         {
2940                 Glib::Threads::RWLock::WriterLock lm (lock);
2941                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2942                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2943                 recompute_tempi (future_map);
2944
2945                 if (check_solved (future_map)) {
2946                         ts->set_beats_per_minute (bpm.beats_per_minute());
2947                         recompute_map (_metrics);
2948                         can_solve = true;
2949                 }
2950         }
2951
2952         Metrics::const_iterator d = future_map.begin();
2953         while (d != future_map.end()) {
2954                 delete (*d);
2955                 ++d;
2956         }
2957         if (can_solve) {
2958                 MetricPositionChanged (); // Emit Signal
2959         }
2960         return can_solve;
2961 }
2962
2963 void
2964 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2965 {
2966         /*
2967           Ts (future prev_t)   Tnext
2968           |                    |
2969           |     [drag^]        |
2970           |----------|----------
2971                 e_f  pulse(frame)
2972         */
2973
2974         Metrics future_map;
2975
2976         {
2977                 Glib::Threads::RWLock::WriterLock lm (lock);
2978
2979                 if (!ts) {
2980                         return;
2981                 }
2982
2983                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2984                 TempoSection* prev_to_prev_t = 0;
2985                 const frameoffset_t fr_off = end_frame - frame;
2986
2987                 if (prev_t && prev_t->pulse() > 0.0) {
2988                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2989                 }
2990
2991                 TempoSection* next_t = 0;
2992                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2993                         TempoSection* t = 0;
2994                         if ((*i)->is_tempo()) {
2995                                 t = static_cast<TempoSection*> (*i);
2996                                 if (t->frame() > ts->frame()) {
2997                                         next_t = t;
2998                                         break;
2999                                 }
3000                         }
3001                 }
3002                 /* minimum allowed measurement distance in frames */
3003                 const framepos_t min_dframe = 2;
3004
3005                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
3006                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
3007                 */
3008                 double contribution = 0.0;
3009
3010                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3011                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
3012                 }
3013
3014                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
3015
3016                 const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
3017                 const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
3018
3019                 double new_bpm;
3020
3021                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
3022
3023                         if (prev_t->position_lock_style() == MusicTime) {
3024                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3025                                         if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
3026
3027                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
3028                                                                                         / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
3029                                         } else {
3030                                                 new_bpm = prev_t->beats_per_minute();
3031                                         }
3032                                 } else {
3033                                         /* prev to prev is irrelevant */
3034
3035                                         if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
3036                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
3037                                         } else {
3038                                                 new_bpm = prev_t->beats_per_minute();
3039                                         }
3040                                 }
3041                         } else {
3042                                 /* AudioTime */
3043                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3044                                         if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
3045
3046                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
3047                                                                                         / (double) ((end_frame) - prev_to_prev_t->frame()));
3048                                         } else {
3049                                                 new_bpm = prev_t->beats_per_minute();
3050                                         }
3051                                 } else {
3052                                         /* prev_to_prev_t is irrelevant */
3053
3054                                         if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
3055                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
3056                                         } else {
3057                                                 new_bpm = prev_t->beats_per_minute();
3058                                         }
3059                                 }
3060                         }
3061                 } else {
3062
3063                         double frame_ratio = 1.0;
3064                         double pulse_ratio = 1.0;
3065                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
3066
3067                         if (prev_to_prev_t) {
3068                                 if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
3069                                         frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
3070                                 }
3071                                 if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
3072                                         pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
3073                                 }
3074                         } else {
3075                                 if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
3076                                         frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
3077                                 }
3078                                 pulse_ratio = (start_pulse / end_pulse);
3079                         }
3080                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
3081                 }
3082
3083                 /* don't clamp and proceed here.
3084                    testing has revealed that this can go negative,
3085                    which is an entirely different thing to just being too low.
3086                 */
3087                 if (new_bpm < 0.5) {
3088                         return;
3089                 }
3090                 new_bpm = min (new_bpm, (double) 1000.0);
3091                 prev_t->set_beats_per_minute (new_bpm);
3092                 recompute_tempi (future_map);
3093                 recompute_meters (future_map);
3094
3095                 if (check_solved (future_map)) {
3096                         ts->set_beats_per_minute (new_bpm);
3097                         recompute_tempi (_metrics);
3098                         recompute_meters (_metrics);
3099                 }
3100         }
3101
3102         Metrics::const_iterator d = future_map.begin();
3103         while (d != future_map.end()) {
3104                 delete (*d);
3105                 ++d;
3106         }
3107
3108         MetricPositionChanged (); // Emit Signal
3109 }
3110
3111 /** Returns the exact beat corresponding to the bar, beat or quarter note subdivision nearest to
3112  * the supplied frame, possibly returning a negative value.
3113  * @param frame  The session frame position.
3114  * @param sub_num The subdivision to use when rounding the beat.
3115  * A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3116  * Positive integers indicate quarter note (non BBT) divisions.
3117  * 0 indicates that the returned beat should not be rounded.
3118  * @return The beat position of the supplied frame.
3119  * If the supplied frame lies before the first meter, the return will be negative,
3120  * in which case the returned beat uses the first meter (for BBT subdivisions) and
3121  * the continuation of the tempo curve (backwards).
3122  *
3123  * This function uses both tempo and meter.
3124  */
3125 double
3126 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
3127 {
3128         Glib::Threads::RWLock::ReaderLock lm (lock);
3129
3130         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
3131 }
3132
3133 double
3134 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions)
3135 {
3136         return beat_at_pulse_locked (_metrics, exact_qn_at_frame_locked (metrics, frame, divisions) / 4.0);
3137 }
3138
3139 /** Returns the exact quarter note corresponding to the bar, beat or quarter note subdivision nearest to
3140  * the supplied frame, possibly returning a negative value.
3141  * @param frame  The session frame position.
3142  * @param sub_num The subdivision to use when rounding the quarter note.
3143  * A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3144  * Positive integers indicate quarter note (non BBT) divisions.
3145  * 0 indicates that the returned quarter note should not be rounded.
3146  * @return The quarter note position of the supplied frame.
3147  * If the supplied frame lies before the first meter, the return will be negative,
3148  * in which case the returned quarter note uses the first meter (for BBT subdivisions) and
3149  * the continuation of the tempo curve (backwards).
3150  *
3151  * This function uses both tempo and meter.
3152  */
3153 double
3154 TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
3155 {
3156         Glib::Threads::RWLock::ReaderLock lm (lock);
3157
3158         return exact_qn_at_frame_locked (_metrics, frame, sub_num);
3159 }
3160
3161 double
3162 TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
3163 {
3164         double qn = quarter_note_at_frame_locked (metrics, frame);
3165
3166         if (sub_num > 1) {
3167                 qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
3168         } else if (sub_num == 1) {
3169                 /* the gui requested exact musical (BBT) beat */
3170                 qn = quarter_note_at_beat_locked (metrics, floor (beat_at_frame_locked (metrics, frame) + 0.5));
3171         } else if (sub_num == -1) {
3172                 /* snap to  bar */
3173                 Timecode::BBT_Time bbt = bbt_at_pulse_locked (metrics, qn / 4.0);
3174                 bbt.beats = 1;
3175                 bbt.ticks = 0;
3176
3177                 const double prev_b = pulse_at_bbt_locked (_metrics, bbt) * 4.0;
3178                 ++bbt.bars;
3179                 const double next_b = pulse_at_bbt_locked (_metrics, bbt) * 4.0;
3180
3181                 if ((qn - prev_b) > (next_b - prev_b) / 2.0) {
3182                         qn = next_b;
3183                 } else {
3184                         qn = prev_b;
3185                 }
3186         }
3187
3188         return qn;
3189 }
3190
3191 framecnt_t
3192 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
3193 {
3194         Glib::Threads::RWLock::ReaderLock lm (lock);
3195
3196         const double tick_at_time = max (0.0, beat_at_frame_locked (_metrics, pos)) * BBT_Time::ticks_per_beat;
3197         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
3198         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
3199
3200         return frame_at_beat_locked (_metrics, total_beats);
3201 }
3202
3203 framepos_t
3204 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
3205 {
3206         return round_to_type (fr, dir, Bar);
3207 }
3208
3209 framepos_t
3210 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
3211 {
3212         return round_to_type (fr, dir, Beat);
3213 }
3214
3215 framepos_t
3216 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3217 {
3218         Glib::Threads::RWLock::ReaderLock lm (lock);
3219         uint32_t ticks = (uint32_t) floor (max (0.0, beat_at_frame_locked (_metrics, fr)) * BBT_Time::ticks_per_beat);
3220         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3221         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3222
3223         ticks -= beats * BBT_Time::ticks_per_beat;
3224
3225         if (dir > 0) {
3226                 /* round to next (or same iff dir == RoundUpMaybe) */
3227
3228                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3229
3230                 if (mod == 0 && dir == RoundUpMaybe) {
3231                         /* right on the subdivision, which is fine, so do nothing */
3232
3233                 } else if (mod == 0) {
3234                         /* right on the subdivision, so the difference is just the subdivision ticks */
3235                         ticks += ticks_one_subdivisions_worth;
3236
3237                 } else {
3238                         /* not on subdivision, compute distance to next subdivision */
3239
3240                         ticks += ticks_one_subdivisions_worth - mod;
3241                 }
3242
3243                 if (ticks >= BBT_Time::ticks_per_beat) {
3244                         ticks -= BBT_Time::ticks_per_beat;
3245                 }
3246         } else if (dir < 0) {
3247
3248                 /* round to previous (or same iff dir == RoundDownMaybe) */
3249
3250                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3251
3252                 if (difference == 0 && dir == RoundDownAlways) {
3253                         /* right on the subdivision, but force-rounding down,
3254                            so the difference is just the subdivision ticks */
3255                         difference = ticks_one_subdivisions_worth;
3256                 }
3257
3258                 if (ticks < difference) {
3259                         ticks = BBT_Time::ticks_per_beat - ticks;
3260                 } else {
3261                         ticks -= difference;
3262                 }
3263
3264         } else {
3265                 /* round to nearest */
3266                 double rem;
3267
3268                 /* compute the distance to the previous and next subdivision */
3269
3270                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3271
3272                         /* closer to the next subdivision, so shift forward */
3273
3274                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3275
3276                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3277
3278                         if (ticks > BBT_Time::ticks_per_beat) {
3279                                 ++beats;
3280                                 ticks -= BBT_Time::ticks_per_beat;
3281                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3282                         }
3283
3284                 } else if (rem > 0) {
3285
3286                         /* closer to previous subdivision, so shift backward */
3287
3288                         if (rem > ticks) {
3289                                 if (beats == 0) {
3290                                         /* can't go backwards past zero, so ... */
3291                                         return 0;
3292                                 }
3293                                 /* step back to previous beat */
3294                                 --beats;
3295                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3296                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3297                         } else {
3298                                 ticks = lrint (ticks - rem);
3299                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3300                         }
3301                 } else {
3302                         /* on the subdivision, do nothing */
3303                 }
3304         }
3305
3306         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
3307
3308         return ret_frame;
3309 }
3310
3311 framepos_t
3312 TempoMap::round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3313 {
3314         Glib::Threads::RWLock::ReaderLock lm (lock);
3315         uint32_t ticks = (uint32_t) floor (max (0.0, quarter_note_at_frame_locked (_metrics, fr)) * BBT_Time::ticks_per_beat);
3316         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3317         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3318
3319         ticks -= beats * BBT_Time::ticks_per_beat;
3320
3321         if (dir > 0) {
3322                 /* round to next (or same iff dir == RoundUpMaybe) */
3323
3324                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3325
3326                 if (mod == 0 && dir == RoundUpMaybe) {
3327                         /* right on the subdivision, which is fine, so do nothing */
3328
3329                 } else if (mod == 0) {
3330                         /* right on the subdivision, so the difference is just the subdivision ticks */
3331                         ticks += ticks_one_subdivisions_worth;
3332
3333                 } else {
3334                         /* not on subdivision, compute distance to next subdivision */
3335
3336                         ticks += ticks_one_subdivisions_worth - mod;
3337                 }
3338
3339                 if (ticks >= BBT_Time::ticks_per_beat) {
3340                         ticks -= BBT_Time::ticks_per_beat;
3341                 }
3342         } else if (dir < 0) {
3343
3344                 /* round to previous (or same iff dir == RoundDownMaybe) */
3345
3346                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3347
3348                 if (difference == 0 && dir == RoundDownAlways) {
3349                         /* right on the subdivision, but force-rounding down,
3350                            so the difference is just the subdivision ticks */
3351                         difference = ticks_one_subdivisions_worth;
3352                 }
3353
3354                 if (ticks < difference) {
3355                         ticks = BBT_Time::ticks_per_beat - ticks;
3356                 } else {
3357                         ticks -= difference;
3358                 }
3359
3360         } else {
3361                 /* round to nearest */
3362                 double rem;
3363
3364                 /* compute the distance to the previous and next subdivision */
3365
3366                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3367
3368                         /* closer to the next subdivision, so shift forward */
3369
3370                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3371
3372                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3373
3374                         if (ticks > BBT_Time::ticks_per_beat) {
3375                                 ++beats;
3376                                 ticks -= BBT_Time::ticks_per_beat;
3377                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3378                         }
3379
3380                 } else if (rem > 0) {
3381
3382                         /* closer to previous subdivision, so shift backward */
3383
3384                         if (rem > ticks) {
3385                                 if (beats == 0) {
3386                                         /* can't go backwards past zero, so ... */
3387                                         return 0;
3388                                 }
3389                                 /* step back to previous beat */
3390                                 --beats;
3391                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3392                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3393                         } else {
3394                                 ticks = lrint (ticks - rem);
3395                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3396                         }
3397                 } else {
3398                         /* on the subdivision, do nothing */
3399                 }
3400         }
3401
3402         const framepos_t ret_frame = frame_at_quarter_note_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
3403
3404         return ret_frame;
3405 }
3406
3407 framepos_t
3408 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
3409 {
3410         Glib::Threads::RWLock::ReaderLock lm (lock);
3411
3412         const double beat_at_framepos = max (0.0, beat_at_frame_locked (_metrics, frame));
3413         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
3414
3415         switch (type) {
3416         case Bar:
3417                 if (dir < 0) {
3418                         /* find bar previous to 'frame' */
3419                         bbt.beats = 1;
3420                         bbt.ticks = 0;
3421                         return frame_at_bbt_locked (_metrics, bbt);
3422
3423                 } else if (dir > 0) {
3424                         /* find bar following 'frame' */
3425                         ++bbt.bars;
3426                         bbt.beats = 1;
3427                         bbt.ticks = 0;
3428                         return frame_at_bbt_locked (_metrics, bbt);
3429                 } else {
3430                         /* true rounding: find nearest bar */
3431                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
3432                         bbt.beats = 1;
3433                         bbt.ticks = 0;
3434                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
3435                         ++bbt.bars;
3436                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
3437
3438                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
3439                                 return next_ft;
3440                         } else {
3441                                 return prev_ft;
3442                         }
3443                 }
3444
3445                 break;
3446
3447         case Beat:
3448                 if (dir < 0) {
3449                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
3450                 } else if (dir > 0) {
3451                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
3452                 } else {
3453                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
3454                 }
3455                 break;
3456         }
3457
3458         return 0;
3459 }
3460
3461 void
3462 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
3463                     framepos_t lower, framepos_t upper)
3464 {
3465         Glib::Threads::RWLock::ReaderLock lm (lock);
3466         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
3467         framecnt_t pos = 0;
3468         /* although the map handles negative beats, bbt doesn't. */
3469         if (cnt < 0.0) {
3470                 cnt = 0.0;
3471         }
3472
3473         if (frame_at_beat_locked (_metrics, cnt) >= upper) {
3474                 return;
3475         }
3476
3477         while (pos >= 0 && pos < upper) {
3478                 pos = frame_at_beat_locked (_metrics, cnt);
3479                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
3480                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
3481                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
3482                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
3483                 ++cnt;
3484         }
3485 }
3486
3487 const TempoSection&
3488 TempoMap::tempo_section_at_frame (framepos_t frame) const
3489 {
3490         Glib::Threads::RWLock::ReaderLock lm (lock);
3491         return tempo_section_at_frame_locked (_metrics, frame);
3492 }
3493
3494 const TempoSection&
3495 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3496 {
3497         TempoSection* prev = 0;
3498
3499         TempoSection* t;
3500
3501         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3502
3503                 if ((*i)->is_tempo()) {
3504                         t = static_cast<TempoSection*> (*i);
3505                         if (!t->active()) {
3506                                 continue;
3507                         }
3508                         if (prev && t->frame() > frame) {
3509                                 break;
3510                         }
3511
3512                         prev = t;
3513                 }
3514         }
3515
3516         if (prev == 0) {
3517                 fatal << endmsg;
3518                 abort(); /*NOTREACHED*/
3519         }
3520
3521         return *prev;
3522 }
3523
3524 const TempoSection&
3525 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3526 {
3527         TempoSection* prev_t = 0;
3528         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
3529
3530         TempoSection* t;
3531
3532         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3533                 if ((*i)->is_tempo()) {
3534                         t = static_cast<TempoSection*> (*i);
3535                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
3536                                 break;
3537                         }
3538                         prev_t = t;
3539                 }
3540
3541         }
3542         return *prev_t;
3543 }
3544
3545 /* don't use this to calculate length (the tempo is only correct for this frame).
3546    do that stuff based on the beat_at_frame and frame_at_beat api
3547 */
3548 double
3549 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3550 {
3551         Glib::Threads::RWLock::ReaderLock lm (lock);
3552
3553         const TempoSection* ts_at = 0;
3554         const TempoSection* ts_after = 0;
3555         Metrics::const_iterator i;
3556         TempoSection* t;
3557
3558         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3559
3560                 if ((*i)->is_tempo()) {
3561                         t = static_cast<TempoSection*> (*i);
3562                         if (!t->active()) {
3563                                 continue;
3564                         }
3565                         if (ts_at && (*i)->frame() > frame) {
3566                                 ts_after = t;
3567                                 break;
3568                         }
3569                         ts_at = t;
3570                 }
3571         }
3572
3573         if (ts_after) {
3574                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * ts_at->note_type());
3575         }
3576         /* must be treated as constant tempo */
3577         return ts_at->frames_per_beat (_frame_rate);
3578 }
3579
3580 const MeterSection&
3581 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3582 {
3583         Metrics::const_iterator i;
3584         MeterSection* prev = 0;
3585
3586         MeterSection* m;
3587
3588         for (i = metrics.begin(); i != metrics.end(); ++i) {
3589
3590                 if (!(*i)->is_tempo()) {
3591                         m = static_cast<MeterSection*> (*i);
3592
3593                         if (prev && (*i)->frame() > frame) {
3594                                 break;
3595                         }
3596
3597                         prev = m;
3598                 }
3599         }
3600
3601         if (prev == 0) {
3602                 fatal << endmsg;
3603                 abort(); /*NOTREACHED*/
3604         }
3605
3606         return *prev;
3607 }
3608
3609
3610 const MeterSection&
3611 TempoMap::meter_section_at_frame (framepos_t frame) const
3612 {
3613         Glib::Threads::RWLock::ReaderLock lm (lock);
3614         return meter_section_at_frame_locked (_metrics, frame);
3615 }
3616
3617 const MeterSection&
3618 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3619 {
3620         MeterSection* prev_m = 0;
3621
3622         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3623                 MeterSection* m;
3624                 if (!(*i)->is_tempo()) {
3625                         m = static_cast<MeterSection*> (*i);
3626                         if (prev_m && m->beat() > beat) {
3627                                 break;
3628                         }
3629                         prev_m = m;
3630                 }
3631
3632         }
3633         return *prev_m;
3634 }
3635
3636 const MeterSection&
3637 TempoMap::meter_section_at_beat (double beat) const
3638 {
3639         Glib::Threads::RWLock::ReaderLock lm (lock);
3640         return meter_section_at_beat_locked (_metrics, beat);
3641 }
3642
3643 const Meter&
3644 TempoMap::meter_at_frame (framepos_t frame) const
3645 {
3646         TempoMetric m (metric_at (frame));
3647         return m.meter();
3648 }
3649
3650 void
3651 TempoMap::fix_legacy_session ()
3652 {
3653         MeterSection* prev_m = 0;
3654         TempoSection* prev_t = 0;
3655
3656         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3657                 MeterSection* m;
3658                 TempoSection* t;
3659
3660                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3661                         if (!m->movable()) {
3662                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3663                                 m->set_beat (bbt);
3664                                 m->set_pulse (0.0);
3665                                 m->set_frame (0);
3666                                 m->set_position_lock_style (AudioTime);
3667                                 prev_m = m;
3668                                 continue;
3669                         }
3670                         if (prev_m) {
3671                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3672                                                                           + (m->bbt().beats - 1)
3673                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3674                                                                           , m->bbt());
3675                                 m->set_beat (start);
3676                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3677                                         + (m->bbt().beats - 1)
3678                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3679                                 m->set_pulse (start_beat / prev_m->note_divisor());
3680                         }
3681                         prev_m = m;
3682                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3683
3684                         if (!t->active()) {
3685                                 continue;
3686                         }
3687
3688                         if (!t->movable()) {
3689                                 t->set_pulse (0.0);
3690                                 t->set_frame (0);
3691                                 t->set_position_lock_style (AudioTime);
3692                                 prev_t = t;
3693                                 continue;
3694                         }
3695
3696                         if (prev_t) {
3697                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3698                                         + (t->legacy_bbt().beats - 1)
3699                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3700                                 if (prev_m) {
3701                                         t->set_pulse (beat / prev_m->note_divisor());
3702                                 } else {
3703                                         /* really shouldn't happen but.. */
3704                                         t->set_pulse (beat / 4.0);
3705                                 }
3706                         }
3707                         prev_t = t;
3708                 }
3709         }
3710 }
3711
3712 XMLNode&
3713 TempoMap::get_state ()
3714 {
3715         Metrics::const_iterator i;
3716         XMLNode *root = new XMLNode ("TempoMap");
3717
3718         {
3719                 Glib::Threads::RWLock::ReaderLock lm (lock);
3720                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3721                         root->add_child_nocopy ((*i)->get_state());
3722                 }
3723         }
3724
3725         return *root;
3726 }
3727
3728 int
3729 TempoMap::set_state (const XMLNode& node, int /*version*/)
3730 {
3731         {
3732                 Glib::Threads::RWLock::WriterLock lm (lock);
3733
3734                 XMLNodeList nlist;
3735                 XMLNodeConstIterator niter;
3736                 Metrics old_metrics (_metrics);
3737                 _metrics.clear();
3738
3739                 nlist = node.children();
3740
3741                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3742                         XMLNode* child = *niter;
3743
3744                         if (child->name() == TempoSection::xml_state_node_name) {
3745
3746                                 try {
3747                                         TempoSection* ts = new TempoSection (*child);
3748                                         _metrics.push_back (ts);
3749                                 }
3750
3751                                 catch (failed_constructor& err){
3752                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3753                                         _metrics = old_metrics;
3754                                         old_metrics.clear();
3755                                         break;
3756                                 }
3757
3758                         } else if (child->name() == MeterSection::xml_state_node_name) {
3759
3760                                 try {
3761                                         MeterSection* ms = new MeterSection (*child);
3762                                         _metrics.push_back (ms);
3763                                 }
3764
3765                                 catch (failed_constructor& err) {
3766                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3767                                         _metrics = old_metrics;
3768                                         old_metrics.clear();
3769                                         break;
3770                                 }
3771                         }
3772                 }
3773
3774                 if (niter == nlist.end()) {
3775                         MetricSectionSorter cmp;
3776                         _metrics.sort (cmp);
3777                 }
3778
3779                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3780                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3781                         TempoSection* t;
3782                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3783                                 if (t->legacy_bbt().bars != 0) {
3784                                         fix_legacy_session();
3785                                         break;
3786                                 }
3787                                 break;
3788                         }
3789                 }
3790
3791                 /* check for multiple tempo/meters at the same location, which
3792                    ardour2 somehow allowed.
3793                 */
3794
3795                 Metrics::iterator prev = _metrics.end();
3796                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3797                         if (prev != _metrics.end()) {
3798                                 MeterSection* ms;
3799                                 MeterSection* prev_m;
3800                                 TempoSection* ts;
3801                                 TempoSection* prev_t;
3802                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3803                                         if (prev_m->pulse() == ms->pulse()) {
3804                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3805                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3806                                                 return -1;
3807                                         }
3808                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3809                                         if (prev_t->pulse() == ts->pulse()) {
3810                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3811                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3812                                                 return -1;
3813                                         }
3814                                 }
3815                         }
3816                         prev = i;
3817                 }
3818
3819                 recompute_map (_metrics);
3820
3821                 Metrics::const_iterator d = old_metrics.begin();
3822                 while (d != old_metrics.end()) {
3823                         delete (*d);
3824                         ++d;
3825                 }
3826                 old_metrics.clear ();
3827         }
3828
3829         PropertyChanged (PropertyChange ());
3830
3831         return 0;
3832 }
3833
3834 void
3835 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3836 {
3837         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3838         const MeterSection* m;
3839         const TempoSection* t;
3840         const TempoSection* prev_t = 0;
3841
3842         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3843
3844                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3845                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3846                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3847                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3848                         if (prev_t) {
3849                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3850                                 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;
3851                         }
3852                         prev_t = t;
3853                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3854                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3855                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3856                 }
3857         }
3858         o << "------" << std::endl;
3859 }
3860
3861 int
3862 TempoMap::n_tempos() const
3863 {
3864         Glib::Threads::RWLock::ReaderLock lm (lock);
3865         int cnt = 0;
3866
3867         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3868                 if ((*i)->is_tempo()) {
3869                         cnt++;
3870                 }
3871         }
3872
3873         return cnt;
3874 }
3875
3876 int
3877 TempoMap::n_meters() const
3878 {
3879         Glib::Threads::RWLock::ReaderLock lm (lock);
3880         int cnt = 0;
3881
3882         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3883                 if (!(*i)->is_tempo()) {
3884                         cnt++;
3885                 }
3886         }
3887
3888         return cnt;
3889 }
3890
3891 void
3892 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3893 {
3894         {
3895                 Glib::Threads::RWLock::WriterLock lm (lock);
3896                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3897                         if ((*i)->frame() >= where && (*i)->movable ()) {
3898                                 (*i)->set_frame ((*i)->frame() + amount);
3899                         }
3900                 }
3901
3902                 /* now reset the BBT time of all metrics, based on their new
3903                  * audio time. This is the only place where we do this reverse
3904                  * timestamp.
3905                  */
3906
3907                 Metrics::iterator i;
3908                 const MeterSection* meter;
3909                 const TempoSection* tempo;
3910                 MeterSection *m;
3911                 TempoSection *t;
3912
3913                 meter = &first_meter ();
3914                 tempo = &first_tempo ();
3915
3916                 BBT_Time start;
3917                 BBT_Time end;
3918
3919                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3920
3921                 bool first = true;
3922                 MetricSection* prev = 0;
3923
3924                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3925
3926                         BBT_Time bbt;
3927                         //TempoMetric metric (*meter, *tempo);
3928                         MeterSection* ms = const_cast<MeterSection*>(meter);
3929                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3930                         if (prev) {
3931                                 if (ts){
3932                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3933                                                 if (!t->active()) {
3934                                                         continue;
3935                                                 }
3936                                                 ts->set_pulse (t->pulse());
3937                                         }
3938                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3939                                                 ts->set_pulse (m->pulse());
3940                                         }
3941                                         ts->set_frame (prev->frame());
3942
3943                                 }
3944                                 if (ms) {
3945                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3946                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3947                                                 ms->set_beat (start);
3948                                                 ms->set_pulse (m->pulse());
3949                                         }
3950                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3951                                                 if (!t->active()) {
3952                                                         continue;
3953                                                 }
3954                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3955                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3956                                                 ms->set_beat (start);
3957                                                 ms->set_pulse (t->pulse());
3958                                         }
3959                                         ms->set_frame (prev->frame());
3960                                 }
3961
3962                         } else {
3963                                 // metric will be at frames=0 bbt=1|1|0 by default
3964                                 // which is correct for our purpose
3965                         }
3966
3967                         // cerr << bbt << endl;
3968
3969                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3970                                 if (!t->active()) {
3971                                         continue;
3972                                 }
3973                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3974                                 tempo = t;
3975                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3976                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3977                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3978
3979                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3980
3981                                 if (first) {
3982                                         first = false;
3983                                 } else {
3984
3985                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3986                                                 /* round up to next beat */
3987                                                 bbt.beats += 1;
3988                                         }
3989
3990                                         bbt.ticks = 0;
3991
3992                                         if (bbt.beats != 1) {
3993                                                 /* round up to next bar */
3994                                                 bbt.bars += 1;
3995                                                 bbt.beats = 1;
3996                                         }
3997                                 }
3998                                 pair<double, BBT_Time> start = make_pair (max (0.0, beat_at_frame_locked (_metrics, m->frame())), bbt);
3999                                 m->set_beat (start);
4000                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
4001                                 meter = m;
4002                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
4003                         } else {
4004                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
4005                                 abort(); /*NOTREACHED*/
4006                         }
4007
4008                         prev = (*i);
4009                 }
4010
4011                 recompute_map (_metrics);
4012         }
4013
4014
4015         PropertyChanged (PropertyChange ());
4016 }
4017 bool
4018 TempoMap::remove_time (framepos_t where, framecnt_t amount)
4019 {
4020         bool moved = false;
4021
4022         std::list<MetricSection*> metric_kill_list;
4023
4024         TempoSection* last_tempo = NULL;
4025         MeterSection* last_meter = NULL;
4026         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
4027         bool meter_after = false; // is there a meter marker likewise?
4028         {
4029                 Glib::Threads::RWLock::WriterLock lm (lock);
4030                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4031                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
4032                                 metric_kill_list.push_back(*i);
4033                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
4034                                 if (lt)
4035                                         last_tempo = lt;
4036                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
4037                                 if (lm)
4038                                         last_meter = lm;
4039                         }
4040                         else if ((*i)->frame() >= where) {
4041                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
4042                                 (*i)->set_frame ((*i)->frame() - amount);
4043                                 if ((*i)->frame() == where) {
4044                                         // marker was immediately after end of range
4045                                         tempo_after = dynamic_cast<TempoSection*> (*i);
4046                                         meter_after = dynamic_cast<MeterSection*> (*i);
4047                                 }
4048                                 moved = true;
4049                         }
4050                 }
4051
4052                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
4053                 if (last_tempo && !tempo_after) {
4054                         metric_kill_list.remove(last_tempo);
4055                         last_tempo->set_frame(where);
4056                         moved = true;
4057                 }
4058                 if (last_meter && !meter_after) {
4059                         metric_kill_list.remove(last_meter);
4060                         last_meter->set_frame(where);
4061                         moved = true;
4062                 }
4063
4064                 //remove all the remaining metrics
4065                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
4066                         _metrics.remove(*i);
4067                         moved = true;
4068                 }
4069
4070                 if (moved) {
4071                         recompute_map (_metrics);
4072                 }
4073         }
4074         PropertyChanged (PropertyChange ());
4075         return moved;
4076 }
4077
4078 /** Add some (fractional) beats to a session frame position, and return the result in frames.
4079  *  pos can be -ve, if required.
4080  */
4081 framepos_t
4082 TempoMap::framepos_plus_beats (framepos_t frame, Evoral::Beats beats) const
4083 {
4084         Glib::Threads::RWLock::ReaderLock lm (lock);
4085
4086         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, frame) + beats.to_double());
4087 }
4088 framepos_t
4089 TempoMap::framepos_plus_qn (framepos_t frame, Evoral::Beats quarter_note) const
4090 {
4091         Glib::Threads::RWLock::ReaderLock lm (lock);
4092
4093         return frame_at_quarter_note_locked (_metrics, quarter_note_at_frame_locked (_metrics, frame) + quarter_note.to_double());
4094 }
4095
4096 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
4097 framepos_t
4098 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
4099 {
4100         Glib::Threads::RWLock::ReaderLock lm (lock);
4101
4102         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
4103 }
4104
4105 /** Add the BBT interval op to pos and return the result */
4106 framepos_t
4107 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
4108 {
4109         Glib::Threads::RWLock::ReaderLock lm (lock);
4110
4111         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
4112         pos_bbt.ticks += op.ticks;
4113         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
4114                 ++pos_bbt.beats;
4115                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
4116         }
4117         pos_bbt.beats += op.beats;
4118         /* the meter in effect will start on the bar */
4119         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();
4120         while (pos_bbt.beats >= divisions_per_bar + 1) {
4121                 ++pos_bbt.bars;
4122                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
4123                 pos_bbt.beats -= divisions_per_bar;
4124         }
4125         pos_bbt.bars += op.bars;
4126
4127         return frame_at_bbt_locked (_metrics, pos_bbt);
4128 }
4129
4130 /** Count the number of beats that are equivalent to distance when going forward,
4131     starting at pos.
4132 */
4133 Evoral::Beats
4134 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
4135 {
4136         Glib::Threads::RWLock::ReaderLock lm (lock);
4137
4138         return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
4139 }
4140
4141 Evoral::Beats
4142 TempoMap::framewalk_to_qn (framepos_t pos, framecnt_t distance) const
4143 {
4144         Glib::Threads::RWLock::ReaderLock lm (lock);
4145
4146         return Evoral::Beats (quarter_note_at_frame_locked (_metrics, pos + distance) - quarter_note_at_frame_locked (_metrics, pos));
4147 }
4148 struct bbtcmp {
4149     bool operator() (const BBT_Time& a, const BBT_Time& b) {
4150             return a < b;
4151     }
4152 };
4153
4154 std::ostream&
4155 operator<< (std::ostream& o, const Meter& m) {
4156         return o << m.divisions_per_bar() << '/' << m.note_divisor();
4157 }
4158
4159 std::ostream&
4160 operator<< (std::ostream& o, const Tempo& t) {
4161         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
4162 }
4163
4164 std::ostream&
4165 operator<< (std::ostream& o, const MetricSection& section) {
4166
4167         o << "MetricSection @ " << section.frame() << ' ';
4168
4169         const TempoSection* ts;
4170         const MeterSection* ms;
4171
4172         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
4173                 o << *((const Tempo*) ts);
4174         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
4175                 o << *((const Meter*) ms);
4176         }
4177
4178         return o;
4179 }