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