Fix incorrect inclusion of note_type in Tempo::pulses_per_minute().
[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                                 return ret;
1710                         }
1711                         prev_t = t;
1712                 }
1713         }
1714
1715         /* treated as constant for this ts */
1716         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1717
1718         return pulses_in_section + prev_t->pulse();
1719 }
1720
1721 framepos_t
1722 TempoMap::frame_at_pulse (const double& pulse) const
1723 {
1724         Glib::Threads::RWLock::ReaderLock lm (lock);
1725         return frame_at_pulse_locked (_metrics, pulse);
1726 }
1727
1728 /* tempo section based */
1729 framepos_t
1730 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1731 {
1732         /* HOLD THE READER LOCK */
1733
1734         const TempoSection* prev_t = 0;
1735
1736         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1737                 TempoSection* t;
1738
1739                 if ((*i)->is_tempo()) {
1740                         t = static_cast<TempoSection*> (*i);
1741                         if (!t->active()) {
1742                                 continue;
1743                         }
1744                         if (prev_t && t->pulse() > pulse) {
1745                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1746                         }
1747
1748                         prev_t = t;
1749                 }
1750         }
1751         /* must be treated as constant, irrespective of _type */
1752         double const dtime = (pulse - prev_t->pulse()) * prev_t->frames_per_pulse (_frame_rate);
1753
1754         return (framecnt_t) floor (dtime) + prev_t->frame();
1755 }
1756
1757 double
1758 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1759 {
1760         Glib::Threads::RWLock::ReaderLock lm (lock);
1761         return beat_at_bbt_locked (_metrics, bbt);
1762 }
1763
1764
1765 double
1766 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1767 {
1768         /* CALLER HOLDS READ LOCK */
1769
1770         MeterSection* prev_m = 0;
1771
1772         /* because audio-locked meters have 'fake' integral beats,
1773            there is no pulse offset here.
1774         */
1775         MeterSection* m;
1776
1777         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1778                 if (!(*i)->is_tempo()) {
1779                         m = static_cast<MeterSection*> (*i);
1780                         if (prev_m) {
1781                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1782                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1783                                         break;
1784                                 }
1785                         }
1786                         prev_m = m;
1787                 }
1788         }
1789
1790         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1791         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1792         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1793
1794         return ret;
1795 }
1796
1797 Timecode::BBT_Time
1798 TempoMap::bbt_at_beat (const double& beats)
1799 {
1800         Glib::Threads::RWLock::ReaderLock lm (lock);
1801         return bbt_at_beat_locked (_metrics, beats);
1802 }
1803
1804 Timecode::BBT_Time
1805 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1806 {
1807         /* CALLER HOLDS READ LOCK */
1808         MeterSection* prev_m = 0;
1809         const double beats = max (0.0, b);
1810
1811         MeterSection* m = 0;
1812
1813         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1814                 if (!(*i)->is_tempo()) {
1815                         m = static_cast<MeterSection*> (*i);
1816                         if (prev_m) {
1817                                 if (m->beat() > beats) {
1818                                         /* this is the meter after the one our beat is on*/
1819                                         break;
1820                                 }
1821                         }
1822
1823                         prev_m = m;
1824                 }
1825         }
1826
1827         const double beats_in_ms = beats - prev_m->beat();
1828         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1829         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1830         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1831         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1832
1833         BBT_Time ret;
1834
1835         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1836         ret.beats = (uint32_t) floor (remaining_beats);
1837         ret.bars = total_bars;
1838
1839         /* 0 0 0 to 1 1 0 - based mapping*/
1840         ++ret.bars;
1841         ++ret.beats;
1842
1843         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1844                 ++ret.beats;
1845                 ret.ticks -= BBT_Time::ticks_per_beat;
1846         }
1847
1848         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1849                 ++ret.bars;
1850                 ret.beats = 1;
1851         }
1852
1853         return ret;
1854 }
1855
1856 double
1857 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1858 {
1859         Glib::Threads::RWLock::ReaderLock lm (lock);
1860
1861         return pulse_at_bbt_locked (_metrics, bbt);
1862 }
1863
1864 double
1865 TempoMap::pulse_at_bbt_rt (const Timecode::BBT_Time& bbt)
1866 {
1867         Glib::Threads::RWLock::ReaderLock lm (lock);
1868
1869         if (!lm.locked()) {
1870                 throw std::logic_error ("TempoMap::pulse_at_bbt_rt() could not lock tempo map");
1871         }
1872
1873         return pulse_at_bbt_locked (_metrics, bbt);
1874 }
1875
1876 double
1877 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1878 {
1879         /* CALLER HOLDS READ LOCK */
1880
1881         MeterSection* prev_m = 0;
1882
1883         /* because audio-locked meters have 'fake' integral beats,
1884            there is no pulse offset here.
1885         */
1886         MeterSection* m;
1887
1888         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1889                 if (!(*i)->is_tempo()) {
1890                         m = static_cast<MeterSection*> (*i);
1891                         if (prev_m) {
1892                                 if (m->bbt().bars > bbt.bars) {
1893                                         break;
1894                                 }
1895                         }
1896                         prev_m = m;
1897                 }
1898         }
1899
1900         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1901         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1902         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1903
1904         return ret;
1905 }
1906
1907 Timecode::BBT_Time
1908 TempoMap::bbt_at_pulse (const double& pulse)
1909 {
1910         Glib::Threads::RWLock::ReaderLock lm (lock);
1911
1912         return bbt_at_pulse_locked (_metrics, pulse);
1913 }
1914
1915 Timecode::BBT_Time
1916 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1917 {
1918         MeterSection* prev_m = 0;
1919
1920         MeterSection* m = 0;
1921
1922         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1923
1924                 if (!(*i)->is_tempo()) {
1925                         m = static_cast<MeterSection*> (*i);
1926
1927                         if (prev_m) {
1928                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1929                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1930                                         /* this is the meter after the one our beat is on*/
1931                                         break;
1932                                 }
1933                         }
1934
1935                         prev_m = m;
1936                 }
1937         }
1938
1939         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1940         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1941         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1942         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1943         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1944
1945         BBT_Time ret;
1946
1947         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1948         ret.beats = (uint32_t) floor (remaining_beats);
1949         ret.bars = total_bars;
1950
1951         /* 0 0 0 to 1 1 0 mapping*/
1952         ++ret.bars;
1953         ++ret.beats;
1954
1955         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1956                 ++ret.beats;
1957                 ret.ticks -= BBT_Time::ticks_per_beat;
1958         }
1959
1960         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1961                 ++ret.bars;
1962                 ret.beats = 1;
1963         }
1964
1965         return ret;
1966 }
1967
1968 BBT_Time
1969 TempoMap::bbt_at_frame (framepos_t frame)
1970 {
1971         if (frame < 0) {
1972                 BBT_Time bbt;
1973                 bbt.bars = 1;
1974                 bbt.beats = 1;
1975                 bbt.ticks = 0;
1976                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1977                 return bbt;
1978         }
1979         Glib::Threads::RWLock::ReaderLock lm (lock);
1980
1981         return bbt_at_frame_locked (_metrics, frame);
1982 }
1983
1984 BBT_Time
1985 TempoMap::bbt_at_frame_rt (framepos_t frame)
1986 {
1987         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1988
1989         if (!lm.locked()) {
1990                 throw std::logic_error ("TempoMap::bbt_at_frame_rt() could not lock tempo map");
1991         }
1992
1993         return bbt_at_frame_locked (_metrics, frame);
1994 }
1995
1996 Timecode::BBT_Time
1997 TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1998 {
1999         if (frame < 0) {
2000                 BBT_Time bbt;
2001                 bbt.bars = 1;
2002                 bbt.beats = 1;
2003                 bbt.ticks = 0;
2004                 return bbt;
2005         }
2006
2007         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
2008         MeterSection* prev_m = 0;
2009         MeterSection* next_m = 0;
2010
2011         MeterSection* m;
2012
2013         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2014                 if (!(*i)->is_tempo()) {
2015                         m = static_cast<MeterSection*> (*i);
2016                         if (prev_m && m->frame() > frame) {
2017                                 next_m = m;
2018                                 break;
2019                         }
2020                         prev_m = m;
2021                 }
2022         }
2023
2024         double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
2025
2026         /* handle frame before first meter */
2027         if (frame < prev_m->frame()) {
2028                 beat = 0.0;
2029         }
2030         /* audio locked meters fake their beat */
2031         if (next_m && next_m->beat() < beat) {
2032                 beat = next_m->beat();
2033         }
2034
2035         beat = max (0.0, beat);
2036
2037         const double beats_in_ms = beat - prev_m->beat();
2038         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2039         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2040         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2041         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2042
2043         BBT_Time ret;
2044
2045         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2046         ret.beats = (uint32_t) floor (remaining_beats);
2047         ret.bars = total_bars;
2048
2049         /* 0 0 0 to 1 1 0 - based mapping*/
2050         ++ret.bars;
2051         ++ret.beats;
2052
2053         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2054                 ++ret.beats;
2055                 ret.ticks -= BBT_Time::ticks_per_beat;
2056         }
2057
2058         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2059                 ++ret.bars;
2060                 ret.beats = 1;
2061         }
2062
2063         return ret;
2064 }
2065
2066 framepos_t
2067 TempoMap::frame_at_bbt (const BBT_Time& bbt)
2068 {
2069         if (bbt.bars < 1) {
2070                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
2071                 return 0;
2072         }
2073
2074         if (bbt.beats < 1) {
2075                 throw std::logic_error ("beats are counted from one");
2076         }
2077         Glib::Threads::RWLock::ReaderLock lm (lock);
2078
2079         return frame_at_bbt_locked (_metrics, bbt);
2080 }
2081
2082 /* meter & tempo section based */
2083 framepos_t
2084 TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
2085 {
2086         /* HOLD THE READER LOCK */
2087
2088         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
2089         return ret;
2090 }
2091
2092 /**
2093  * Returns the distance from 0 in quarter pulses at the supplied frame.
2094  *
2095  * Plugin APIs don't count ticks in the same way PROGRAM_NAME does.
2096  * We use ticks per beat whereas the rest of the world uses ticks per quarter note.
2097  * This is more or less the VST's ppqPos (a scalar you use to obtain tick position
2098  * in whatever ppqn you're using).
2099  *
2100  * @param frame The distance in frames relative to session 0 whose quarter note distance you would like.
2101  * @return The quarter note (quarter pulse) distance from session 0 to the supplied frame. Ignores meter.
2102 */
2103
2104 double
2105 TempoMap::quarter_note_at_frame (const framepos_t frame)
2106 {
2107         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2108
2109         const double ret = quarter_note_at_frame_locked (_metrics, frame);
2110
2111         return ret;
2112 }
2113
2114 double
2115 TempoMap::quarter_note_at_frame_locked (const Metrics& metrics, const framepos_t frame) const
2116 {
2117         const double ret = pulse_at_frame_locked (metrics, frame) * 4.0;
2118
2119         return ret;
2120 }
2121
2122 double
2123 TempoMap::quarter_note_at_frame_rt (const framepos_t frame)
2124 {
2125         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2126
2127         if (!lm.locked()) {
2128                 throw std::logic_error ("TempoMap::quarter_note_at_frame_rt() could not lock tempo map");
2129         }
2130
2131         const double ret = pulse_at_frame_locked (_metrics, frame) * 4.0;
2132
2133         return ret;
2134 }
2135
2136 framepos_t
2137 TempoMap::frame_at_quarter_note (const double quarter_note)
2138 {
2139         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2140
2141         const framepos_t ret = frame_at_quarter_note_locked (_metrics, quarter_note);
2142
2143         return ret;
2144 }
2145
2146 framepos_t
2147 TempoMap::frame_at_quarter_note_locked (const Metrics& metrics, const double quarter_note) const
2148 {
2149         const framepos_t ret = frame_at_pulse_locked (metrics, quarter_note / 4.0);
2150
2151         return ret;
2152 }
2153
2154 double
2155 TempoMap::quarter_note_at_beat (const double beat)
2156 {
2157         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2158
2159         const double ret = quarter_note_at_beat_locked (_metrics, beat);
2160
2161         return ret;
2162 }
2163
2164 double
2165 TempoMap::quarter_note_at_beat_locked (const Metrics& metrics, const double beat) const
2166 {
2167         const double ret = pulse_at_beat_locked (metrics, beat) * 4.0;
2168
2169         return ret;
2170 }
2171
2172 double
2173 TempoMap::beat_at_quarter_note (const double quarter_note)
2174 {
2175         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2176
2177         const double ret = beat_at_pulse_locked (_metrics, quarter_note / 4.0);
2178
2179         return ret;
2180 }
2181
2182 bool
2183 TempoMap::check_solved (const Metrics& metrics) const
2184 {
2185         TempoSection* prev_t = 0;
2186         MeterSection* prev_m = 0;
2187
2188         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2189                 TempoSection* t;
2190                 MeterSection* m;
2191                 if ((*i)->is_tempo()) {
2192                         t = static_cast<TempoSection*> (*i);
2193                         if (!t->active()) {
2194                                 continue;
2195                         }
2196                         if (prev_t) {
2197                                 /* check ordering */
2198                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
2199                                         return false;
2200                                 }
2201
2202                                 /* precision check ensures tempo and frames align.*/
2203                                 if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
2204                                         if (!t->locked_to_meter()) {
2205                                                 return false;
2206                                         }
2207                                 }
2208
2209                                 /* gradient limit - who knows what it should be?
2210                                    things are also ok (if a little chaotic) without this
2211                                 */
2212                                 if (fabs (prev_t->c_func()) > 1000.0) {
2213                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
2214                                         return false;
2215                                 }
2216                         }
2217                         prev_t = t;
2218                 }
2219
2220                 if (!(*i)->is_tempo()) {
2221                         m = static_cast<MeterSection*> (*i);
2222                         if (prev_m && m->position_lock_style() == AudioTime) {
2223                                 const TempoSection* t = &tempo_section_at_frame_locked (metrics, m->frame() - 1);
2224                                 const framepos_t nascent_m_frame = t->frame_at_pulse (m->pulse(), _frame_rate);
2225                                 /* Here we check that a preceding section of music doesn't overlap a subsequent one.
2226                                    It is complicated by the fact that audio locked meters represent a discontinuity in the pulse
2227                                    (they place an exact pulse at a particular time expressed only in frames).
2228                                    This has the effect of shifting the calculated frame at the meter pulse (wrt the previous section of music)
2229                                    away from its actual frame (which is now the frame location of the exact pulse).
2230                                    This can result in the calculated frame (from the previous musical section)
2231                                    differing from the exact frame by one sample.
2232                                    Allow for that.
2233                                 */
2234                                 if (t && (nascent_m_frame > m->frame() + 1 || nascent_m_frame < 0)) {
2235                                         return false;
2236                                 }
2237                         }
2238
2239                         prev_m = m;
2240                 }
2241
2242         }
2243
2244         return true;
2245 }
2246
2247 bool
2248 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
2249 {
2250         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2251                 TempoSection* t;
2252                 if ((*i)->is_tempo()) {
2253                         t = static_cast<TempoSection*> (*i);
2254                         if (!t->movable()) {
2255                                 t->set_active (true);
2256                                 continue;
2257                         }
2258                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
2259                                 t->set_active (false);
2260                                 t->set_pulse (0.0);
2261                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
2262                                 t->set_active (true);
2263                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
2264                                 return false;
2265                         }
2266                 }
2267         }
2268         return true;
2269 }
2270
2271 bool
2272 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
2273 {
2274         TempoSection* prev_t = 0;
2275         TempoSection* section_prev = 0;
2276         framepos_t first_m_frame = 0;
2277
2278         /* can't move a tempo before the first meter */
2279         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2280                 MeterSection* m;
2281                 if (!(*i)->is_tempo()) {
2282                         m = static_cast<MeterSection*> (*i);
2283                         if (!m->movable()) {
2284                                 first_m_frame = m->frame();
2285                                 break;
2286                         }
2287                 }
2288         }
2289         if (section->movable() && frame <= first_m_frame) {
2290                 return false;
2291         }
2292
2293         section->set_active (true);
2294         section->set_frame (frame);
2295
2296         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2297                 TempoSection* t;
2298                 if ((*i)->is_tempo()) {
2299                         t = static_cast<TempoSection*> (*i);
2300
2301                         if (!t->active()) {
2302                                 continue;
2303                         }
2304                         if (prev_t) {
2305                                 if (t == section) {
2306                                         section_prev = prev_t;
2307                                         if (t->locked_to_meter()) {
2308                                                 prev_t = t;
2309                                         }
2310                                         continue;
2311                                 }
2312                                 if (t->position_lock_style() == MusicTime) {
2313                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2314                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2315                                 } else {
2316                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2317                                         if (!t->locked_to_meter()) {
2318                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2319                                         }
2320                                 }
2321                         }
2322                         prev_t = t;
2323                 }
2324         }
2325
2326         if (section_prev) {
2327                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
2328                 if (!section->locked_to_meter()) {
2329                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2330                 }
2331         }
2332
2333 #if (0)
2334         recompute_tempi (imaginary);
2335
2336         if (check_solved (imaginary)) {
2337                 return true;
2338         } else {
2339                 dunp (imaginary, std::cout);
2340         }
2341 #endif
2342
2343         MetricSectionFrameSorter fcmp;
2344         imaginary.sort (fcmp);
2345
2346         recompute_tempi (imaginary);
2347
2348         if (check_solved (imaginary)) {
2349                 return true;
2350         }
2351
2352         return false;
2353 }
2354
2355 bool
2356 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2357 {
2358         TempoSection* prev_t = 0;
2359         TempoSection* section_prev = 0;
2360
2361         section->set_pulse (pulse);
2362
2363         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2364                 TempoSection* t;
2365                 if ((*i)->is_tempo()) {
2366                         t = static_cast<TempoSection*> (*i);
2367                         if (!t->active()) {
2368                                 continue;
2369                         }
2370                         if (!t->movable()) {
2371                                 t->set_pulse (0.0);
2372                                 prev_t = t;
2373                                 continue;
2374                         }
2375                         if (prev_t) {
2376                                 if (t == section) {
2377                                         section_prev = prev_t;
2378                                         continue;
2379                                 }
2380                                 if (t->position_lock_style() == MusicTime) {
2381                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2382                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2383                                 } else {
2384                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2385                                         if (!t->locked_to_meter()) {
2386                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2387                                         }
2388                                 }
2389                         }
2390                         prev_t = t;
2391                 }
2392         }
2393
2394         if (section_prev) {
2395                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
2396                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2397         }
2398
2399 #if (0)
2400         recompute_tempi (imaginary);
2401
2402         if (check_solved (imaginary)) {
2403                 return true;
2404         } else {
2405                 dunp (imaginary, std::cout);
2406         }
2407 #endif
2408
2409         MetricSectionSorter cmp;
2410         imaginary.sort (cmp);
2411
2412         recompute_tempi (imaginary);
2413         /* Reordering
2414          * XX need a restriction here, but only for this case,
2415          * as audio locked tempos don't interact in the same way.
2416          *
2417          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2418          * e.g.
2419          * |50 bpm                        |250 bpm |60 bpm
2420          *                drag 250 to the pulse after 60->
2421          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2422          */
2423         if (check_solved (imaginary)) {
2424                 return true;
2425         }
2426
2427         return false;
2428 }
2429
2430 bool
2431 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2432 {
2433         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2434         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2435         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2436                 return false;
2437         }
2438
2439         if (!section->movable()) {
2440                 /* lock the first tempo to our first meter */
2441                 if (!set_active_tempos (imaginary, frame)) {
2442                         return false;
2443                 }
2444         }
2445
2446         TempoSection* meter_locked_tempo = 0;
2447
2448         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2449                 TempoSection* t;
2450                 if ((*ii)->is_tempo()) {
2451                         t = static_cast<TempoSection*> (*ii);
2452                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2453                                 meter_locked_tempo = t;
2454                                 break;
2455                         }
2456                 }
2457         }
2458
2459         if (!meter_locked_tempo) {
2460                 return false;
2461         }
2462
2463         MeterSection* prev_m = 0;
2464         Metrics future_map;
2465         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2466         bool solved = false;
2467
2468         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2469                 MeterSection* m;
2470                 if (!(*i)->is_tempo()) {
2471                         m = static_cast<MeterSection*> (*i);
2472                         if (m == section){
2473                                 if (prev_m && section->movable()) {
2474                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2475                                         if (beats + prev_m->beat() < section->beat()) {
2476                                                 /* set the frame/pulse corresponding to its musical position,
2477                                                  * as an earlier time than this has been requested.
2478                                                 */
2479                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2480                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2481
2482                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2483
2484                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2485                                                         meter_locked_tempo->set_pulse (new_pulse);
2486                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2487                                                         section->set_frame (smallest_frame);
2488                                                         section->set_pulse (new_pulse);
2489                                                 } else {
2490                                                         solved = false;
2491                                                 }
2492
2493                                                 Metrics::const_iterator d = future_map.begin();
2494                                                 while (d != future_map.end()) {
2495                                                         delete (*d);
2496                                                         ++d;
2497                                                 }
2498
2499                                                 if (!solved) {
2500                                                         return false;
2501                                                 }
2502                                         } else {
2503                                                 /* all is ok. set section's locked tempo if allowed.
2504                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2505                                                    XX this check could possibly go. its never actually happened here.
2506                                                 */
2507                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2508                                                 meter_copy->set_frame (frame);
2509
2510                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2511                                                         section->set_frame (frame);
2512                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2513                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2514                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2515                                                 } else {
2516                                                         solved = false;
2517                                                 }
2518
2519                                                 Metrics::const_iterator d = future_map.begin();
2520                                                 while (d != future_map.end()) {
2521                                                         delete (*d);
2522                                                         ++d;
2523                                                 }
2524
2525                                                 if (!solved) {
2526                                                         return false;
2527                                                 }
2528                                         }
2529                                 } else {
2530                                         /* not movable (first meter atm) */
2531
2532                                         tempo_copy->set_frame (frame);
2533                                         tempo_copy->set_pulse (0.0);
2534
2535                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2536                                                 section->set_frame (frame);
2537                                                 meter_locked_tempo->set_frame (frame);
2538                                                 meter_locked_tempo->set_pulse (0.0);
2539                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2540                                         } else {
2541                                                 solved = false;
2542                                         }
2543
2544                                         Metrics::const_iterator d = future_map.begin();
2545                                         while (d != future_map.end()) {
2546                                                 delete (*d);
2547                                                 ++d;
2548                                         }
2549
2550                                         if (!solved) {
2551                                                 return false;
2552                                         }
2553
2554                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2555                                         section->set_beat (b_bbt);
2556                                         section->set_pulse (0.0);
2557
2558                                 }
2559                                 break;
2560                         }
2561
2562                         prev_m = m;
2563                 }
2564         }
2565
2566         MetricSectionFrameSorter fcmp;
2567         imaginary.sort (fcmp);
2568
2569         recompute_meters (imaginary);
2570
2571         return true;
2572 }
2573
2574 bool
2575 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2576 {
2577         /* disallow setting section to an existing meter's bbt */
2578         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2579                 MeterSection* m;
2580                 if (!(*i)->is_tempo()) {
2581                         m = static_cast<MeterSection*> (*i);
2582                         if (m != section && m->bbt().bars == when.bars) {
2583                                 return false;
2584                         }
2585                 }
2586         }
2587
2588         MeterSection* prev_m = 0;
2589         MeterSection* section_prev = 0;
2590
2591         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2592                 MeterSection* m;
2593                 if (!(*i)->is_tempo()) {
2594                         m = static_cast<MeterSection*> (*i);
2595                         pair<double, BBT_Time> b_bbt;
2596                         double new_pulse = 0.0;
2597
2598                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2599                                 section_prev = prev_m;
2600                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2601                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2602                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2603
2604                                 section->set_beat (b_bbt);
2605                                 section->set_pulse (pulse);
2606                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2607                                 prev_m = section;
2608                                 continue;
2609                         }
2610
2611                         if (m->position_lock_style() == AudioTime) {
2612                                 TempoSection* meter_locked_tempo = 0;
2613
2614                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2615                                         TempoSection* t;
2616                                         if ((*ii)->is_tempo()) {
2617                                                 t = static_cast<TempoSection*> (*ii);
2618                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2619                                                         meter_locked_tempo = t;
2620                                                         break;
2621                                                 }
2622                                         }
2623                                 }
2624
2625                                 if (!meter_locked_tempo) {
2626                                         return false;
2627                                 }
2628
2629                                 if (prev_m) {
2630                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2631
2632                                         if (beats + prev_m->beat() != m->beat()) {
2633                                                 /* tempo/ meter change caused a change in beat (bar). */
2634                                                 b_bbt = make_pair (beats + prev_m->beat()
2635                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2636                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2637                                         } else if (m->movable()) {
2638                                                 b_bbt = make_pair (m->beat(), m->bbt());
2639                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2640                                         }
2641                                 } else {
2642                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2643                                 }
2644
2645                                 meter_locked_tempo->set_pulse (new_pulse);
2646                                 m->set_beat (b_bbt);
2647                                 m->set_pulse (new_pulse);
2648
2649                         } else {
2650                                 /* MusicTime */
2651                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2652                                 if (beats + prev_m->beat() != m->beat()) {
2653                                         /* tempo/ meter change caused a change in beat (bar). */
2654                                         b_bbt = make_pair (beats + prev_m->beat()
2655                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2656                                 } else {
2657                                         b_bbt = make_pair (beats + prev_m->beat()
2658                                                            , m->bbt());
2659                                 }
2660                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2661                                 m->set_beat (b_bbt);
2662                                 m->set_pulse (new_pulse);
2663                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2664                         }
2665
2666                         prev_m = m;
2667                 }
2668         }
2669
2670         if (!section_prev) {
2671
2672                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2673                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2674                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2675
2676                 section->set_beat (b_bbt);
2677                 section->set_pulse (pulse);
2678                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2679         }
2680
2681         MetricSectionSorter cmp;
2682         imaginary.sort (cmp);
2683
2684         recompute_meters (imaginary);
2685
2686         return true;
2687 }
2688
2689 /** places a copy of _metrics into copy and returns a pointer
2690  *  to section's equivalent in copy.
2691  */
2692 TempoSection*
2693 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2694 {
2695         TempoSection* ret = 0;
2696
2697         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2698                 TempoSection* t;
2699                 MeterSection* m;
2700                 if ((*i)->is_tempo()) {
2701                         t = static_cast<TempoSection*> (*i);
2702                         if (t == section) {
2703                                 ret = new TempoSection (*t);
2704                                 copy.push_back (ret);
2705                                 continue;
2706                         }
2707
2708                         TempoSection* cp = new TempoSection (*t);
2709                         copy.push_back (cp);
2710                 }
2711                 if (!(*i)->is_tempo()) {
2712                         m = static_cast<MeterSection *> (*i);
2713                         MeterSection* cp = new MeterSection (*m);
2714                         copy.push_back (cp);
2715                 }
2716         }
2717
2718         return ret;
2719 }
2720
2721 MeterSection*
2722 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2723 {
2724         MeterSection* ret = 0;
2725
2726         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2727                 TempoSection* t;
2728                 MeterSection* m;
2729                 if ((*i)->is_tempo()) {
2730                         t = static_cast<TempoSection*> (*i);
2731                         TempoSection* cp = new TempoSection (*t);
2732                         copy.push_back (cp);
2733                 }
2734
2735                 if (!(*i)->is_tempo()) {
2736                         m = static_cast<MeterSection *> (*i);
2737                         if (m == section) {
2738                                 ret = new MeterSection (*m);
2739                                 copy.push_back (ret);
2740                                 continue;
2741                         }
2742                         MeterSection* cp = new MeterSection (*m);
2743                         copy.push_back (cp);
2744                 }
2745         }
2746
2747         return ret;
2748 }
2749
2750 /** answers the question "is this a valid beat position for this tempo section?".
2751  *  it returns true if the tempo section can be moved to the requested bbt position,
2752  *  leaving the tempo map in a solved state.
2753  * @param section the tempo section to be moved
2754  * @param bbt the requested new position for the tempo section
2755  * @return true if the tempo section can be moved to the position, otherwise false.
2756  */
2757 bool
2758 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2759 {
2760         Metrics copy;
2761         TempoSection* tempo_copy = 0;
2762
2763         {
2764                 Glib::Threads::RWLock::ReaderLock lm (lock);
2765                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2766                 if (!tempo_copy) {
2767                         return false;
2768                 }
2769         }
2770
2771         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2772
2773         Metrics::const_iterator d = copy.begin();
2774         while (d != copy.end()) {
2775                 delete (*d);
2776                 ++d;
2777         }
2778
2779         return ret;
2780 }
2781
2782 /**
2783 * 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,
2784 * taking any possible reordering as a consequence of this into account.
2785 * @param section - the section to be altered
2786 * @param bbt - the bbt where the altered tempo will fall
2787 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2788 */
2789 pair<double, framepos_t>
2790 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2791 {
2792         Metrics future_map;
2793         pair<double, framepos_t> ret = make_pair (0.0, 0);
2794
2795         Glib::Threads::RWLock::ReaderLock lm (lock);
2796
2797         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2798
2799         const double beat = beat_at_bbt_locked (future_map, bbt);
2800
2801         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2802                 ret.first = tempo_copy->pulse();
2803                 ret.second = tempo_copy->frame();
2804         } else {
2805                 ret.first = section->pulse();
2806                 ret.second = section->frame();
2807         }
2808
2809         Metrics::const_iterator d = future_map.begin();
2810         while (d != future_map.end()) {
2811                 delete (*d);
2812                 ++d;
2813         }
2814         return ret;
2815 }
2816
2817 void
2818 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame, const int& sub_num)
2819 {
2820         Metrics future_map;
2821
2822         if (ts->position_lock_style() == MusicTime) {
2823                 {
2824                         /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
2825                         Glib::Threads::RWLock::WriterLock lm (lock);
2826                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2827
2828                         tempo_copy->set_position_lock_style (AudioTime);
2829
2830                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2831                                 const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
2832                                 const double pulse = pulse_at_beat_locked (future_map, beat);
2833
2834                                 if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2835                                         solve_map_pulse (_metrics, ts, pulse);
2836                                         recompute_meters (_metrics);
2837                                 }
2838                         }
2839                 }
2840
2841         } else {
2842
2843                 {
2844                         Glib::Threads::RWLock::WriterLock lm (lock);
2845                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2846
2847                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2848                                 if (sub_num != 0) {
2849                                         /* We're moving the object that defines the grid while snapping to it...
2850                                          * Placing the ts at the beat corresponding to the requested frame may shift the
2851                                          * grid in such a way that the mouse is left hovering over a completerly different division,
2852                                          * causing jittering when the mouse next moves (esp. large tempo deltas).
2853                                          * To avoid this, place the ts at the requested frame in a dummy map
2854                                          * then find the closest beat subdivision to that frame in the dummy.
2855                                          * This alters the snap behaviour slightly in that we snap to beat divisions
2856                                          * in the future map rather than the existing one.
2857                                          */
2858                                         const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
2859                                         const double pulse = pulse_at_beat_locked (future_map, beat);
2860
2861                                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2862                                                 /* snapping to a grid. force MusicTime temporarily. */
2863                                                 ts->set_position_lock_style (MusicTime);
2864                                                 solve_map_pulse (_metrics, ts, pulse);
2865                                                 ts->set_position_lock_style (AudioTime);
2866
2867                                                 recompute_meters (_metrics);
2868                                         }
2869                                 } else {
2870                                         solve_map_frame (_metrics, ts, frame);
2871                                         recompute_meters (_metrics);
2872                                 }
2873                         }
2874                 }
2875         }
2876
2877         Metrics::const_iterator d = future_map.begin();
2878         while (d != future_map.end()) {
2879                 delete (*d);
2880                 ++d;
2881         }
2882
2883         MetricPositionChanged (); // Emit Signal
2884 }
2885
2886 void
2887 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2888 {
2889         Metrics future_map;
2890
2891         if (ms->position_lock_style() == AudioTime) {
2892
2893                 {
2894                         Glib::Threads::RWLock::WriterLock lm (lock);
2895                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2896
2897                         if (solve_map_frame (future_map, copy, frame)) {
2898                                 solve_map_frame (_metrics, ms, frame);
2899                                 recompute_tempi (_metrics);
2900                         }
2901                 }
2902         } else {
2903                 {
2904                         Glib::Threads::RWLock::WriterLock lm (lock);
2905                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2906
2907                         const double beat = beat_at_frame_locked (_metrics, frame);
2908                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2909
2910                         if (solve_map_bbt (future_map, copy, bbt)) {
2911                                 solve_map_bbt (_metrics, ms, bbt);
2912                                 recompute_tempi (_metrics);
2913                         }
2914                 }
2915         }
2916
2917         Metrics::const_iterator d = future_map.begin();
2918         while (d != future_map.end()) {
2919                 delete (*d);
2920                 ++d;
2921         }
2922
2923         MetricPositionChanged (); // Emit Signal
2924 }
2925
2926 bool
2927 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2928 {
2929         Metrics future_map;
2930         bool can_solve = false;
2931         {
2932                 Glib::Threads::RWLock::WriterLock lm (lock);
2933                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2934                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2935                 recompute_tempi (future_map);
2936
2937                 if (check_solved (future_map)) {
2938                         ts->set_beats_per_minute (bpm.beats_per_minute());
2939                         recompute_map (_metrics);
2940                         can_solve = true;
2941                 }
2942         }
2943
2944         Metrics::const_iterator d = future_map.begin();
2945         while (d != future_map.end()) {
2946                 delete (*d);
2947                 ++d;
2948         }
2949         if (can_solve) {
2950                 MetricPositionChanged (); // Emit Signal
2951         }
2952         return can_solve;
2953 }
2954
2955 void
2956 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2957 {
2958         /*
2959           Ts (future prev_t)   Tnext
2960           |                    |
2961           |     [drag^]        |
2962           |----------|----------
2963                 e_f  pulse(frame)
2964         */
2965
2966         Metrics future_map;
2967
2968         {
2969                 Glib::Threads::RWLock::WriterLock lm (lock);
2970
2971                 if (!ts) {
2972                         return;
2973                 }
2974
2975                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2976                 TempoSection* prev_to_prev_t = 0;
2977                 const frameoffset_t fr_off = end_frame - frame;
2978
2979                 if (prev_t && prev_t->pulse() > 0.0) {
2980                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2981                 }
2982
2983                 TempoSection* next_t = 0;
2984                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2985                         TempoSection* t = 0;
2986                         if ((*i)->is_tempo()) {
2987                                 t = static_cast<TempoSection*> (*i);
2988                                 if (t->frame() > ts->frame()) {
2989                                         next_t = t;
2990                                         break;
2991                                 }
2992                         }
2993                 }
2994                 /* minimum allowed measurement distance in frames */
2995                 const framepos_t min_dframe = 2;
2996
2997                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2998                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2999                 */
3000                 double contribution = 0.0;
3001
3002                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3003                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
3004                 }
3005
3006                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
3007
3008                 const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
3009                 const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
3010
3011                 double new_bpm;
3012
3013                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
3014
3015                         if (prev_t->position_lock_style() == MusicTime) {
3016                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3017                                         if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
3018
3019                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
3020                                                                                         / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
3021                                         } else {
3022                                                 new_bpm = prev_t->beats_per_minute();
3023                                         }
3024                                 } else {
3025                                         /* prev to prev is irrelevant */
3026
3027                                         if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
3028                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
3029                                         } else {
3030                                                 new_bpm = prev_t->beats_per_minute();
3031                                         }
3032                                 }
3033                         } else {
3034                                 /* AudioTime */
3035                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3036                                         if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
3037
3038                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
3039                                                                                         / (double) ((end_frame) - prev_to_prev_t->frame()));
3040                                         } else {
3041                                                 new_bpm = prev_t->beats_per_minute();
3042                                         }
3043                                 } else {
3044                                         /* prev_to_prev_t is irrelevant */
3045
3046                                         if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
3047                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
3048                                         } else {
3049                                                 new_bpm = prev_t->beats_per_minute();
3050                                         }
3051                                 }
3052                         }
3053                 } else {
3054
3055                         double frame_ratio = 1.0;
3056                         double pulse_ratio = 1.0;
3057                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
3058
3059                         if (prev_to_prev_t) {
3060                                 if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
3061                                         frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
3062                                 }
3063                                 if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
3064                                         pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
3065                                 }
3066                         } else {
3067                                 if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
3068                                         frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
3069                                 }
3070                                 pulse_ratio = (start_pulse / end_pulse);
3071                         }
3072                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
3073                 }
3074
3075                 /* don't clamp and proceed here.
3076                    testing has revealed that this can go negative,
3077                    which is an entirely different thing to just being too low.
3078                 */
3079                 if (new_bpm < 0.5) {
3080                         return;
3081                 }
3082                 new_bpm = min (new_bpm, (double) 1000.0);
3083                 prev_t->set_beats_per_minute (new_bpm);
3084                 recompute_tempi (future_map);
3085                 recompute_meters (future_map);
3086
3087                 if (check_solved (future_map)) {
3088                         ts->set_beats_per_minute (new_bpm);
3089                         recompute_tempi (_metrics);
3090                         recompute_meters (_metrics);
3091                 }
3092         }
3093
3094         Metrics::const_iterator d = future_map.begin();
3095         while (d != future_map.end()) {
3096                 delete (*d);
3097                 ++d;
3098         }
3099
3100         MetricPositionChanged (); // Emit Signal
3101 }
3102
3103 /** Returns the exact beat subdivision closest to the supplied frame, possibly returning a negative value.
3104  * @param frame  The session frame position.
3105  * @param sub_num The requested beat subdivision to use when rounding the frame position.
3106  * @return The beat position of the supplied frame.
3107  * If the supplied frame lies before the first meter, the return will be negative.
3108  * The returned beat is obtained using the first meter and the continuation of the tempo curve (backwards).
3109  *
3110  * This function uses both tempo and meter.
3111  */
3112 double
3113 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
3114 {
3115         Glib::Threads::RWLock::ReaderLock lm (lock);
3116
3117         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
3118 }
3119
3120 double
3121 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
3122 {
3123         double beat = beat_at_frame_locked (metrics, frame);
3124
3125         if (sub_num > 1) {
3126                 beat = floor (beat) + (floor (((beat - floor (beat)) * (double) sub_num) + 0.5) / sub_num);
3127         } else if (sub_num == 1) {
3128                 /* snap to beat */
3129                 beat = floor (beat + 0.5);
3130         } else if (sub_num == -1) {
3131                 /* snap to  bar */
3132                 Timecode::BBT_Time bbt = bbt_at_beat_locked (metrics, beat);
3133                 bbt.beats = 1;
3134                 bbt.ticks = 0;
3135
3136                 const double prev_b = beat_at_bbt_locked (_metrics, bbt);
3137                 ++bbt.bars;
3138                 const double next_b = beat_at_bbt_locked (_metrics, bbt);
3139
3140                 if ((beat - prev_b) > (next_b - prev_b) / 2.0) {
3141                         beat = next_b;
3142                 } else {
3143                         beat = prev_b;
3144                 }
3145         }
3146
3147         return beat;
3148 }
3149 double
3150 TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
3151 {
3152         Glib::Threads::RWLock::ReaderLock lm (lock);
3153
3154         return exact_qn_at_frame_locked (_metrics, frame, sub_num);
3155 }
3156
3157 double
3158 TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
3159 {
3160         double qn = quarter_note_at_frame_locked (metrics, frame);
3161
3162         if (sub_num > 1) {
3163                 qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
3164         } else if (sub_num == 1) {
3165                 /* snap to quarter note */
3166                 qn = floor (qn + 0.5);
3167         } else if (sub_num == -1) {
3168                 /* snap to  bar */
3169                 Timecode::BBT_Time bbt = bbt_at_pulse_locked (metrics, qn / 4.0);
3170                 bbt.beats = 1;
3171                 bbt.ticks = 0;
3172
3173                 const double prev_b = pulse_at_bbt_locked (_metrics, bbt) * 4.0;
3174                 ++bbt.bars;
3175                 const double next_b = pulse_at_bbt_locked (_metrics, bbt) * 4.0;
3176
3177                 if ((qn - prev_b) > (next_b - prev_b) / 2.0) {
3178                         qn = next_b;
3179                 } else {
3180                         qn = prev_b;
3181                 }
3182         }
3183
3184         return qn;
3185 }
3186
3187 framecnt_t
3188 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
3189 {
3190         Glib::Threads::RWLock::ReaderLock lm (lock);
3191
3192         const double tick_at_time = max (0.0, beat_at_frame_locked (_metrics, pos)) * BBT_Time::ticks_per_beat;
3193         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
3194         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
3195
3196         return frame_at_beat_locked (_metrics, total_beats);
3197 }
3198
3199 framepos_t
3200 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
3201 {
3202         return round_to_type (fr, dir, Bar);
3203 }
3204
3205 framepos_t
3206 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
3207 {
3208         return round_to_type (fr, dir, Beat);
3209 }
3210
3211 framepos_t
3212 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3213 {
3214         Glib::Threads::RWLock::ReaderLock lm (lock);
3215         uint32_t ticks = (uint32_t) floor (max (0.0, beat_at_frame_locked (_metrics, fr)) * BBT_Time::ticks_per_beat);
3216         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3217         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3218
3219         ticks -= beats * BBT_Time::ticks_per_beat;
3220
3221         if (dir > 0) {
3222                 /* round to next (or same iff dir == RoundUpMaybe) */
3223
3224                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3225
3226                 if (mod == 0 && dir == RoundUpMaybe) {
3227                         /* right on the subdivision, which is fine, so do nothing */
3228
3229                 } else if (mod == 0) {
3230                         /* right on the subdivision, so the difference is just the subdivision ticks */
3231                         ticks += ticks_one_subdivisions_worth;
3232
3233                 } else {
3234                         /* not on subdivision, compute distance to next subdivision */
3235
3236                         ticks += ticks_one_subdivisions_worth - mod;
3237                 }
3238
3239                 if (ticks >= BBT_Time::ticks_per_beat) {
3240                         ticks -= BBT_Time::ticks_per_beat;
3241                 }
3242         } else if (dir < 0) {
3243
3244                 /* round to previous (or same iff dir == RoundDownMaybe) */
3245
3246                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3247
3248                 if (difference == 0 && dir == RoundDownAlways) {
3249                         /* right on the subdivision, but force-rounding down,
3250                            so the difference is just the subdivision ticks */
3251                         difference = ticks_one_subdivisions_worth;
3252                 }
3253
3254                 if (ticks < difference) {
3255                         ticks = BBT_Time::ticks_per_beat - ticks;
3256                 } else {
3257                         ticks -= difference;
3258                 }
3259
3260         } else {
3261                 /* round to nearest */
3262                 double rem;
3263
3264                 /* compute the distance to the previous and next subdivision */
3265
3266                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3267
3268                         /* closer to the next subdivision, so shift forward */
3269
3270                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3271
3272                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3273
3274                         if (ticks > BBT_Time::ticks_per_beat) {
3275                                 ++beats;
3276                                 ticks -= BBT_Time::ticks_per_beat;
3277                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3278                         }
3279
3280                 } else if (rem > 0) {
3281
3282                         /* closer to previous subdivision, so shift backward */
3283
3284                         if (rem > ticks) {
3285                                 if (beats == 0) {
3286                                         /* can't go backwards past zero, so ... */
3287                                         return 0;
3288                                 }
3289                                 /* step back to previous beat */
3290                                 --beats;
3291                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3292                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3293                         } else {
3294                                 ticks = lrint (ticks - rem);
3295                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3296                         }
3297                 } else {
3298                         /* on the subdivision, do nothing */
3299                 }
3300         }
3301
3302         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
3303
3304         return ret_frame;
3305 }
3306
3307 framepos_t
3308 TempoMap::round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3309 {
3310         Glib::Threads::RWLock::ReaderLock lm (lock);
3311         uint32_t ticks = (uint32_t) floor (max (0.0, quarter_note_at_frame_locked (_metrics, fr)) * BBT_Time::ticks_per_beat);
3312         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3313         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3314
3315         ticks -= beats * BBT_Time::ticks_per_beat;
3316
3317         if (dir > 0) {
3318                 /* round to next (or same iff dir == RoundUpMaybe) */
3319
3320                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3321
3322                 if (mod == 0 && dir == RoundUpMaybe) {
3323                         /* right on the subdivision, which is fine, so do nothing */
3324
3325                 } else if (mod == 0) {
3326                         /* right on the subdivision, so the difference is just the subdivision ticks */
3327                         ticks += ticks_one_subdivisions_worth;
3328
3329                 } else {
3330                         /* not on subdivision, compute distance to next subdivision */
3331
3332                         ticks += ticks_one_subdivisions_worth - mod;
3333                 }
3334
3335                 if (ticks >= BBT_Time::ticks_per_beat) {
3336                         ticks -= BBT_Time::ticks_per_beat;
3337                 }
3338         } else if (dir < 0) {
3339
3340                 /* round to previous (or same iff dir == RoundDownMaybe) */
3341
3342                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3343
3344                 if (difference == 0 && dir == RoundDownAlways) {
3345                         /* right on the subdivision, but force-rounding down,
3346                            so the difference is just the subdivision ticks */
3347                         difference = ticks_one_subdivisions_worth;
3348                 }
3349
3350                 if (ticks < difference) {
3351                         ticks = BBT_Time::ticks_per_beat - ticks;
3352                 } else {
3353                         ticks -= difference;
3354                 }
3355
3356         } else {
3357                 /* round to nearest */
3358                 double rem;
3359
3360                 /* compute the distance to the previous and next subdivision */
3361
3362                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3363
3364                         /* closer to the next subdivision, so shift forward */
3365
3366                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3367
3368                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3369
3370                         if (ticks > BBT_Time::ticks_per_beat) {
3371                                 ++beats;
3372                                 ticks -= BBT_Time::ticks_per_beat;
3373                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3374                         }
3375
3376                 } else if (rem > 0) {
3377
3378                         /* closer to previous subdivision, so shift backward */
3379
3380                         if (rem > ticks) {
3381                                 if (beats == 0) {
3382                                         /* can't go backwards past zero, so ... */
3383                                         return 0;
3384                                 }
3385                                 /* step back to previous beat */
3386                                 --beats;
3387                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3388                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3389                         } else {
3390                                 ticks = lrint (ticks - rem);
3391                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3392                         }
3393                 } else {
3394                         /* on the subdivision, do nothing */
3395                 }
3396         }
3397
3398         const framepos_t ret_frame = frame_at_quarter_note_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
3399
3400         return ret_frame;
3401 }
3402
3403 framepos_t
3404 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
3405 {
3406         Glib::Threads::RWLock::ReaderLock lm (lock);
3407
3408         const double beat_at_framepos = max (0.0, beat_at_frame_locked (_metrics, frame));
3409         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
3410
3411         switch (type) {
3412         case Bar:
3413                 if (dir < 0) {
3414                         /* find bar previous to 'frame' */
3415                         bbt.beats = 1;
3416                         bbt.ticks = 0;
3417                         return frame_at_bbt_locked (_metrics, bbt);
3418
3419                 } else if (dir > 0) {
3420                         /* find bar following 'frame' */
3421                         ++bbt.bars;
3422                         bbt.beats = 1;
3423                         bbt.ticks = 0;
3424                         return frame_at_bbt_locked (_metrics, bbt);
3425                 } else {
3426                         /* true rounding: find nearest bar */
3427                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
3428                         bbt.beats = 1;
3429                         bbt.ticks = 0;
3430                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
3431                         ++bbt.bars;
3432                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
3433
3434                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
3435                                 return next_ft;
3436                         } else {
3437                                 return prev_ft;
3438                         }
3439                 }
3440
3441                 break;
3442
3443         case Beat:
3444                 if (dir < 0) {
3445                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
3446                 } else if (dir > 0) {
3447                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
3448                 } else {
3449                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
3450                 }
3451                 break;
3452         }
3453
3454         return 0;
3455 }
3456
3457 void
3458 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
3459                     framepos_t lower, framepos_t upper)
3460 {
3461         Glib::Threads::RWLock::ReaderLock lm (lock);
3462         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
3463         framecnt_t pos = 0;
3464         /* although the map handles negative beats, bbt doesn't. */
3465         if (cnt < 0.0) {
3466                 cnt = 0.0;
3467         }
3468
3469         if (frame_at_beat_locked (_metrics, cnt) >= upper) {
3470                 return;
3471         }
3472
3473         while (pos < upper) {
3474                 pos = frame_at_beat_locked (_metrics, cnt);
3475                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
3476                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
3477                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
3478                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
3479                 ++cnt;
3480         }
3481 }
3482
3483 const TempoSection&
3484 TempoMap::tempo_section_at_frame (framepos_t frame) const
3485 {
3486         Glib::Threads::RWLock::ReaderLock lm (lock);
3487         return tempo_section_at_frame_locked (_metrics, frame);
3488 }
3489
3490 const TempoSection&
3491 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3492 {
3493         TempoSection* prev = 0;
3494
3495         TempoSection* t;
3496
3497         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3498
3499                 if ((*i)->is_tempo()) {
3500                         t = static_cast<TempoSection*> (*i);
3501                         if (!t->active()) {
3502                                 continue;
3503                         }
3504                         if (prev && t->frame() > frame) {
3505                                 break;
3506                         }
3507
3508                         prev = t;
3509                 }
3510         }
3511
3512         if (prev == 0) {
3513                 fatal << endmsg;
3514                 abort(); /*NOTREACHED*/
3515         }
3516
3517         return *prev;
3518 }
3519
3520 const TempoSection&
3521 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3522 {
3523         TempoSection* prev_t = 0;
3524         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
3525
3526         TempoSection* t;
3527
3528         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3529                 if ((*i)->is_tempo()) {
3530                         t = static_cast<TempoSection*> (*i);
3531                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
3532                                 break;
3533                         }
3534                         prev_t = t;
3535                 }
3536
3537         }
3538         return *prev_t;
3539 }
3540
3541 /* don't use this to calculate length (the tempo is only correct for this frame).
3542    do that stuff based on the beat_at_frame and frame_at_beat api
3543 */
3544 double
3545 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3546 {
3547         Glib::Threads::RWLock::ReaderLock lm (lock);
3548
3549         const TempoSection* ts_at = 0;
3550         const TempoSection* ts_after = 0;
3551         Metrics::const_iterator i;
3552         TempoSection* t;
3553
3554         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3555
3556                 if ((*i)->is_tempo()) {
3557                         t = static_cast<TempoSection*> (*i);
3558                         if (!t->active()) {
3559                                 continue;
3560                         }
3561                         if (ts_at && (*i)->frame() > frame) {
3562                                 ts_after = t;
3563                                 break;
3564                         }
3565                         ts_at = t;
3566                 }
3567         }
3568
3569         if (ts_after) {
3570                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * 4.0);
3571         }
3572         /* must be treated as constant tempo */
3573         return ts_at->frames_per_beat (_frame_rate);
3574 }
3575
3576 const MeterSection&
3577 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3578 {
3579         Metrics::const_iterator i;
3580         MeterSection* prev = 0;
3581
3582         MeterSection* m;
3583
3584         for (i = metrics.begin(); i != metrics.end(); ++i) {
3585
3586                 if (!(*i)->is_tempo()) {
3587                         m = static_cast<MeterSection*> (*i);
3588
3589                         if (prev && (*i)->frame() > frame) {
3590                                 break;
3591                         }
3592
3593                         prev = m;
3594                 }
3595         }
3596
3597         if (prev == 0) {
3598                 fatal << endmsg;
3599                 abort(); /*NOTREACHED*/
3600         }
3601
3602         return *prev;
3603 }
3604
3605
3606 const MeterSection&
3607 TempoMap::meter_section_at_frame (framepos_t frame) const
3608 {
3609         Glib::Threads::RWLock::ReaderLock lm (lock);
3610         return meter_section_at_frame_locked (_metrics, frame);
3611 }
3612
3613 const MeterSection&
3614 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3615 {
3616         MeterSection* prev_m = 0;
3617
3618         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3619                 MeterSection* m;
3620                 if (!(*i)->is_tempo()) {
3621                         m = static_cast<MeterSection*> (*i);
3622                         if (prev_m && m->beat() > beat) {
3623                                 break;
3624                         }
3625                         prev_m = m;
3626                 }
3627
3628         }
3629         return *prev_m;
3630 }
3631
3632 const MeterSection&
3633 TempoMap::meter_section_at_beat (double beat) const
3634 {
3635         Glib::Threads::RWLock::ReaderLock lm (lock);
3636         return meter_section_at_beat_locked (_metrics, beat);
3637 }
3638
3639 const Meter&
3640 TempoMap::meter_at_frame (framepos_t frame) const
3641 {
3642         TempoMetric m (metric_at (frame));
3643         return m.meter();
3644 }
3645
3646 void
3647 TempoMap::fix_legacy_session ()
3648 {
3649         MeterSection* prev_m = 0;
3650         TempoSection* prev_t = 0;
3651
3652         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3653                 MeterSection* m;
3654                 TempoSection* t;
3655
3656                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3657                         if (!m->movable()) {
3658                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3659                                 m->set_beat (bbt);
3660                                 m->set_pulse (0.0);
3661                                 m->set_frame (0);
3662                                 m->set_position_lock_style (AudioTime);
3663                                 prev_m = m;
3664                                 continue;
3665                         }
3666                         if (prev_m) {
3667                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3668                                                                           + (m->bbt().beats - 1)
3669                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3670                                                                           , m->bbt());
3671                                 m->set_beat (start);
3672                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3673                                         + (m->bbt().beats - 1)
3674                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3675                                 m->set_pulse (start_beat / prev_m->note_divisor());
3676                         }
3677                         prev_m = m;
3678                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3679
3680                         if (!t->active()) {
3681                                 continue;
3682                         }
3683
3684                         if (!t->movable()) {
3685                                 t->set_pulse (0.0);
3686                                 t->set_frame (0);
3687                                 t->set_position_lock_style (AudioTime);
3688                                 prev_t = t;
3689                                 continue;
3690                         }
3691
3692                         if (prev_t) {
3693                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3694                                         + (t->legacy_bbt().beats - 1)
3695                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3696                                 if (prev_m) {
3697                                         t->set_pulse (beat / prev_m->note_divisor());
3698                                 } else {
3699                                         /* really shouldn't happen but.. */
3700                                         t->set_pulse (beat / 4.0);
3701                                 }
3702                         }
3703                         prev_t = t;
3704                 }
3705         }
3706 }
3707
3708 XMLNode&
3709 TempoMap::get_state ()
3710 {
3711         Metrics::const_iterator i;
3712         XMLNode *root = new XMLNode ("TempoMap");
3713
3714         {
3715                 Glib::Threads::RWLock::ReaderLock lm (lock);
3716                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3717                         root->add_child_nocopy ((*i)->get_state());
3718                 }
3719         }
3720
3721         return *root;
3722 }
3723
3724 int
3725 TempoMap::set_state (const XMLNode& node, int /*version*/)
3726 {
3727         {
3728                 Glib::Threads::RWLock::WriterLock lm (lock);
3729
3730                 XMLNodeList nlist;
3731                 XMLNodeConstIterator niter;
3732                 Metrics old_metrics (_metrics);
3733                 _metrics.clear();
3734
3735                 nlist = node.children();
3736
3737                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3738                         XMLNode* child = *niter;
3739
3740                         if (child->name() == TempoSection::xml_state_node_name) {
3741
3742                                 try {
3743                                         TempoSection* ts = new TempoSection (*child);
3744                                         _metrics.push_back (ts);
3745                                 }
3746
3747                                 catch (failed_constructor& err){
3748                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3749                                         _metrics = old_metrics;
3750                                         old_metrics.clear();
3751                                         break;
3752                                 }
3753
3754                         } else if (child->name() == MeterSection::xml_state_node_name) {
3755
3756                                 try {
3757                                         MeterSection* ms = new MeterSection (*child);
3758                                         _metrics.push_back (ms);
3759                                 }
3760
3761                                 catch (failed_constructor& err) {
3762                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3763                                         _metrics = old_metrics;
3764                                         old_metrics.clear();
3765                                         break;
3766                                 }
3767                         }
3768                 }
3769
3770                 if (niter == nlist.end()) {
3771                         MetricSectionSorter cmp;
3772                         _metrics.sort (cmp);
3773                 }
3774
3775                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3776                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3777                         TempoSection* t;
3778                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3779                                 if (t->legacy_bbt().bars != 0) {
3780                                         fix_legacy_session();
3781                                         break;
3782                                 }
3783                                 break;
3784                         }
3785                 }
3786
3787                 /* check for multiple tempo/meters at the same location, which
3788                    ardour2 somehow allowed.
3789                 */
3790
3791                 Metrics::iterator prev = _metrics.end();
3792                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3793                         if (prev != _metrics.end()) {
3794                                 MeterSection* ms;
3795                                 MeterSection* prev_m;
3796                                 TempoSection* ts;
3797                                 TempoSection* prev_t;
3798                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3799                                         if (prev_m->pulse() == ms->pulse()) {
3800                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3801                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3802                                                 return -1;
3803                                         }
3804                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3805                                         if (prev_t->pulse() == ts->pulse()) {
3806                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3807                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3808                                                 return -1;
3809                                         }
3810                                 }
3811                         }
3812                         prev = i;
3813                 }
3814
3815                 recompute_map (_metrics);
3816
3817                 Metrics::const_iterator d = old_metrics.begin();
3818                 while (d != old_metrics.end()) {
3819                         delete (*d);
3820                         ++d;
3821                 }
3822                 old_metrics.clear ();
3823         }
3824
3825         PropertyChanged (PropertyChange ());
3826
3827         return 0;
3828 }
3829
3830 void
3831 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3832 {
3833         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3834         const MeterSection* m;
3835         const TempoSection* t;
3836         const TempoSection* prev_t = 0;
3837
3838         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3839
3840                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3841                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3842                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3843                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3844                         if (prev_t) {
3845                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3846                                 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;
3847                         }
3848                         prev_t = t;
3849                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3850                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3851                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3852                 }
3853         }
3854         o << "------" << std::endl;
3855 }
3856
3857 int
3858 TempoMap::n_tempos() const
3859 {
3860         Glib::Threads::RWLock::ReaderLock lm (lock);
3861         int cnt = 0;
3862
3863         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3864                 if ((*i)->is_tempo()) {
3865                         cnt++;
3866                 }
3867         }
3868
3869         return cnt;
3870 }
3871
3872 int
3873 TempoMap::n_meters() const
3874 {
3875         Glib::Threads::RWLock::ReaderLock lm (lock);
3876         int cnt = 0;
3877
3878         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3879                 if (!(*i)->is_tempo()) {
3880                         cnt++;
3881                 }
3882         }
3883
3884         return cnt;
3885 }
3886
3887 void
3888 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3889 {
3890         {
3891                 Glib::Threads::RWLock::WriterLock lm (lock);
3892                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3893                         if ((*i)->frame() >= where && (*i)->movable ()) {
3894                                 (*i)->set_frame ((*i)->frame() + amount);
3895                         }
3896                 }
3897
3898                 /* now reset the BBT time of all metrics, based on their new
3899                  * audio time. This is the only place where we do this reverse
3900                  * timestamp.
3901                  */
3902
3903                 Metrics::iterator i;
3904                 const MeterSection* meter;
3905                 const TempoSection* tempo;
3906                 MeterSection *m;
3907                 TempoSection *t;
3908
3909                 meter = &first_meter ();
3910                 tempo = &first_tempo ();
3911
3912                 BBT_Time start;
3913                 BBT_Time end;
3914
3915                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3916
3917                 bool first = true;
3918                 MetricSection* prev = 0;
3919
3920                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3921
3922                         BBT_Time bbt;
3923                         //TempoMetric metric (*meter, *tempo);
3924                         MeterSection* ms = const_cast<MeterSection*>(meter);
3925                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3926                         if (prev) {
3927                                 if (ts){
3928                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3929                                                 if (!t->active()) {
3930                                                         continue;
3931                                                 }
3932                                                 ts->set_pulse (t->pulse());
3933                                         }
3934                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3935                                                 ts->set_pulse (m->pulse());
3936                                         }
3937                                         ts->set_frame (prev->frame());
3938
3939                                 }
3940                                 if (ms) {
3941                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3942                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3943                                                 ms->set_beat (start);
3944                                                 ms->set_pulse (m->pulse());
3945                                         }
3946                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3947                                                 if (!t->active()) {
3948                                                         continue;
3949                                                 }
3950                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3951                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3952                                                 ms->set_beat (start);
3953                                                 ms->set_pulse (t->pulse());
3954                                         }
3955                                         ms->set_frame (prev->frame());
3956                                 }
3957
3958                         } else {
3959                                 // metric will be at frames=0 bbt=1|1|0 by default
3960                                 // which is correct for our purpose
3961                         }
3962
3963                         // cerr << bbt << endl;
3964
3965                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3966                                 if (!t->active()) {
3967                                         continue;
3968                                 }
3969                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3970                                 tempo = t;
3971                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3972                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3973                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3974
3975                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3976
3977                                 if (first) {
3978                                         first = false;
3979                                 } else {
3980
3981                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3982                                                 /* round up to next beat */
3983                                                 bbt.beats += 1;
3984                                         }
3985
3986                                         bbt.ticks = 0;
3987
3988                                         if (bbt.beats != 1) {
3989                                                 /* round up to next bar */
3990                                                 bbt.bars += 1;
3991                                                 bbt.beats = 1;
3992                                         }
3993                                 }
3994                                 pair<double, BBT_Time> start = make_pair (max (0.0, beat_at_frame_locked (_metrics, m->frame())), bbt);
3995                                 m->set_beat (start);
3996                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3997                                 meter = m;
3998                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3999                         } else {
4000                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
4001                                 abort(); /*NOTREACHED*/
4002                         }
4003
4004                         prev = (*i);
4005                 }
4006
4007                 recompute_map (_metrics);
4008         }
4009
4010
4011         PropertyChanged (PropertyChange ());
4012 }
4013 bool
4014 TempoMap::remove_time (framepos_t where, framecnt_t amount)
4015 {
4016         bool moved = false;
4017
4018         std::list<MetricSection*> metric_kill_list;
4019
4020         TempoSection* last_tempo = NULL;
4021         MeterSection* last_meter = NULL;
4022         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
4023         bool meter_after = false; // is there a meter marker likewise?
4024         {
4025                 Glib::Threads::RWLock::WriterLock lm (lock);
4026                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4027                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
4028                                 metric_kill_list.push_back(*i);
4029                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
4030                                 if (lt)
4031                                         last_tempo = lt;
4032                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
4033                                 if (lm)
4034                                         last_meter = lm;
4035                         }
4036                         else if ((*i)->frame() >= where) {
4037                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
4038                                 (*i)->set_frame ((*i)->frame() - amount);
4039                                 if ((*i)->frame() == where) {
4040                                         // marker was immediately after end of range
4041                                         tempo_after = dynamic_cast<TempoSection*> (*i);
4042                                         meter_after = dynamic_cast<MeterSection*> (*i);
4043                                 }
4044                                 moved = true;
4045                         }
4046                 }
4047
4048                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
4049                 if (last_tempo && !tempo_after) {
4050                         metric_kill_list.remove(last_tempo);
4051                         last_tempo->set_frame(where);
4052                         moved = true;
4053                 }
4054                 if (last_meter && !meter_after) {
4055                         metric_kill_list.remove(last_meter);
4056                         last_meter->set_frame(where);
4057                         moved = true;
4058                 }
4059
4060                 //remove all the remaining metrics
4061                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
4062                         _metrics.remove(*i);
4063                         moved = true;
4064                 }
4065
4066                 if (moved) {
4067                         recompute_map (_metrics);
4068                 }
4069         }
4070         PropertyChanged (PropertyChange ());
4071         return moved;
4072 }
4073
4074 /** Add some (fractional) beats to a session frame position, and return the result in frames.
4075  *  pos can be -ve, if required.
4076  */
4077 framepos_t
4078 TempoMap::framepos_plus_beats (framepos_t frame, Evoral::Beats beats) const
4079 {
4080         Glib::Threads::RWLock::ReaderLock lm (lock);
4081
4082         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, frame) + beats.to_double());
4083 }
4084 framepos_t
4085 TempoMap::framepos_plus_qn (framepos_t frame, Evoral::Beats quarter_note) const
4086 {
4087         Glib::Threads::RWLock::ReaderLock lm (lock);
4088
4089         return frame_at_quarter_note_locked (_metrics, quarter_note_at_frame_locked (_metrics, frame) + quarter_note.to_double());
4090 }
4091
4092 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
4093 framepos_t
4094 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
4095 {
4096         Glib::Threads::RWLock::ReaderLock lm (lock);
4097
4098         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
4099 }
4100
4101 /** Add the BBT interval op to pos and return the result */
4102 framepos_t
4103 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
4104 {
4105         Glib::Threads::RWLock::ReaderLock lm (lock);
4106
4107         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
4108         pos_bbt.ticks += op.ticks;
4109         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
4110                 ++pos_bbt.beats;
4111                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
4112         }
4113         pos_bbt.beats += op.beats;
4114         /* the meter in effect will start on the bar */
4115         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();
4116         while (pos_bbt.beats >= divisions_per_bar + 1) {
4117                 ++pos_bbt.bars;
4118                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
4119                 pos_bbt.beats -= divisions_per_bar;
4120         }
4121         pos_bbt.bars += op.bars;
4122
4123         return frame_at_bbt_locked (_metrics, pos_bbt);
4124 }
4125
4126 /** Count the number of beats that are equivalent to distance when going forward,
4127     starting at pos.
4128 */
4129 Evoral::Beats
4130 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
4131 {
4132         Glib::Threads::RWLock::ReaderLock lm (lock);
4133
4134         return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
4135 }
4136
4137 Evoral::Beats
4138 TempoMap::framewalk_to_qn (framepos_t pos, framecnt_t distance) const
4139 {
4140         Glib::Threads::RWLock::ReaderLock lm (lock);
4141
4142         return Evoral::Beats (quarter_note_at_frame_locked (_metrics, pos + distance) - quarter_note_at_frame_locked (_metrics, pos));
4143 }
4144 struct bbtcmp {
4145     bool operator() (const BBT_Time& a, const BBT_Time& b) {
4146             return a < b;
4147     }
4148 };
4149
4150 std::ostream&
4151 operator<< (std::ostream& o, const Meter& m) {
4152         return o << m.divisions_per_bar() << '/' << m.note_divisor();
4153 }
4154
4155 std::ostream&
4156 operator<< (std::ostream& o, const Tempo& t) {
4157         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
4158 }
4159
4160 std::ostream&
4161 operator<< (std::ostream& o, const MetricSection& section) {
4162
4163         o << "MetricSection @ " << section.frame() << ' ';
4164
4165         const TempoSection* ts;
4166         const MeterSection* ms;
4167
4168         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
4169                 o << *((const Tempo*) ts);
4170         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
4171                 o << *((const Meter*) ms);
4172         }
4173
4174         return o;
4175 }