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