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