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