Improve the performance of TempoMap::frame_at_beat ().
[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 "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)
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), "%f", 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), "%f", _beats_per_minute);
187         root->add_property ("beats-per-minute", buf);
188         snprintf (buf, sizeof (buf), "%f", _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), 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), "%f", _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), "%f", _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         Metrics::iterator i;
776
777         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
778                 TempoSection* t = 0;
779                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
780                         if (meter.frame() == (*i)->frame()) {
781                                 if (t->locked_to_meter()) {
782                                         delete (*i);
783                                         _metrics.erase (i);
784                                         break;
785                                 }
786                         }
787                 }
788         }
789
790         for (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
984         do_insert (t);
985
986         if (recompute) {
987                 if (pls == AudioTime) {
988                         solve_map_frame (_metrics, t, t->frame());
989                 } else {
990                         solve_map_pulse (_metrics, t, t->pulse());
991                 }
992                 recompute_meters (_metrics);
993         }
994
995         return t;
996 }
997
998 MeterSection*
999 TempoMap::add_meter (const Meter& meter, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
1000 {
1001         MeterSection* m = 0;
1002         {
1003                 Glib::Threads::RWLock::WriterLock lm (lock);
1004                 m = add_meter_locked (meter, beat, where, frame, pls, true);
1005         }
1006
1007
1008 #ifndef NDEBUG
1009         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
1010                 dump (_metrics, std::cerr);
1011         }
1012 #endif
1013
1014         PropertyChanged (PropertyChange ());
1015         return m;
1016 }
1017
1018 void
1019 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
1020 {
1021         {
1022                 Glib::Threads::RWLock::WriterLock lm (lock);
1023                 const double beat = beat_at_bbt_locked (_metrics, where);
1024
1025                 if (ms.movable()) {
1026                         remove_meter_locked (ms);
1027                         add_meter_locked (meter, beat, where, frame, pls, true);
1028                 } else {
1029                         MeterSection& first (first_meter());
1030                         TempoSection& first_t (first_tempo());
1031                         /* cannot move the first meter section */
1032                         *static_cast<Meter*>(&first) = meter;
1033                         first.set_position_lock_style (AudioTime);
1034                         first.set_pulse (0.0);
1035                         first.set_frame (frame);
1036                         pair<double, BBT_Time> beat = make_pair (0.0, BBT_Time (1, 1, 0));
1037                         first.set_beat (beat);
1038                         first_t.set_frame (first.frame());
1039                         first_t.set_pulse (0.0);
1040                         first_t.set_position_lock_style (AudioTime);
1041                         recompute_map (_metrics);
1042                 }
1043         }
1044
1045         PropertyChanged (PropertyChange ());
1046 }
1047
1048 MeterSection*
1049 TempoMap::add_meter_locked (const Meter& meter, double beat, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
1050 {
1051         const MeterSection& prev_m = meter_section_at_frame_locked  (_metrics, frame - 1);
1052         const double pulse = ((where.bars - prev_m.bbt().bars) * (prev_m.divisions_per_bar() / prev_m.note_divisor())) + prev_m.pulse();
1053
1054         if (pls == AudioTime) {
1055                 /* add meter-locked tempo */
1056                 add_tempo_locked (tempo_at_frame_locked (_metrics, frame), pulse,  frame, TempoSection::Ramp, AudioTime, true, true);
1057         }
1058
1059         MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
1060
1061         do_insert (new_meter);
1062
1063         if (recompute) {
1064
1065                 if (pls == AudioTime) {
1066                         solve_map_frame (_metrics, new_meter, frame);
1067                 } else {
1068                         solve_map_bbt (_metrics, new_meter, where);
1069                 }
1070         }
1071
1072         return new_meter;
1073 }
1074
1075 void
1076 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
1077 {
1078         Tempo newtempo (beats_per_minute, note_type);
1079         TempoSection* t;
1080
1081         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1082                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1083                         if (!t->active()) {
1084                                 continue;
1085                         }
1086                         {
1087                                 Glib::Threads::RWLock::WriterLock lm (lock);
1088                                 *((Tempo*) t) = newtempo;
1089                                 recompute_map (_metrics);
1090                         }
1091                         PropertyChanged (PropertyChange ());
1092                         break;
1093                 }
1094         }
1095 }
1096
1097 void
1098 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
1099 {
1100         Tempo newtempo (beats_per_minute, note_type);
1101
1102         TempoSection* prev;
1103         TempoSection* first;
1104         Metrics::iterator i;
1105
1106         /* find the TempoSection immediately preceding "where"
1107          */
1108
1109         for (first = 0, i = _metrics.begin(), prev = 0; i != _metrics.end(); ++i) {
1110
1111                 if ((*i)->frame() > where) {
1112                         break;
1113                 }
1114
1115                 TempoSection* t;
1116
1117                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1118                         if (!t->active()) {
1119                                 continue;
1120                         }
1121                         if (!first) {
1122                                 first = t;
1123                         }
1124                         prev = t;
1125                 }
1126         }
1127
1128         if (!prev) {
1129                 if (!first) {
1130                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
1131                         return;
1132                 }
1133
1134                 prev = first;
1135         }
1136
1137         /* reset */
1138
1139         {
1140                 Glib::Threads::RWLock::WriterLock lm (lock);
1141                 /* cannot move the first tempo section */
1142                 *((Tempo*)prev) = newtempo;
1143                 recompute_map (_metrics);
1144         }
1145
1146         PropertyChanged (PropertyChange ());
1147 }
1148
1149 const MeterSection&
1150 TempoMap::first_meter () const
1151 {
1152         const MeterSection *m = 0;
1153
1154         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1155                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
1156                         return *m;
1157                 }
1158         }
1159
1160         fatal << _("programming error: no meter section in tempo map!") << endmsg;
1161         abort(); /*NOTREACHED*/
1162         return *m;
1163 }
1164
1165 MeterSection&
1166 TempoMap::first_meter ()
1167 {
1168         MeterSection *m = 0;
1169
1170         /* CALLER MUST HOLD LOCK */
1171
1172         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1173                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1174                         return *m;
1175                 }
1176         }
1177
1178         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1179         abort(); /*NOTREACHED*/
1180         return *m;
1181 }
1182
1183 const TempoSection&
1184 TempoMap::first_tempo () const
1185 {
1186         const TempoSection *t = 0;
1187
1188         /* CALLER MUST HOLD LOCK */
1189
1190         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1191                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1192                         if (!t->active()) {
1193                                 continue;
1194                         }
1195                         if (!t->movable()) {
1196                                 return *t;
1197                         }
1198                 }
1199         }
1200
1201         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1202         abort(); /*NOTREACHED*/
1203         return *t;
1204 }
1205
1206 TempoSection&
1207 TempoMap::first_tempo ()
1208 {
1209         TempoSection *t = 0;
1210
1211         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1212                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1213                         if (!t->active()) {
1214                                 continue;
1215                         }
1216                         if (!t->movable()) {
1217                                 return *t;
1218                         }
1219                 }
1220         }
1221
1222         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1223         abort(); /*NOTREACHED*/
1224         return *t;
1225 }
1226 void
1227 TempoMap::recompute_tempos (Metrics& metrics)
1228 {
1229         TempoSection* prev_t = 0;
1230
1231         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1232                 TempoSection* t;
1233
1234                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1235                         if (!t->active()) {
1236                                 continue;
1237                         }
1238                         if (!t->movable()) {
1239                                 if (!prev_t) {
1240                                         t->set_pulse (0.0);
1241                                         prev_t = t;
1242                                         continue;
1243                                 }
1244                         }
1245                         if (prev_t) {
1246                                 if (t->position_lock_style() == AudioTime) {
1247                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1248                                         if (!t->locked_to_meter()) {
1249                                                 t->set_pulse (prev_t->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate));
1250                                         }
1251
1252                                 } else {
1253                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1254                                         t->set_frame (prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate));
1255
1256                                 }
1257                         }
1258                         prev_t = t;
1259                 }
1260         }
1261         prev_t->set_c_func (0.0);
1262 }
1263
1264 /* tempos must be positioned correctly.
1265    the current approach is to use a meter's bbt time as its base position unit.
1266    an audio-locked meter requires a recomputation of pulse and beat (but not bbt),
1267    while a music-locked meter requires recomputations of frame pulse and beat (but not bbt)
1268 */
1269 void
1270 TempoMap::recompute_meters (Metrics& metrics)
1271 {
1272         MeterSection* meter = 0;
1273         MeterSection* prev_m = 0;
1274
1275         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1276                 if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
1277                         if (meter->position_lock_style() == AudioTime) {
1278                                 double pulse = 0.0;
1279                                 pair<double, BBT_Time> b_bbt;
1280                                 TempoSection* meter_locked_tempo = 0;
1281                                 for (Metrics::const_iterator ii = metrics.begin(); ii != metrics.end(); ++ii) {
1282                                         TempoSection* t;
1283                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
1284                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
1285                                                         meter_locked_tempo = t;
1286                                                         break;
1287                                                 }
1288                                         }
1289                                 }
1290
1291                                 if (prev_m) {
1292                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1293                                         if (beats + prev_m->beat() != meter->beat()) {
1294                                                 /* reordering caused a bbt change */
1295                                                 b_bbt = make_pair (beats + prev_m->beat()
1296                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1297                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1298
1299                                         } else if (meter->movable()) {
1300                                                 b_bbt = make_pair (meter->beat(), meter->bbt());
1301                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1302                                         }
1303                                 } else {
1304                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
1305                                 }
1306                                 if (meter_locked_tempo) {
1307                                         meter_locked_tempo->set_pulse (pulse);
1308                                 }
1309                                 meter->set_beat (b_bbt);
1310                                 meter->set_pulse (pulse);
1311
1312                         } else {
1313                                 /* MusicTime */
1314                                 double pulse = 0.0;
1315                                 pair<double, BBT_Time> b_bbt;
1316                                 if (prev_m) {
1317                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1318                                         if (beats + prev_m->beat() != meter->beat()) {
1319                                                 /* reordering caused a bbt change */
1320                                                 b_bbt = make_pair (beats + prev_m->beat()
1321                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1322                                         } else {
1323                                                 b_bbt = make_pair (beats + prev_m->beat(), meter->bbt());
1324                                         }
1325                                         pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
1326                                 } else {
1327                                         /* shouldn't happen - the first is audio-locked */
1328                                         pulse = pulse_at_beat_locked (metrics, meter->beat());
1329                                         b_bbt = make_pair (meter->beat(), meter->bbt());
1330                                 }
1331
1332                                 meter->set_beat (b_bbt);
1333                                 meter->set_pulse (pulse);
1334                                 meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1335                         }
1336
1337                         prev_m = meter;
1338                 }
1339         }
1340 }
1341
1342 void
1343 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1344 {
1345         /* CALLER MUST HOLD WRITE LOCK */
1346
1347         if (end < 0) {
1348
1349                 /* we will actually stop once we hit
1350                    the last metric.
1351                 */
1352                 end = max_framepos;
1353
1354         }
1355
1356         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1357
1358         if (end == 0) {
1359                 /* silly call from Session::process() during startup
1360                  */
1361                 return;
1362         }
1363
1364         recompute_tempos (metrics);
1365         recompute_meters (metrics);
1366 }
1367
1368 TempoMetric
1369 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1370 {
1371         Glib::Threads::RWLock::ReaderLock lm (lock);
1372         TempoMetric m (first_meter(), first_tempo());
1373
1374         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1375            at something, because we insert the default tempo and meter during
1376            TempoMap construction.
1377
1378            now see if we can find better candidates.
1379         */
1380
1381         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1382
1383                 if ((*i)->frame() > frame) {
1384                         break;
1385                 }
1386
1387                 m.set_metric(*i);
1388
1389                 if (last) {
1390                         *last = i;
1391                 }
1392         }
1393
1394         return m;
1395 }
1396
1397 /* XX meters only */
1398 TempoMetric
1399 TempoMap::metric_at (BBT_Time bbt) const
1400 {
1401         Glib::Threads::RWLock::ReaderLock lm (lock);
1402         TempoMetric m (first_meter(), first_tempo());
1403
1404         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1405            at something, because we insert the default tempo and meter during
1406            TempoMap construction.
1407
1408            now see if we can find better candidates.
1409         */
1410
1411         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1412                 MeterSection* mw;
1413                 if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
1414                         BBT_Time section_start (mw->bbt());
1415
1416                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1417                                 break;
1418                         }
1419
1420                         m.set_metric (*i);
1421                 }
1422         }
1423
1424         return m;
1425 }
1426
1427 double
1428 TempoMap::beat_at_frame (const framecnt_t& frame) const
1429 {
1430         Glib::Threads::RWLock::ReaderLock lm (lock);
1431         return beat_at_frame_locked (_metrics, frame);
1432 }
1433
1434 /* meter / tempo section based */
1435 double
1436 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1437 {
1438         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
1439         MeterSection* prev_m = 0;
1440         MeterSection* next_m = 0;
1441
1442         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1443                 MeterSection* m;
1444                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1445                         if (prev_m && m->frame() > frame) {
1446                                 next_m = m;
1447                                 break;
1448                         }
1449                         prev_m = m;
1450                 }
1451         }
1452         if (frame < prev_m->frame()) {
1453                 return 0.0;
1454         }
1455         const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
1456
1457         /* audio locked meters fake their beat */
1458         if (next_m && next_m->beat() < beat) {
1459                 return next_m->beat();
1460         }
1461
1462         return beat;
1463 }
1464
1465 framecnt_t
1466 TempoMap::frame_at_beat (const double& beat) const
1467 {
1468         Glib::Threads::RWLock::ReaderLock lm (lock);
1469         return frame_at_beat_locked (_metrics, beat);
1470 }
1471
1472 /* meter & tempo section based */
1473 framecnt_t
1474 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1475 {
1476         MeterSection* prev_m = 0;
1477         TempoSection* prev_t = 0;
1478
1479         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1480                 MeterSection* m;
1481                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1482                         if (prev_m && m->beat() > beat) {
1483                                 break;
1484                         }
1485                         prev_m = m;
1486                 }
1487         }
1488
1489         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1490                 TempoSection* t;
1491                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1492                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
1493                                 break;
1494                         }
1495                         prev_t = t;
1496                 }
1497
1498         }
1499
1500         return prev_t->frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
1501 }
1502
1503 Tempo
1504 TempoMap::tempo_at_frame (const framepos_t& frame) const
1505 {
1506         Glib::Threads::RWLock::ReaderLock lm (lock);
1507         return tempo_at_frame_locked (_metrics, frame);
1508 }
1509
1510 Tempo
1511 TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1512 {
1513         TempoSection* prev_t = 0;
1514
1515         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1516                 TempoSection* t;
1517                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1518                         if (!t->active()) {
1519                                 continue;
1520                         }
1521                         if ((prev_t) && t->frame() > frame) {
1522                                 /* t is the section past frame */
1523                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
1524                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
1525                                 return ret_tempo;
1526                         }
1527                         prev_t = t;
1528                 }
1529         }
1530
1531         const double ret = prev_t->beats_per_minute();
1532         const Tempo ret_tempo (ret, prev_t->note_type ());
1533
1534         return ret_tempo;
1535 }
1536
1537 /** returns the frame at which the supplied tempo occurs, or
1538  *  the frame of the last tempo section (search exhausted)
1539  *  only the position of the first occurence will be returned
1540  *  (extend me)
1541 */
1542 framepos_t
1543 TempoMap::frame_at_tempo (const Tempo& tempo) const
1544 {
1545         Glib::Threads::RWLock::ReaderLock lm (lock);
1546         return frame_at_tempo_locked (_metrics, tempo);
1547 }
1548
1549
1550 framepos_t
1551 TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1552 {
1553         TempoSection* prev_t = 0;
1554         const double tempo_ppm = tempo.beats_per_minute() / tempo.note_type();
1555
1556         Metrics::const_iterator i;
1557
1558         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
1559                 TempoSection* t;
1560                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1561
1562                         if (!t->active()) {
1563                                 continue;
1564                         }
1565
1566                         const double t_ppm = t->beats_per_minute() / t->note_type();
1567
1568                         if (t_ppm == tempo_ppm) {
1569                                 return t->frame();
1570                         }
1571
1572                         if (prev_t) {
1573                                 const double prev_t_ppm = prev_t->beats_per_minute() / prev_t->note_type();
1574
1575                                 if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) {
1576                                         const framepos_t ret_frame = prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate);
1577                                         return ret_frame;
1578                                 }
1579                         }
1580                         prev_t = t;
1581                 }
1582         }
1583
1584         return prev_t->frame();
1585 }
1586
1587 /** more precise than doing tempo_at_frame (frame_at_beat (b)),
1588  *  as there is no intermediate frame rounding.
1589  */
1590 Tempo
1591 TempoMap::tempo_at_beat (const double& beat) const
1592 {
1593         Glib::Threads::RWLock::ReaderLock lm (lock);
1594         const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
1595         const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
1596         const double note_type = prev_t->note_type();
1597
1598         return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()) * note_type, note_type);
1599 }
1600
1601 double
1602 TempoMap::pulse_at_beat (const double& beat) const
1603 {
1604         Glib::Threads::RWLock::ReaderLock lm (lock);
1605         return pulse_at_beat_locked (_metrics, beat);
1606 }
1607
1608 double
1609 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1610 {
1611         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1612
1613         return prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1614 }
1615
1616 double
1617 TempoMap::beat_at_pulse (const double& pulse) const
1618 {
1619         Glib::Threads::RWLock::ReaderLock lm (lock);
1620         return beat_at_pulse_locked (_metrics, pulse);
1621 }
1622
1623 double
1624 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1625 {
1626         MeterSection* prev_m = 0;
1627
1628         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1629                 MeterSection* m;
1630                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1631                         if (prev_m && m->pulse() > pulse) {
1632                                 if (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > m->beat()) {
1633                                         break;
1634                                 }
1635                         }
1636                         prev_m = m;
1637                 }
1638         }
1639
1640         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1641         return ret;
1642 }
1643
1644 double
1645 TempoMap::pulse_at_frame (const framecnt_t& frame) const
1646 {
1647         Glib::Threads::RWLock::ReaderLock lm (lock);
1648         return pulse_at_frame_locked (_metrics, frame);
1649 }
1650
1651 /* tempo section based */
1652 double
1653 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1654 {
1655         /* HOLD (at least) THE READER LOCK */
1656         TempoSection* prev_t = 0;
1657
1658         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1659                 TempoSection* t;
1660                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1661                         if (!t->active()) {
1662                                 continue;
1663                         }
1664                         if (prev_t && t->frame() > frame) {
1665                                 /*the previous ts is the one containing the frame */
1666                                 const double ret = prev_t->pulse_at_frame (frame, _frame_rate);
1667                                 return ret;
1668                         }
1669                         prev_t = t;
1670                 }
1671         }
1672
1673         /* treated as constant for this ts */
1674         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1675
1676         return pulses_in_section + prev_t->pulse();
1677 }
1678
1679 framecnt_t
1680 TempoMap::frame_at_pulse (const double& pulse) const
1681 {
1682         Glib::Threads::RWLock::ReaderLock lm (lock);
1683         return frame_at_pulse_locked (_metrics, pulse);
1684 }
1685
1686 /* tempo section based */
1687 framecnt_t
1688 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1689 {
1690         /* HOLD THE READER LOCK */
1691
1692         const TempoSection* prev_t = 0;
1693
1694         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1695                 TempoSection* t;
1696
1697                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1698                         if (!t->active()) {
1699                                 continue;
1700                         }
1701                         if (prev_t && t->pulse() > pulse) {
1702                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1703                         }
1704
1705                         prev_t = t;
1706                 }
1707         }
1708         /* must be treated as constant, irrespective of _type */
1709         double const pulses_in_section = pulse - prev_t->pulse();
1710         double const dtime = pulses_in_section * prev_t->frames_per_pulse (_frame_rate);
1711
1712         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_t->frame();
1713
1714         return ret;
1715 }
1716
1717 double
1718 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1719 {
1720         Glib::Threads::RWLock::ReaderLock lm (lock);
1721         return beat_at_bbt_locked (_metrics, bbt);
1722 }
1723
1724
1725 double
1726 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1727 {
1728         /* CALLER HOLDS READ LOCK */
1729
1730         MeterSection* prev_m = 0;
1731
1732         /* because audio-locked meters have 'fake' integral beats,
1733            there is no pulse offset here.
1734         */
1735         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1736                 MeterSection* m;
1737                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1738                         if (prev_m) {
1739                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1740                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1741                                         break;
1742                                 }
1743                         }
1744                         prev_m = m;
1745                 }
1746         }
1747
1748         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1749         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1750         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1751
1752         return ret;
1753 }
1754
1755 Timecode::BBT_Time
1756 TempoMap::bbt_at_beat (const double& beats)
1757 {
1758         Glib::Threads::RWLock::ReaderLock lm (lock);
1759         return bbt_at_beat_locked (_metrics, beats);
1760 }
1761
1762 Timecode::BBT_Time
1763 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1764 {
1765         /* CALLER HOLDS READ LOCK */
1766         MeterSection* prev_m = 0;
1767         const double beats = max (0.0, b);
1768
1769         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1770                 MeterSection* m = 0;
1771
1772                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1773                         if (prev_m) {
1774                                 if (m->beat() > beats) {
1775                                         /* this is the meter after the one our beat is on*/
1776                                         break;
1777                                 }
1778                         }
1779
1780                         prev_m = m;
1781                 }
1782         }
1783
1784         const double beats_in_ms = beats - prev_m->beat();
1785         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1786         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1787         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1788         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1789
1790         BBT_Time ret;
1791
1792         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1793         ret.beats = (uint32_t) floor (remaining_beats);
1794         ret.bars = total_bars;
1795
1796         /* 0 0 0 to 1 1 0 - based mapping*/
1797         ++ret.bars;
1798         ++ret.beats;
1799
1800         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1801                 ++ret.beats;
1802                 ret.ticks -= BBT_Time::ticks_per_beat;
1803         }
1804
1805         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1806                 ++ret.bars;
1807                 ret.beats = 1;
1808         }
1809
1810         return ret;
1811 }
1812
1813 double
1814 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1815 {
1816         Glib::Threads::RWLock::ReaderLock lm (lock);
1817
1818         return pulse_at_bbt_locked (_metrics, bbt);
1819 }
1820
1821 double
1822 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1823 {
1824         /* CALLER HOLDS READ LOCK */
1825
1826         MeterSection* prev_m = 0;
1827
1828         /* because audio-locked meters have 'fake' integral beats,
1829            there is no pulse offset here.
1830         */
1831         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1832                 MeterSection* m;
1833                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1834                         if (prev_m) {
1835                                 if (m->bbt().bars > bbt.bars) {
1836                                         break;
1837                                 }
1838                         }
1839                         prev_m = m;
1840                 }
1841         }
1842
1843         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1844         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1845         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1846
1847         return ret;
1848 }
1849
1850 Timecode::BBT_Time
1851 TempoMap::bbt_at_pulse (const double& pulse)
1852 {
1853         Glib::Threads::RWLock::ReaderLock lm (lock);
1854
1855         return bbt_at_pulse_locked (_metrics, pulse);
1856 }
1857
1858 Timecode::BBT_Time
1859 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1860 {
1861         MeterSection* prev_m = 0;
1862
1863         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1864                 MeterSection* m = 0;
1865
1866                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1867
1868                         if (prev_m) {
1869                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1870                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1871                                         /* this is the meter after the one our beat is on*/
1872                                         break;
1873                                 }
1874                         }
1875
1876                         prev_m = m;
1877                 }
1878         }
1879
1880         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1881         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1882         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1883         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1884         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1885
1886         BBT_Time ret;
1887
1888         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1889         ret.beats = (uint32_t) floor (remaining_beats);
1890         ret.bars = total_bars;
1891
1892         /* 0 0 0 to 1 1 0 mapping*/
1893         ++ret.bars;
1894         ++ret.beats;
1895
1896         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1897                 ++ret.beats;
1898                 ret.ticks -= BBT_Time::ticks_per_beat;
1899         }
1900
1901         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1902                 ++ret.bars;
1903                 ret.beats = 1;
1904         }
1905
1906         return ret;
1907 }
1908
1909 BBT_Time
1910 TempoMap::bbt_at_frame (framepos_t frame)
1911 {
1912         if (frame < 0) {
1913                 BBT_Time bbt;
1914                 bbt.bars = 1;
1915                 bbt.beats = 1;
1916                 bbt.ticks = 0;
1917                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1918                 return bbt;
1919         }
1920         Glib::Threads::RWLock::ReaderLock lm (lock);
1921
1922         return bbt_at_frame_locked (_metrics, frame);
1923 }
1924
1925 BBT_Time
1926 TempoMap::bbt_at_frame_rt (framepos_t frame)
1927 {
1928         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1929
1930         if (!lm.locked()) {
1931                 throw std::logic_error ("TempoMap::bbt_time_rt() could not lock tempo map");
1932         }
1933
1934         return bbt_at_frame_locked (_metrics, frame);
1935 }
1936
1937 Timecode::BBT_Time
1938 TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1939 {
1940         if (frame < 0) {
1941                 BBT_Time bbt;
1942                 bbt.bars = 1;
1943                 bbt.beats = 1;
1944                 bbt.ticks = 0;
1945                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1946                 return bbt;
1947         }
1948         const double beat = beat_at_frame_locked (metrics, frame);
1949
1950         return bbt_at_beat_locked (metrics, beat);
1951 }
1952
1953 framepos_t
1954 TempoMap::frame_at_bbt (const BBT_Time& bbt)
1955 {
1956         if (bbt.bars < 1) {
1957                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1958                 return 0;
1959         }
1960
1961         if (bbt.beats < 1) {
1962                 throw std::logic_error ("beats are counted from one");
1963         }
1964         Glib::Threads::RWLock::ReaderLock lm (lock);
1965
1966         return frame_at_bbt_locked (_metrics, bbt);
1967 }
1968
1969 /* meter & tempo section based */
1970 framepos_t
1971 TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
1972 {
1973         /* HOLD THE READER LOCK */
1974
1975         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
1976         return ret;
1977 }
1978
1979 bool
1980 TempoMap::check_solved (const Metrics& metrics) const
1981 {
1982         TempoSection* prev_t = 0;
1983         MeterSection* prev_m = 0;
1984
1985         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1986                 TempoSection* t;
1987                 MeterSection* m;
1988                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1989                         if (!t->active()) {
1990                                 continue;
1991                         }
1992                         if (prev_t) {
1993                                 /* check ordering */
1994                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
1995                                         return false;
1996                                 }
1997
1998                                 /* precision check ensures tempo and frames align.*/
1999                                 if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
2000                                         if (!t->locked_to_meter()) {
2001                                                 return false;
2002                                         }
2003                                 }
2004
2005                                 /* gradient limit - who knows what it should be?
2006                                    things are also ok (if a little chaotic) without this
2007                                 */
2008                                 if (fabs (prev_t->c_func()) > 1000.0) {
2009                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
2010                                         return false;
2011                                 }
2012                         }
2013                         prev_t = t;
2014                 }
2015
2016                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2017                         if (prev_m && m->position_lock_style() == AudioTime) {
2018                                 TempoSection* t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (metrics, m->frame() - 1));
2019                                 const double nascent_m_pulse = ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
2020                                 const framepos_t nascent_m_frame = t->frame_at_pulse (nascent_m_pulse, _frame_rate);
2021
2022                                 if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
2023                                         return false;
2024                                 }
2025                         }
2026
2027                         prev_m = m;
2028                 }
2029
2030         }
2031
2032         return true;
2033 }
2034
2035 bool
2036 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
2037 {
2038         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2039                 TempoSection* t;
2040                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2041                         if (!t->movable()) {
2042                                 t->set_active (true);
2043                                 continue;
2044                         }
2045                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
2046                                 t->set_active (false);
2047                                 t->set_pulse (0.0);
2048                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
2049                                 t->set_active (true);
2050                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
2051                                 return false;
2052                         }
2053                 }
2054         }
2055         return true;
2056 }
2057
2058 bool
2059 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
2060 {
2061         TempoSection* prev_t = 0;
2062         TempoSection* section_prev = 0;
2063         framepos_t first_m_frame = 0;
2064
2065         /* can't move a tempo before the first meter */
2066         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2067                 MeterSection* m;
2068                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2069                         if (!m->movable()) {
2070                                 first_m_frame = m->frame();
2071                                 break;
2072                         }
2073                 }
2074         }
2075         if (section->movable() && frame <= first_m_frame) {
2076                 return false;
2077         }
2078
2079         section->set_active (true);
2080         section->set_frame (frame);
2081
2082         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2083                 TempoSection* t;
2084                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2085
2086                         if (!t->active()) {
2087                                 continue;
2088                         }
2089                         if (prev_t) {
2090                                 if (t == section) {
2091                                         section_prev = prev_t;
2092                                         if (t->locked_to_meter()) {
2093                                                 prev_t = t;
2094                                         }
2095                                         continue;
2096                                 }
2097                                 if (t->position_lock_style() == MusicTime) {
2098                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2099                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2100                                 } else {
2101                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2102                                         if (!t->locked_to_meter()) {
2103                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2104                                         }
2105                                 }
2106                         }
2107                         prev_t = t;
2108                 }
2109         }
2110
2111         if (section_prev) {
2112                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
2113                 if (!section->locked_to_meter()) {
2114                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2115                 }
2116         }
2117
2118 #if (0)
2119         recompute_tempos (imaginary);
2120
2121         if (check_solved (imaginary)) {
2122                 return true;
2123         } else {
2124                 dunp (imaginary, std::cout);
2125         }
2126 #endif
2127
2128         MetricSectionFrameSorter fcmp;
2129         imaginary.sort (fcmp);
2130
2131         recompute_tempos (imaginary);
2132
2133         if (check_solved (imaginary)) {
2134                 return true;
2135         }
2136
2137         return false;
2138 }
2139
2140 bool
2141 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2142 {
2143         TempoSection* prev_t = 0;
2144         TempoSection* section_prev = 0;
2145
2146         section->set_pulse (pulse);
2147
2148         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2149                 TempoSection* t;
2150                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2151                         if (!t->active()) {
2152                                 continue;
2153                         }
2154                         if (!t->movable()) {
2155                                 t->set_pulse (0.0);
2156                                 prev_t = t;
2157                                 continue;
2158                         }
2159                         if (prev_t) {
2160                                 if (t == section) {
2161                                         section_prev = prev_t;
2162                                         continue;
2163                                 }
2164                                 if (t->position_lock_style() == MusicTime) {
2165                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2166                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2167                                 } else {
2168                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2169                                         if (!t->locked_to_meter()) {
2170                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2171                                         }
2172                                 }
2173                         }
2174                         prev_t = t;
2175                 }
2176         }
2177
2178         if (section_prev) {
2179                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
2180                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2181         }
2182
2183 #if (0)
2184         recompute_tempos (imaginary);
2185
2186         if (check_solved (imaginary)) {
2187                 return true;
2188         } else {
2189                 dunp (imaginary, std::cout);
2190         }
2191 #endif
2192
2193         MetricSectionSorter cmp;
2194         imaginary.sort (cmp);
2195
2196         recompute_tempos (imaginary);
2197         /* Reordering
2198          * XX need a restriction here, but only for this case,
2199          * as audio locked tempos don't interact in the same way.
2200          *
2201          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2202          * e.g.
2203          * |50 bpm                        |250 bpm |60 bpm
2204          *                drag 250 to the pulse after 60->
2205          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2206          */
2207         if (check_solved (imaginary)) {
2208                 return true;
2209         }
2210
2211         return false;
2212 }
2213
2214 bool
2215 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2216 {
2217         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2218         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2219         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2220                 return false;
2221         }
2222
2223         if (!section->movable()) {
2224                 /* lock the first tempo to our first meter */
2225                 if (!set_active_tempos (imaginary, frame)) {
2226                         return false;
2227                 }
2228         }
2229
2230         TempoSection* meter_locked_tempo = 0;
2231
2232         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2233                 TempoSection* t;
2234                 if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2235                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2236                                 meter_locked_tempo = t;
2237                                 break;
2238                         }
2239                 }
2240         }
2241
2242         if (!meter_locked_tempo) {
2243                 return false;
2244         }
2245
2246         MeterSection* prev_m = 0;
2247         Metrics future_map;
2248         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2249         bool solved = false;
2250
2251         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2252                 MeterSection* m;
2253                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2254                         if (m == section){
2255                                 if (prev_m && section->movable()) {
2256                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2257                                         if (beats + prev_m->beat() < section->beat()) {
2258                                                 /* set the frame/pulse corresponding to its musical position,
2259                                                  * as an earlier time than this has been requested.
2260                                                 */
2261                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2262                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2263
2264                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2265
2266                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2267                                                         meter_locked_tempo->set_pulse (new_pulse);
2268                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2269                                                         section->set_frame (smallest_frame);
2270                                                         section->set_pulse (new_pulse);
2271                                                 } else {
2272                                                         solved = false;
2273                                                 }
2274
2275                                                 Metrics::const_iterator d = future_map.begin();
2276                                                 while (d != future_map.end()) {
2277                                                         delete (*d);
2278                                                         ++d;
2279                                                 }
2280
2281                                                 if (!solved) {
2282                                                         return false;
2283                                                 }
2284                                         } else {
2285                                                 /* all is ok. set section's locked tempo if allowed.
2286                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2287                                                    XX this check could possibly go. its never actually happened here.
2288                                                 */
2289                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2290                                                 meter_copy->set_frame (frame);
2291
2292                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2293                                                         section->set_frame (frame);
2294                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2295                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2296                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2297                                                 } else {
2298                                                         solved = false;
2299                                                 }
2300
2301                                                 Metrics::const_iterator d = future_map.begin();
2302                                                 while (d != future_map.end()) {
2303                                                         delete (*d);
2304                                                         ++d;
2305                                                 }
2306
2307                                                 if (!solved) {
2308                                                         return false;
2309                                                 }
2310                                         }
2311                                 } else {
2312                                         /* not movable (first meter atm) */
2313
2314                                         tempo_copy->set_frame (frame);
2315                                         tempo_copy->set_pulse (0.0);
2316
2317                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2318                                                 section->set_frame (frame);
2319                                                 meter_locked_tempo->set_frame (frame);
2320                                                 meter_locked_tempo->set_pulse (0.0);
2321                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2322                                         } else {
2323                                                 solved = false;
2324                                         }
2325
2326                                         Metrics::const_iterator d = future_map.begin();
2327                                         while (d != future_map.end()) {
2328                                                 delete (*d);
2329                                                 ++d;
2330                                         }
2331
2332                                         if (!solved) {
2333                                                 return false;
2334                                         }
2335
2336                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2337                                         section->set_beat (b_bbt);
2338                                         section->set_pulse (0.0);
2339
2340                                 }
2341                                 break;
2342                         }
2343
2344                         prev_m = m;
2345                 }
2346         }
2347
2348         MetricSectionFrameSorter fcmp;
2349         imaginary.sort (fcmp);
2350
2351         recompute_meters (imaginary);
2352
2353         return true;
2354 }
2355
2356 bool
2357 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2358 {
2359         /* disallow setting section to an existing meter's bbt */
2360         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2361                 MeterSection* m;
2362                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2363                         if (m != section && m->bbt().bars == when.bars) {
2364                                 return false;
2365                         }
2366                 }
2367         }
2368
2369         MeterSection* prev_m = 0;
2370         MeterSection* section_prev = 0;
2371
2372         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2373                 MeterSection* m;
2374                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2375                         pair<double, BBT_Time> b_bbt;
2376                         double new_pulse = 0.0;
2377
2378                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2379                                 section_prev = prev_m;
2380                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2381                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2382                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2383
2384                                 section->set_beat (b_bbt);
2385                                 section->set_pulse (pulse);
2386                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2387                                 prev_m = section;
2388                                 continue;
2389                         }
2390
2391                         if (m->position_lock_style() == AudioTime) {
2392                                 TempoSection* meter_locked_tempo = 0;
2393
2394                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2395                                         TempoSection* t;
2396                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2397                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2398                                                         meter_locked_tempo = t;
2399                                                         break;
2400                                                 }
2401                                         }
2402                                 }
2403
2404                                 if (!meter_locked_tempo) {
2405                                         return false;
2406                                 }
2407
2408                                 if (prev_m) {
2409                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2410
2411                                         if (beats + prev_m->beat() != m->beat()) {
2412                                                 /* tempo/ meter change caused a change in beat (bar). */
2413                                                 b_bbt = make_pair (beats + prev_m->beat()
2414                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2415                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2416                                         } else if (m->movable()) {
2417                                                 b_bbt = make_pair (m->beat(), m->bbt());
2418                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2419                                         }
2420                                 } else {
2421                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2422                                 }
2423
2424                                 meter_locked_tempo->set_pulse (new_pulse);
2425                                 m->set_beat (b_bbt);
2426                                 m->set_pulse (new_pulse);
2427
2428                         } else {
2429                                 /* MusicTime */
2430                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2431                                 if (beats + prev_m->beat() != m->beat()) {
2432                                         /* tempo/ meter change caused a change in beat (bar). */
2433                                         b_bbt = make_pair (beats + prev_m->beat()
2434                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2435                                 } else {
2436                                         b_bbt = make_pair (beats + prev_m->beat()
2437                                                            , m->bbt());
2438                                 }
2439                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2440                                 m->set_beat (b_bbt);
2441                                 m->set_pulse (new_pulse);
2442                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2443                         }
2444
2445                         prev_m = m;
2446                 }
2447         }
2448
2449         if (!section_prev) {
2450
2451                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2452                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2453                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2454
2455                 section->set_beat (b_bbt);
2456                 section->set_pulse (pulse);
2457                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2458         }
2459
2460         MetricSectionSorter cmp;
2461         imaginary.sort (cmp);
2462
2463         recompute_meters (imaginary);
2464
2465         return true;
2466 }
2467
2468 /** places a copy of _metrics into copy and returns a pointer
2469  *  to section's equivalent in copy.
2470  */
2471 TempoSection*
2472 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2473 {
2474         TempoSection* ret = 0;
2475
2476         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2477                 TempoSection* t;
2478                 MeterSection* m;
2479                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2480                         if (t == section) {
2481                                 ret = new TempoSection (*t);
2482                                 copy.push_back (ret);
2483                                 continue;
2484                         }
2485
2486                         TempoSection* cp = new TempoSection (*t);
2487                         copy.push_back (cp);
2488                 }
2489                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2490                         MeterSection* cp = new MeterSection (*m);
2491                         copy.push_back (cp);
2492                 }
2493         }
2494
2495         return ret;
2496 }
2497
2498 MeterSection*
2499 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2500 {
2501         MeterSection* ret = 0;
2502
2503         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2504                 TempoSection* t;
2505                 MeterSection* m;
2506                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2507                         TempoSection* cp = new TempoSection (*t);
2508                         copy.push_back (cp);
2509                 }
2510
2511                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2512                         if (m == section) {
2513                                 ret = new MeterSection (*m);
2514                                 copy.push_back (ret);
2515                                 continue;
2516                         }
2517                         MeterSection* cp = new MeterSection (*m);
2518                         copy.push_back (cp);
2519                 }
2520         }
2521
2522         return ret;
2523 }
2524
2525 /** answers the question "is this a valid beat position for this tempo section?".
2526  *  it returns true if the tempo section can be moved to the requested bbt position,
2527  *  leaving the tempo map in a solved state.
2528  * @param section the tempo section to be moved
2529  * @param bbt the requested new position for the tempo section
2530  * @return true if the tempo section can be moved to the position, otherwise false.
2531  */
2532 bool
2533 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2534 {
2535         Metrics copy;
2536         TempoSection* tempo_copy = 0;
2537
2538         {
2539                 Glib::Threads::RWLock::ReaderLock lm (lock);
2540                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2541                 if (!tempo_copy) {
2542                         return false;
2543                 }
2544         }
2545
2546         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2547
2548         Metrics::const_iterator d = copy.begin();
2549         while (d != copy.end()) {
2550                 delete (*d);
2551                 ++d;
2552         }
2553
2554         return ret;
2555 }
2556
2557 /**
2558 * 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,
2559 * taking any possible reordering as a consequence of this into account.
2560 * @param section - the section to be altered
2561 * @param bbt - the bbt where the altered tempo will fall
2562 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2563 */
2564 pair<double, framepos_t>
2565 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2566 {
2567         Metrics future_map;
2568         pair<double, framepos_t> ret = make_pair (0.0, 0);
2569
2570         Glib::Threads::RWLock::ReaderLock lm (lock);
2571
2572         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2573
2574         const double beat = beat_at_bbt_locked (future_map, bbt);
2575
2576         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2577                 ret.first = tempo_copy->pulse();
2578                 ret.second = tempo_copy->frame();
2579         } else {
2580                 ret.first = section->pulse();
2581                 ret.second = section->frame();
2582         }
2583
2584         Metrics::const_iterator d = future_map.begin();
2585         while (d != future_map.end()) {
2586                 delete (*d);
2587                 ++d;
2588         }
2589         return ret;
2590 }
2591
2592 void
2593 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame, const int& sub_num)
2594 {
2595         Metrics future_map;
2596         bool was_musical = ts->position_lock_style() == MusicTime;
2597
2598         if (sub_num == 0 && was_musical) {
2599                 /* if we're not snapping to music,
2600                    AudioTime and MusicTime may be treated identically.
2601                 */
2602                 ts->set_position_lock_style (AudioTime);
2603         }
2604
2605         if (ts->position_lock_style() == MusicTime) {
2606                 {
2607                         /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
2608                         Glib::Threads::RWLock::WriterLock lm (lock);
2609                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2610                         const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
2611                         double pulse = pulse_at_beat_locked (future_map, beat);
2612
2613                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2614                                 solve_map_pulse (_metrics, ts, pulse);
2615                                 recompute_meters (_metrics);
2616                         }
2617                 }
2618
2619         } else {
2620
2621                 {
2622                         Glib::Threads::RWLock::WriterLock lm (lock);
2623                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2624                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2625                                 solve_map_frame (_metrics, ts, frame);
2626                                 recompute_meters (_metrics);
2627                         }
2628                 }
2629         }
2630
2631         if (sub_num == 0 && was_musical) {
2632                 ts->set_position_lock_style (MusicTime);
2633         }
2634
2635         Metrics::const_iterator d = future_map.begin();
2636         while (d != future_map.end()) {
2637                 delete (*d);
2638                 ++d;
2639         }
2640
2641         MetricPositionChanged (); // Emit Signal
2642 }
2643
2644 void
2645 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2646 {
2647         Metrics future_map;
2648
2649         if (ms->position_lock_style() == AudioTime) {
2650
2651                 {
2652                         Glib::Threads::RWLock::WriterLock lm (lock);
2653                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2654
2655                         if (solve_map_frame (future_map, copy, frame)) {
2656                                 solve_map_frame (_metrics, ms, frame);
2657                                 recompute_tempos (_metrics);
2658                         }
2659                 }
2660         } else {
2661                 {
2662                         Glib::Threads::RWLock::WriterLock lm (lock);
2663                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2664
2665                         const double beat = beat_at_frame_locked (_metrics, frame);
2666                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2667
2668                         if (solve_map_bbt (future_map, copy, bbt)) {
2669                                 solve_map_bbt (_metrics, ms, bbt);
2670                                 recompute_tempos (_metrics);
2671                         }
2672                 }
2673         }
2674
2675         Metrics::const_iterator d = future_map.begin();
2676         while (d != future_map.end()) {
2677                 delete (*d);
2678                 ++d;
2679         }
2680
2681         MetricPositionChanged (); // Emit Signal
2682 }
2683
2684 bool
2685 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2686 {
2687         Metrics future_map;
2688         bool can_solve = false;
2689         {
2690                 Glib::Threads::RWLock::WriterLock lm (lock);
2691                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2692                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2693                 recompute_tempos (future_map);
2694
2695                 if (check_solved (future_map)) {
2696                         ts->set_beats_per_minute (bpm.beats_per_minute());
2697                         recompute_map (_metrics);
2698                         can_solve = true;
2699                 }
2700         }
2701
2702         Metrics::const_iterator d = future_map.begin();
2703         while (d != future_map.end()) {
2704                 delete (*d);
2705                 ++d;
2706         }
2707         if (can_solve) {
2708                 MetricPositionChanged (); // Emit Signal
2709         }
2710         return can_solve;
2711 }
2712
2713 void
2714 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2715 {
2716         /*
2717           Ts (future prev_t)   Tnext
2718           |                    |
2719           |     [drag^]        |
2720           |----------|----------
2721                 e_f  pulse(frame)
2722         */
2723
2724         Metrics future_map;
2725
2726         {
2727                 Glib::Threads::RWLock::WriterLock lm (lock);
2728
2729                 if (!ts) {
2730                         return;
2731                 }
2732
2733                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2734                 TempoSection* prev_to_prev_t = 0;
2735                 const frameoffset_t fr_off = end_frame - frame;
2736
2737                 if (prev_t && prev_t->pulse() > 0.0) {
2738                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2739                 }
2740
2741                 TempoSection* next_t = 0;
2742                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2743                         TempoSection* t = 0;
2744                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2745                                 if (t->frame() > ts->frame()) {
2746                                         next_t = t;
2747                                         break;
2748                                 }
2749                         }
2750                 }
2751                 /* minimum allowed measurement distance in frames */
2752                 const framepos_t min_dframe = 2;
2753
2754                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2755                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2756                 */
2757                 double contribution = 0.0;
2758
2759                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2760                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2761                 }
2762
2763                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2764
2765                 const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2766                 const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2767
2768                 double new_bpm;
2769
2770                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2771
2772                         if (prev_t->position_lock_style() == MusicTime) {
2773                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2774                                         if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
2775
2776                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2777                                                                                         / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2778                                         } else {
2779                                                 new_bpm = prev_t->beats_per_minute();
2780                                         }
2781                                 } else {
2782                                         /* prev to prev is irrelevant */
2783
2784                                         if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
2785                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2786                                         } else {
2787                                                 new_bpm = prev_t->beats_per_minute();
2788                                         }
2789                                 }
2790                         } else {
2791                                 /* AudioTime */
2792                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2793                                         if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
2794
2795                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2796                                                                                         / (double) ((end_frame) - prev_to_prev_t->frame()));
2797                                         } else {
2798                                                 new_bpm = prev_t->beats_per_minute();
2799                                         }
2800                                 } else {
2801                                         /* prev_to_prev_t is irrelevant */
2802
2803                                         if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
2804                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2805                                         } else {
2806                                                 new_bpm = prev_t->beats_per_minute();
2807                                         }
2808                                 }
2809                         }
2810                 } else {
2811
2812                         double frame_ratio = 1.0;
2813                         double pulse_ratio = 1.0;
2814                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2815
2816                         if (prev_to_prev_t) {
2817                                 if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
2818                                         frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2819                                 }
2820                                 if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
2821                                         pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2822                                 }
2823                         } else {
2824                                 if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
2825                                         frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2826                                 }
2827                                 pulse_ratio = (start_pulse / end_pulse);
2828                         }
2829                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2830                 }
2831
2832                 /* don't clamp and proceed here.
2833                    testing has revealed that this can go negative,
2834                    which is an entirely different thing to just being too low.
2835                 */
2836                 if (new_bpm < 0.5) {
2837                         return;
2838                 }
2839                 new_bpm = min (new_bpm, (double) 1000.0);
2840                 prev_t->set_beats_per_minute (new_bpm);
2841                 recompute_tempos (future_map);
2842                 recompute_meters (future_map);
2843
2844                 if (check_solved (future_map)) {
2845                         ts->set_beats_per_minute (new_bpm);
2846                         recompute_tempos (_metrics);
2847                         recompute_meters (_metrics);
2848                 }
2849         }
2850
2851         Metrics::const_iterator d = future_map.begin();
2852         while (d != future_map.end()) {
2853                 delete (*d);
2854                 ++d;
2855         }
2856
2857         MetricPositionChanged (); // Emit Signal
2858 }
2859
2860 double
2861 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t& sub_num)
2862 {
2863         Glib::Threads::RWLock::ReaderLock lm (lock);
2864
2865         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
2866 }
2867
2868 double
2869 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t& sub_num)
2870 {
2871         double beat = beat_at_frame_locked (metrics, frame);
2872         if (sub_num > 1) {
2873                 beat = floor (beat) + (floor (((beat - floor (beat)) * (double) sub_num) + 0.5) / sub_num);
2874         } else if (sub_num == 1) {
2875                 /* snap to beat */
2876                 beat = floor (beat + 0.5);
2877         } else if (sub_num == -1) {
2878                 /* snap to  bar */
2879                 Timecode::BBT_Time bbt = bbt_at_beat_locked (metrics, beat);
2880                 bbt.beats = 1;
2881                 bbt.ticks = 0;
2882                 beat = beat_at_bbt_locked (metrics, bbt);
2883         }
2884         return beat;
2885 }
2886
2887 framecnt_t
2888 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2889 {
2890         Glib::Threads::RWLock::ReaderLock lm (lock);
2891
2892         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2893         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2894         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2895
2896         return frame_at_beat_locked (_metrics, total_beats);
2897 }
2898
2899 framepos_t
2900 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2901 {
2902         return round_to_type (fr, dir, Bar);
2903 }
2904
2905 framepos_t
2906 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2907 {
2908         return round_to_type (fr, dir, Beat);
2909 }
2910
2911 framepos_t
2912 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2913 {
2914         Glib::Threads::RWLock::ReaderLock lm (lock);
2915         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2916         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2917         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2918
2919         ticks -= beats * BBT_Time::ticks_per_beat;
2920
2921         if (dir > 0) {
2922                 /* round to next (or same iff dir == RoundUpMaybe) */
2923
2924                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2925
2926                 if (mod == 0 && dir == RoundUpMaybe) {
2927                         /* right on the subdivision, which is fine, so do nothing */
2928
2929                 } else if (mod == 0) {
2930                         /* right on the subdivision, so the difference is just the subdivision ticks */
2931                         ticks += ticks_one_subdivisions_worth;
2932
2933                 } else {
2934                         /* not on subdivision, compute distance to next subdivision */
2935
2936                         ticks += ticks_one_subdivisions_worth - mod;
2937                 }
2938
2939                 if (ticks >= BBT_Time::ticks_per_beat) {
2940                         ticks -= BBT_Time::ticks_per_beat;
2941                 }
2942         } else if (dir < 0) {
2943
2944                 /* round to previous (or same iff dir == RoundDownMaybe) */
2945
2946                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2947
2948                 if (difference == 0 && dir == RoundDownAlways) {
2949                         /* right on the subdivision, but force-rounding down,
2950                            so the difference is just the subdivision ticks */
2951                         difference = ticks_one_subdivisions_worth;
2952                 }
2953
2954                 if (ticks < difference) {
2955                         ticks = BBT_Time::ticks_per_beat - ticks;
2956                 } else {
2957                         ticks -= difference;
2958                 }
2959
2960         } else {
2961                 /* round to nearest */
2962                 double rem;
2963
2964                 /* compute the distance to the previous and next subdivision */
2965
2966                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2967
2968                         /* closer to the next subdivision, so shift forward */
2969
2970                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2971
2972                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2973
2974                         if (ticks > BBT_Time::ticks_per_beat) {
2975                                 ++beats;
2976                                 ticks -= BBT_Time::ticks_per_beat;
2977                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2978                         }
2979
2980                 } else if (rem > 0) {
2981
2982                         /* closer to previous subdivision, so shift backward */
2983
2984                         if (rem > ticks) {
2985                                 if (beats == 0) {
2986                                         /* can't go backwards past zero, so ... */
2987                                         return 0;
2988                                 }
2989                                 /* step back to previous beat */
2990                                 --beats;
2991                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2992                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2993                         } else {
2994                                 ticks = lrint (ticks - rem);
2995                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2996                         }
2997                 } else {
2998                         /* on the subdivision, do nothing */
2999                 }
3000         }
3001
3002         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
3003
3004         return ret_frame;
3005 }
3006
3007 framepos_t
3008 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
3009 {
3010         Glib::Threads::RWLock::ReaderLock lm (lock);
3011
3012         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
3013         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
3014
3015         switch (type) {
3016         case Bar:
3017                 if (dir < 0) {
3018                         /* find bar previous to 'frame' */
3019                         bbt.beats = 1;
3020                         bbt.ticks = 0;
3021                         return frame_at_bbt_locked (_metrics, bbt);
3022
3023                 } else if (dir > 0) {
3024                         /* find bar following 'frame' */
3025                         ++bbt.bars;
3026                         bbt.beats = 1;
3027                         bbt.ticks = 0;
3028                         return frame_at_bbt_locked (_metrics, bbt);
3029                 } else {
3030                         /* true rounding: find nearest bar */
3031                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
3032                         bbt.beats = 1;
3033                         bbt.ticks = 0;
3034                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
3035                         ++bbt.bars;
3036                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
3037
3038                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
3039                                 return next_ft;
3040                         } else {
3041                                 return prev_ft;
3042                         }
3043                 }
3044
3045                 break;
3046
3047         case Beat:
3048                 if (dir < 0) {
3049                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
3050                 } else if (dir > 0) {
3051                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
3052                 } else {
3053                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
3054                 }
3055                 break;
3056         }
3057
3058         return 0;
3059 }
3060
3061 void
3062 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
3063                     framepos_t lower, framepos_t upper)
3064 {
3065         Glib::Threads::RWLock::ReaderLock lm (lock);
3066         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
3067         framecnt_t pos = 0;
3068         /* although the map handles negative beats, bbt doesn't. */
3069         if (cnt < 0.0) {
3070                 cnt = 0.0;
3071         }
3072
3073         if (frame_at_beat_locked (_metrics, cnt) >= upper) {
3074                 return;
3075         }
3076
3077         while (pos < upper) {
3078                 pos = frame_at_beat_locked (_metrics, cnt);
3079                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
3080                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
3081                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
3082                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
3083                 ++cnt;
3084         }
3085 }
3086
3087 const TempoSection&
3088 TempoMap::tempo_section_at_frame (framepos_t frame) const
3089 {
3090         Glib::Threads::RWLock::ReaderLock lm (lock);
3091         return tempo_section_at_frame_locked (_metrics, frame);
3092 }
3093
3094 const TempoSection&
3095 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3096 {
3097         Metrics::const_iterator i;
3098         TempoSection* prev = 0;
3099
3100         for (i = metrics.begin(); i != metrics.end(); ++i) {
3101                 TempoSection* t;
3102
3103                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3104                         if (!t->active()) {
3105                                 continue;
3106                         }
3107                         if (prev && t->frame() > frame) {
3108                                 break;
3109                         }
3110
3111                         prev = t;
3112                 }
3113         }
3114
3115         if (prev == 0) {
3116                 fatal << endmsg;
3117                 abort(); /*NOTREACHED*/
3118         }
3119
3120         return *prev;
3121 }
3122
3123 const TempoSection&
3124 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3125 {
3126         TempoSection* prev_t = 0;
3127         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
3128
3129         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3130                 TempoSection* t;
3131                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3132                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
3133                                 break;
3134                         }
3135                         prev_t = t;
3136                 }
3137
3138         }
3139         return *prev_t;
3140 }
3141
3142 /* don't use this to calculate length (the tempo is only correct for this frame).
3143    do that stuff based on the beat_at_frame and frame_at_beat api
3144 */
3145 double
3146 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3147 {
3148         Glib::Threads::RWLock::ReaderLock lm (lock);
3149
3150         const TempoSection* ts_at = &tempo_section_at_frame_locked (_metrics, frame);
3151         const TempoSection* ts_after = 0;
3152         Metrics::const_iterator i;
3153
3154         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3155                 TempoSection* t;
3156
3157                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3158                         if (!t->active()) {
3159                                 continue;
3160                         }
3161                         if ((*i)->frame() > frame) {
3162                                 ts_after = t;
3163                                 break;
3164                         }
3165                 }
3166         }
3167
3168         if (ts_after) {
3169                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * ts_at->note_type());
3170         }
3171         /* must be treated as constant tempo */
3172         return ts_at->frames_per_beat (_frame_rate);
3173 }
3174
3175 const MeterSection&
3176 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3177 {
3178         Metrics::const_iterator i;
3179         MeterSection* prev = 0;
3180
3181         for (i = metrics.begin(); i != metrics.end(); ++i) {
3182                 MeterSection* m;
3183
3184                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3185
3186                         if (prev && (*i)->frame() > frame) {
3187                                 break;
3188                         }
3189
3190                         prev = m;
3191                 }
3192         }
3193
3194         if (prev == 0) {
3195                 fatal << endmsg;
3196                 abort(); /*NOTREACHED*/
3197         }
3198
3199         return *prev;
3200 }
3201
3202
3203 const MeterSection&
3204 TempoMap::meter_section_at_frame (framepos_t frame) const
3205 {
3206         Glib::Threads::RWLock::ReaderLock lm (lock);
3207         return meter_section_at_frame_locked (_metrics, frame);
3208 }
3209
3210 const MeterSection&
3211 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3212 {
3213         MeterSection* prev_m = 0;
3214
3215         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3216                 MeterSection* m;
3217                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3218                         if (prev_m && m->beat() > beat) {
3219                                 break;
3220                         }
3221                         prev_m = m;
3222                 }
3223
3224         }
3225         return *prev_m;
3226 }
3227
3228 const MeterSection&
3229 TempoMap::meter_section_at_beat (double beat) const
3230 {
3231         Glib::Threads::RWLock::ReaderLock lm (lock);
3232         return meter_section_at_beat_locked (_metrics, beat);
3233 }
3234
3235 const Meter&
3236 TempoMap::meter_at_frame (framepos_t frame) const
3237 {
3238         TempoMetric m (metric_at (frame));
3239         return m.meter();
3240 }
3241
3242 void
3243 TempoMap::fix_legacy_session ()
3244 {
3245         MeterSection* prev_m = 0;
3246         TempoSection* prev_t = 0;
3247
3248         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3249                 MeterSection* m;
3250                 TempoSection* t;
3251
3252                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3253                         if (!m->movable()) {
3254                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3255                                 m->set_beat (bbt);
3256                                 m->set_pulse (0.0);
3257                                 m->set_frame (0);
3258                                 m->set_position_lock_style (AudioTime);
3259                                 prev_m = m;
3260                                 continue;
3261                         }
3262                         if (prev_m) {
3263                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3264                                                                           + (m->bbt().beats - 1)
3265                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3266                                                                           , m->bbt());
3267                                 m->set_beat (start);
3268                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3269                                         + (m->bbt().beats - 1)
3270                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3271                                 m->set_pulse (start_beat / prev_m->note_divisor());
3272                         }
3273                         prev_m = m;
3274                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3275
3276                         if (!t->active()) {
3277                                 continue;
3278                         }
3279
3280                         if (!t->movable()) {
3281                                 t->set_pulse (0.0);
3282                                 t->set_frame (0);
3283                                 t->set_position_lock_style (AudioTime);
3284                                 prev_t = t;
3285                                 continue;
3286                         }
3287
3288                         if (prev_t) {
3289                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3290                                         + (t->legacy_bbt().beats - 1)
3291                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3292                                 if (prev_m) {
3293                                         t->set_pulse (beat / prev_m->note_divisor());
3294                                 } else {
3295                                         /* really shouldn't happen but.. */
3296                                         t->set_pulse (beat / 4.0);
3297                                 }
3298                         }
3299                         prev_t = t;
3300                 }
3301         }
3302 }
3303
3304 XMLNode&
3305 TempoMap::get_state ()
3306 {
3307         Metrics::const_iterator i;
3308         XMLNode *root = new XMLNode ("TempoMap");
3309
3310         {
3311                 Glib::Threads::RWLock::ReaderLock lm (lock);
3312                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3313                         root->add_child_nocopy ((*i)->get_state());
3314                 }
3315         }
3316
3317         return *root;
3318 }
3319
3320 int
3321 TempoMap::set_state (const XMLNode& node, int /*version*/)
3322 {
3323         {
3324                 Glib::Threads::RWLock::WriterLock lm (lock);
3325
3326                 XMLNodeList nlist;
3327                 XMLNodeConstIterator niter;
3328                 Metrics old_metrics (_metrics);
3329                 _metrics.clear();
3330
3331                 nlist = node.children();
3332
3333                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3334                         XMLNode* child = *niter;
3335
3336                         if (child->name() == TempoSection::xml_state_node_name) {
3337
3338                                 try {
3339                                         TempoSection* ts = new TempoSection (*child);
3340                                         _metrics.push_back (ts);
3341                                 }
3342
3343                                 catch (failed_constructor& err){
3344                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3345                                         _metrics = old_metrics;
3346                                         break;
3347                                 }
3348
3349                         } else if (child->name() == MeterSection::xml_state_node_name) {
3350
3351                                 try {
3352                                         MeterSection* ms = new MeterSection (*child);
3353                                         _metrics.push_back (ms);
3354                                 }
3355
3356                                 catch (failed_constructor& err) {
3357                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3358                                         _metrics = old_metrics;
3359                                         break;
3360                                 }
3361                         }
3362                 }
3363
3364                 if (niter == nlist.end()) {
3365                         MetricSectionSorter cmp;
3366                         _metrics.sort (cmp);
3367                 }
3368
3369                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3370                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3371                         TempoSection* t;
3372                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3373                                 if (t->legacy_bbt().bars != 0) {
3374                                         fix_legacy_session();
3375                                         break;
3376                                 }
3377                                 break;
3378                         }
3379                 }
3380
3381                 /* check for multiple tempo/meters at the same location, which
3382                    ardour2 somehow allowed.
3383                 */
3384
3385                 Metrics::iterator prev = _metrics.end();
3386                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3387                         if (prev != _metrics.end()) {
3388                                 MeterSection* ms;
3389                                 MeterSection* prev_m;
3390                                 TempoSection* ts;
3391                                 TempoSection* prev_t;
3392                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3393                                         if (prev_m->pulse() == ms->pulse()) {
3394                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3395                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3396                                                 return -1;
3397                                         }
3398                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3399                                         if (prev_t->pulse() == ts->pulse()) {
3400                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3401                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3402                                                 return -1;
3403                                         }
3404                                 }
3405                         }
3406                         prev = i;
3407                 }
3408
3409                 recompute_map (_metrics);
3410         }
3411
3412         PropertyChanged (PropertyChange ());
3413
3414         return 0;
3415 }
3416
3417 void
3418 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3419 {
3420         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3421         const MeterSection* m;
3422         const TempoSection* t;
3423         const TempoSection* prev_t = 0;
3424
3425         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3426
3427                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3428                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3429                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3430                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3431                         if (prev_t) {
3432                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3433                                 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;
3434                         }
3435                         prev_t = t;
3436                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3437                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3438                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3439                 }
3440         }
3441         o << "------" << std::endl;
3442 }
3443
3444 int
3445 TempoMap::n_tempos() const
3446 {
3447         Glib::Threads::RWLock::ReaderLock lm (lock);
3448         int cnt = 0;
3449
3450         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3451                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3452                         cnt++;
3453                 }
3454         }
3455
3456         return cnt;
3457 }
3458
3459 int
3460 TempoMap::n_meters() const
3461 {
3462         Glib::Threads::RWLock::ReaderLock lm (lock);
3463         int cnt = 0;
3464
3465         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3466                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3467                         cnt++;
3468                 }
3469         }
3470
3471         return cnt;
3472 }
3473
3474 void
3475 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3476 {
3477         {
3478                 Glib::Threads::RWLock::WriterLock lm (lock);
3479                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3480                         if ((*i)->frame() >= where && (*i)->movable ()) {
3481                                 (*i)->set_frame ((*i)->frame() + amount);
3482                         }
3483                 }
3484
3485                 /* now reset the BBT time of all metrics, based on their new
3486                  * audio time. This is the only place where we do this reverse
3487                  * timestamp.
3488                  */
3489
3490                 Metrics::iterator i;
3491                 const MeterSection* meter;
3492                 const TempoSection* tempo;
3493                 MeterSection *m;
3494                 TempoSection *t;
3495
3496                 meter = &first_meter ();
3497                 tempo = &first_tempo ();
3498
3499                 BBT_Time start;
3500                 BBT_Time end;
3501
3502                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3503
3504                 bool first = true;
3505                 MetricSection* prev = 0;
3506
3507                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3508
3509                         BBT_Time bbt;
3510                         //TempoMetric metric (*meter, *tempo);
3511                         MeterSection* ms = const_cast<MeterSection*>(meter);
3512                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3513                         if (prev) {
3514                                 if (ts){
3515                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3516                                                 if (!t->active()) {
3517                                                         continue;
3518                                                 }
3519                                                 ts->set_pulse (t->pulse());
3520                                         }
3521                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3522                                                 ts->set_pulse (m->pulse());
3523                                         }
3524                                         ts->set_frame (prev->frame());
3525
3526                                 }
3527                                 if (ms) {
3528                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3529                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3530                                                 ms->set_beat (start);
3531                                                 ms->set_pulse (m->pulse());
3532                                         }
3533                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3534                                                 if (!t->active()) {
3535                                                         continue;
3536                                                 }
3537                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3538                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3539                                                 ms->set_beat (start);
3540                                                 ms->set_pulse (t->pulse());
3541                                         }
3542                                         ms->set_frame (prev->frame());
3543                                 }
3544
3545                         } else {
3546                                 // metric will be at frames=0 bbt=1|1|0 by default
3547                                 // which is correct for our purpose
3548                         }
3549
3550                         // cerr << bbt << endl;
3551
3552                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3553                                 if (!t->active()) {
3554                                         continue;
3555                                 }
3556                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3557                                 tempo = t;
3558                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3559                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3560                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3561
3562                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3563
3564                                 if (first) {
3565                                         first = false;
3566                                 } else {
3567
3568                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3569                                                 /* round up to next beat */
3570                                                 bbt.beats += 1;
3571                                         }
3572
3573                                         bbt.ticks = 0;
3574
3575                                         if (bbt.beats != 1) {
3576                                                 /* round up to next bar */
3577                                                 bbt.bars += 1;
3578                                                 bbt.beats = 1;
3579                                         }
3580                                 }
3581                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3582                                 m->set_beat (start);
3583                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3584                                 meter = m;
3585                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3586                         } else {
3587                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3588                                 abort(); /*NOTREACHED*/
3589                         }
3590
3591                         prev = (*i);
3592                 }
3593
3594                 recompute_map (_metrics);
3595         }
3596
3597
3598         PropertyChanged (PropertyChange ());
3599 }
3600 bool
3601 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3602 {
3603         bool moved = false;
3604
3605         std::list<MetricSection*> metric_kill_list;
3606
3607         TempoSection* last_tempo = NULL;
3608         MeterSection* last_meter = NULL;
3609         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3610         bool meter_after = false; // is there a meter marker likewise?
3611         {
3612                 Glib::Threads::RWLock::WriterLock lm (lock);
3613                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3614                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3615                                 metric_kill_list.push_back(*i);
3616                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3617                                 if (lt)
3618                                         last_tempo = lt;
3619                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3620                                 if (lm)
3621                                         last_meter = lm;
3622                         }
3623                         else if ((*i)->frame() >= where) {
3624                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3625                                 (*i)->set_frame ((*i)->frame() - amount);
3626                                 if ((*i)->frame() == where) {
3627                                         // marker was immediately after end of range
3628                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3629                                         meter_after = dynamic_cast<MeterSection*> (*i);
3630                                 }
3631                                 moved = true;
3632                         }
3633                 }
3634
3635                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3636                 if (last_tempo && !tempo_after) {
3637                         metric_kill_list.remove(last_tempo);
3638                         last_tempo->set_frame(where);
3639                         moved = true;
3640                 }
3641                 if (last_meter && !meter_after) {
3642                         metric_kill_list.remove(last_meter);
3643                         last_meter->set_frame(where);
3644                         moved = true;
3645                 }
3646
3647                 //remove all the remaining metrics
3648                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3649                         _metrics.remove(*i);
3650                         moved = true;
3651                 }
3652
3653                 if (moved) {
3654                         recompute_map (_metrics);
3655                 }
3656         }
3657         PropertyChanged (PropertyChange ());
3658         return moved;
3659 }
3660
3661 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3662  *  pos can be -ve, if required.
3663  */
3664 framepos_t
3665 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3666 {
3667         Glib::Threads::RWLock::ReaderLock lm (lock);
3668
3669         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) + beats.to_double());
3670 }
3671
3672 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3673 framepos_t
3674 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3675 {
3676         Glib::Threads::RWLock::ReaderLock lm (lock);
3677
3678         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
3679 }
3680
3681 /** Add the BBT interval op to pos and return the result */
3682 framepos_t
3683 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3684 {
3685         Glib::Threads::RWLock::ReaderLock lm (lock);
3686
3687         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3688         pos_bbt.ticks += op.ticks;
3689         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3690                 ++pos_bbt.beats;
3691                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3692         }
3693         pos_bbt.beats += op.beats;
3694         /* the meter in effect will start on the bar */
3695         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();
3696         while (pos_bbt.beats >= divisions_per_bar + 1) {
3697                 ++pos_bbt.bars;
3698                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3699                 pos_bbt.beats -= divisions_per_bar;
3700         }
3701         pos_bbt.bars += op.bars;
3702
3703         return frame_at_bbt_locked (_metrics, pos_bbt);
3704 }
3705
3706 /** Count the number of beats that are equivalent to distance when going forward,
3707     starting at pos.
3708 */
3709 Evoral::Beats
3710 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3711 {
3712         Glib::Threads::RWLock::ReaderLock lm (lock);
3713
3714         return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
3715 }
3716
3717 struct bbtcmp {
3718     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3719             return a < b;
3720     }
3721 };
3722
3723 std::ostream&
3724 operator<< (std::ostream& o, const Meter& m) {
3725         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3726 }
3727
3728 std::ostream&
3729 operator<< (std::ostream& o, const Tempo& t) {
3730         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3731 }
3732
3733 std::ostream&
3734 operator<< (std::ostream& o, const MetricSection& section) {
3735
3736         o << "MetricSection @ " << section.frame() << ' ';
3737
3738         const TempoSection* ts;
3739         const MeterSection* ms;
3740
3741         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3742                 o << *((const Tempo*) ts);
3743         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3744                 o << *((const Meter*) ms);
3745         }
3746
3747         return o;
3748 }