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