64bcd58f03917fb74fa9557d5c4bbe7e5e0e2642
[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-minute\" 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         assert (prev_t);
1337         prev_t->set_c_func (0.0);
1338 }
1339
1340 /* tempos must be positioned correctly.
1341    the current approach is to use a meter's bbt time as its base position unit.
1342    an audio-locked meter requires a recomputation of pulse and beat (but not bbt),
1343    while a music-locked meter requires recomputations of frame pulse and beat (but not bbt)
1344 */
1345 void
1346 TempoMap::recompute_meters (Metrics& metrics)
1347 {
1348         MeterSection* meter = 0;
1349         MeterSection* prev_m = 0;
1350
1351         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1352                 if (!(*mi)->is_tempo()) {
1353                         meter = static_cast<MeterSection*> (*mi);
1354                         if (meter->position_lock_style() == AudioTime) {
1355                                 double pulse = 0.0;
1356                                 pair<double, BBT_Time> b_bbt;
1357                                 TempoSection* meter_locked_tempo = 0;
1358                                 for (Metrics::const_iterator ii = metrics.begin(); ii != metrics.end(); ++ii) {
1359                                         TempoSection* t;
1360                                         if ((*ii)->is_tempo()) {
1361                                                 t = static_cast<TempoSection*> (*ii);
1362                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
1363                                                         meter_locked_tempo = t;
1364                                                         break;
1365                                                 }
1366                                         }
1367                                 }
1368
1369                                 if (prev_m) {
1370                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1371                                         if (beats + prev_m->beat() != meter->beat()) {
1372                                                 /* reordering caused a bbt change */
1373                                                 b_bbt = make_pair (beats + prev_m->beat()
1374                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1375                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1376
1377                                         } else if (meter->movable()) {
1378                                                 b_bbt = make_pair (meter->beat(), meter->bbt());
1379                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1380                                         }
1381                                 } else {
1382                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
1383                                 }
1384                                 if (meter_locked_tempo) {
1385                                         meter_locked_tempo->set_pulse (pulse);
1386                                 }
1387                                 meter->set_beat (b_bbt);
1388                                 meter->set_pulse (pulse);
1389
1390                         } else {
1391                                 /* MusicTime */
1392                                 double pulse = 0.0;
1393                                 pair<double, BBT_Time> b_bbt;
1394                                 if (prev_m) {
1395                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1396                                         if (beats + prev_m->beat() != meter->beat()) {
1397                                                 /* reordering caused a bbt change */
1398                                                 b_bbt = make_pair (beats + prev_m->beat()
1399                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1400                                         } else {
1401                                                 b_bbt = make_pair (beats + prev_m->beat(), meter->bbt());
1402                                         }
1403                                         pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
1404                                 } else {
1405                                         /* shouldn't happen - the first is audio-locked */
1406                                         pulse = pulse_at_beat_locked (metrics, meter->beat());
1407                                         b_bbt = make_pair (meter->beat(), meter->bbt());
1408                                 }
1409
1410                                 meter->set_beat (b_bbt);
1411                                 meter->set_pulse (pulse);
1412                                 meter->set_minute (minute_at_pulse_locked (metrics, pulse));
1413                         }
1414
1415                         prev_m = meter;
1416                 }
1417         }
1418 }
1419
1420 void
1421 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1422 {
1423         /* CALLER MUST HOLD WRITE LOCK */
1424
1425         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1426
1427         if (end == 0) {
1428                 /* silly call from Session::process() during startup
1429                  */
1430                 return;
1431         }
1432
1433         recompute_tempi (metrics);
1434         recompute_meters (metrics);
1435 }
1436
1437 TempoMetric
1438 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1439 {
1440         Glib::Threads::RWLock::ReaderLock lm (lock);
1441         TempoMetric m (first_meter(), first_tempo());
1442
1443         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1444            at something, because we insert the default tempo and meter during
1445            TempoMap construction.
1446
1447            now see if we can find better candidates.
1448         */
1449
1450         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1451
1452                 if ((*i)->frame() > frame) {
1453                         break;
1454                 }
1455
1456                 m.set_metric(*i);
1457
1458                 if (last) {
1459                         *last = i;
1460                 }
1461         }
1462
1463         return m;
1464 }
1465
1466 /* XX meters only */
1467 TempoMetric
1468 TempoMap::metric_at (BBT_Time bbt) const
1469 {
1470         Glib::Threads::RWLock::ReaderLock lm (lock);
1471         TempoMetric m (first_meter(), first_tempo());
1472
1473         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1474            at something, because we insert the default tempo and meter during
1475            TempoMap construction.
1476
1477            now see if we can find better candidates.
1478         */
1479
1480         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1481                 MeterSection* mw;
1482                 if (!(*i)->is_tempo()) {
1483                         mw = static_cast<MeterSection*> (*i);
1484                         BBT_Time section_start (mw->bbt());
1485
1486                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1487                                 break;
1488                         }
1489
1490                         m.set_metric (*i);
1491                 }
1492         }
1493
1494         return m;
1495 }
1496
1497 /** Returns the BBT (meter-based) beat corresponding to the supplied frame, possibly returning a negative value.
1498  * @param frame The session frame position.
1499  * @return The beat duration according to the tempo map at the supplied frame.
1500  *
1501  * If the supplied frame lies before the first meter, the returned beat duration will be negative.
1502  * The returned beat is obtained using the first meter and the continuation of the tempo curve (backwards).
1503  *
1504  * This function uses both tempo and meter.
1505  */
1506 double
1507 TempoMap::beat_at_frame (const framecnt_t& frame) const
1508 {
1509         Glib::Threads::RWLock::ReaderLock lm (lock);
1510
1511         return beat_at_minute_locked (_metrics, minute_at_frame (frame));
1512 }
1513
1514 /* This function uses both tempo and meter.*/
1515 double
1516 TempoMap::beat_at_minute_locked (const Metrics& metrics, const double& minute) const
1517 {
1518         const TempoSection& ts = tempo_section_at_minute_locked (metrics, minute);
1519         MeterSection* prev_m = 0;
1520         MeterSection* next_m = 0;
1521
1522         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1523                 if (!(*i)->is_tempo()) {
1524                         if (prev_m && (*i)->minute() > minute) {
1525                                 next_m = static_cast<MeterSection*> (*i);
1526                                 break;
1527                         }
1528                         prev_m = static_cast<MeterSection*> (*i);
1529                 }
1530         }
1531
1532         const double beat = prev_m->beat() + (ts.pulse_at_minute (minute) - prev_m->pulse()) * prev_m->note_divisor();
1533
1534         /* audio locked meters fake their beat */
1535         if (next_m && next_m->beat() < beat) {
1536                 return next_m->beat();
1537         }
1538
1539         return beat;
1540 }
1541
1542 /** Returns the frame corresponding to the supplied BBT (meter-based) beat.
1543  * @param beat The BBT (meter-based) beat.
1544  * @return The frame duration according to the tempo map at the supplied BBT (meter-based) beat.
1545  *
1546  * This function uses both tempo and meter.
1547  */
1548 framepos_t
1549 TempoMap::frame_at_beat (const double& beat) const
1550 {
1551         Glib::Threads::RWLock::ReaderLock lm (lock);
1552
1553         return frame_at_minute (minute_at_beat_locked (_metrics, beat));
1554 }
1555
1556 /* meter & tempo section based */
1557 double
1558 TempoMap::minute_at_beat_locked (const Metrics& metrics, const double& beat) const
1559 {
1560         MeterSection* prev_m = 0;
1561         TempoSection* prev_t = 0;
1562
1563         MeterSection* m;
1564
1565         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1566                 if (!(*i)->is_tempo()) {
1567                         m = static_cast<MeterSection*> (*i);
1568                         if (prev_m && m->beat() > beat) {
1569                                 break;
1570                         }
1571                         prev_m = m;
1572                 }
1573         }
1574         assert (prev_m);
1575
1576         TempoSection* t;
1577
1578         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1579                 if ((*i)->is_tempo()) {
1580                         t = static_cast<TempoSection*> (*i);
1581                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
1582                                 break;
1583                         }
1584                         prev_t = t;
1585                 }
1586
1587         }
1588         assert (prev_t);
1589
1590         return prev_t->minute_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse());
1591 }
1592
1593 /** Returns a Tempo corresponding to the supplied frame position.
1594  * @param frame The audio frame.
1595  * @return a Tempo according to the tempo map at the supplied frame.
1596  *
1597  */
1598 Tempo
1599 TempoMap::tempo_at_frame (const framepos_t& frame) const
1600 {
1601         Glib::Threads::RWLock::ReaderLock lm (lock);
1602
1603         return tempo_at_minute_locked (_metrics, minute_at_frame (frame));
1604 }
1605
1606 Tempo
1607 TempoMap::tempo_at_minute_locked (const Metrics& metrics, const double& minute) const
1608 {
1609         TempoSection* prev_t = 0;
1610
1611         TempoSection* t;
1612
1613         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1614                 if ((*i)->is_tempo()) {
1615                         t = static_cast<TempoSection*> (*i);
1616                         if (!t->active()) {
1617                                 continue;
1618                         }
1619                         if ((prev_t) && t->minute() > minute) {
1620                                 /* t is the section past frame */
1621                                 return prev_t->tempo_at_minute (minute);
1622                         }
1623                         prev_t = t;
1624                 }
1625         }
1626
1627         return Tempo (prev_t->note_types_per_minute(), prev_t->note_type());
1628 }
1629
1630 /** returns the frame at which the supplied tempo occurs, or
1631  *  the frame of the last tempo section (search exhausted)
1632  *  only the position of the first occurence will be returned
1633  *  (extend me)
1634 */
1635 framepos_t
1636 TempoMap::frame_at_tempo (const Tempo& tempo) const
1637 {
1638         Glib::Threads::RWLock::ReaderLock lm (lock);
1639
1640         return frame_at_minute (minute_at_tempo_locked (_metrics, tempo));
1641 }
1642
1643 double
1644 TempoMap::minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1645 {
1646         TempoSection* prev_t = 0;
1647         const double tempo_bpm = tempo.note_types_per_minute();
1648
1649         Metrics::const_iterator i;
1650
1651         for (i = metrics.begin(); i != metrics.end(); ++i) {
1652                 TempoSection* t;
1653                 if ((*i)->is_tempo()) {
1654                         t = static_cast<TempoSection*> (*i);
1655
1656                         if (!t->active()) {
1657                                 continue;
1658                         }
1659
1660                         const double t_bpm = t->note_types_per_minute();
1661
1662                         if (t_bpm == tempo_bpm) {
1663                                 return t->minute();
1664                         }
1665
1666                         if (prev_t) {
1667                                 const double prev_t_bpm = prev_t->note_types_per_minute();
1668
1669                                 if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) {
1670                                         return prev_t->minute_at_ntpm (prev_t->note_types_per_minute(), prev_t->pulse());
1671                                 }
1672                         }
1673                         prev_t = t;
1674                 }
1675         }
1676
1677         return prev_t->minute();
1678 }
1679
1680 Tempo
1681 TempoMap::tempo_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1682 {
1683         TempoSection* prev_t = 0;
1684
1685         TempoSection* t;
1686
1687         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1688                 if ((*i)->is_tempo()) {
1689                         t = static_cast<TempoSection*> (*i);
1690                         if (!t->active()) {
1691                                 continue;
1692                         }
1693                         if ((prev_t) && t->pulse() > pulse) {
1694                                 /* t is the section past frame */
1695                                 return prev_t->tempo_at_pulse (pulse);
1696                         }
1697                         prev_t = t;
1698                 }
1699         }
1700
1701         return Tempo (prev_t->note_types_per_minute(), prev_t->note_type());
1702 }
1703
1704 double
1705 TempoMap::pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1706 {
1707         TempoSection* prev_t = 0;
1708         const double tempo_bpm = tempo.note_types_per_minute();
1709
1710         Metrics::const_iterator i;
1711
1712         for (i = metrics.begin(); i != metrics.end(); ++i) {
1713                 TempoSection* t;
1714                 if ((*i)->is_tempo()) {
1715                         t = static_cast<TempoSection*> (*i);
1716
1717                         if (!t->active()) {
1718                                 continue;
1719                         }
1720
1721                         const double t_bpm = t->note_types_per_minute();
1722
1723                         if (t_bpm == tempo_bpm) {
1724                                 return t->pulse();
1725                         }
1726
1727                         if (prev_t) {
1728                                 const double prev_t_bpm = prev_t->note_types_per_minute();
1729
1730                                 if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) {
1731                                         return prev_t->pulse_at_ntpm (prev_t->note_types_per_minute(), prev_t->minute());
1732                                 }
1733                         }
1734                         prev_t = t;
1735                 }
1736         }
1737
1738         return prev_t->pulse();
1739 }
1740
1741 /** Returns a Tempo corresponding to the supplied position in quarter-note beats.
1742  * @param qn the position in quarter note beats.
1743  * @return the Tempo at the supplied quarter-note.
1744  */
1745 Tempo
1746 TempoMap::tempo_at_quarter_note (const double& qn) const
1747 {
1748         Glib::Threads::RWLock::ReaderLock lm (lock);
1749
1750         return tempo_at_pulse_locked (_metrics, qn / 4.0);
1751 }
1752
1753 /** Returns the position in quarter-note beats corresponding to the supplied Tempo.
1754  * @param tempo the tempo.
1755  * @return the position in quarter-note beats where the map bpm
1756  * is equal to that of the Tempo. currently ignores note_type.
1757  */
1758 double
1759 TempoMap::quarter_note_at_tempo (const Tempo& tempo) const
1760 {
1761         Glib::Threads::RWLock::ReaderLock lm (lock);
1762
1763         return pulse_at_tempo_locked (_metrics, tempo) * 4.0;;
1764 }
1765
1766 /** Returns the whole-note pulse corresponding to the supplied  BBT (meter-based) beat.
1767  * @param metrics the list of metric sections used to calculate the pulse.
1768  * @param beat The BBT (meter-based) beat.
1769  * @return the whole-note pulse at the supplied BBT (meter-based) beat.
1770  *
1771  * a pulse or whole note is the base musical position of a MetricSection.
1772  * it is equivalent to four quarter notes.
1773  *
1774  */
1775 double
1776 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1777 {
1778         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1779
1780         return prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1781 }
1782
1783 /** Returns the BBT (meter-based) beat corresponding to the supplied whole-note pulse .
1784  * @param metrics the list of metric sections used to calculate the beat.
1785  * @param pulse the whole-note pulse.
1786  * @return the meter-based beat at the supplied whole-note pulse.
1787  *
1788  * a pulse or whole note is the base musical position of a MetricSection.
1789  * it is equivalent to four quarter notes.
1790  */
1791 double
1792 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1793 {
1794         MeterSection* prev_m = 0;
1795
1796         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1797                 MeterSection* m;
1798                 if (!(*i)->is_tempo()) {
1799                         m = static_cast<MeterSection*> (*i);
1800                         if (prev_m && m->pulse() > pulse) {
1801                                 break;
1802                         }
1803                         prev_m = m;
1804                 }
1805         }
1806         assert (prev_m);
1807
1808         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1809         return ret;
1810 }
1811
1812 /* tempo section based */
1813 double
1814 TempoMap::pulse_at_minute_locked (const Metrics& metrics, const double& minute) const
1815 {
1816         /* HOLD (at least) THE READER LOCK */
1817         TempoSection* prev_t = 0;
1818
1819         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1820                 TempoSection* t;
1821                 if ((*i)->is_tempo()) {
1822                         t = static_cast<TempoSection*> (*i);
1823                         if (!t->active()) {
1824                                 continue;
1825                         }
1826                         if (prev_t && t->minute() > minute) {
1827                                 /*the previous ts is the one containing the frame */
1828                                 const double ret = prev_t->pulse_at_minute (minute);
1829                                 /* audio locked section in new meter*/
1830                                 if (t->pulse() < ret) {
1831                                         return t->pulse();
1832                                 }
1833                                 return ret;
1834                         }
1835                         prev_t = t;
1836                 }
1837         }
1838
1839         /* treated as constant for this ts */
1840         const double pulses_in_section = ((minute - prev_t->minute()) * prev_t->note_types_per_minute()) / prev_t->note_type();
1841
1842         return pulses_in_section + prev_t->pulse();
1843 }
1844
1845 /* tempo section based */
1846 double
1847 TempoMap::minute_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1848 {
1849         /* HOLD THE READER LOCK */
1850
1851         const TempoSection* prev_t = 0;
1852
1853         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1854                 TempoSection* t;
1855
1856                 if ((*i)->is_tempo()) {
1857                         t = static_cast<TempoSection*> (*i);
1858                         if (!t->active()) {
1859                                 continue;
1860                         }
1861                         if (prev_t && t->pulse() > pulse) {
1862                                 return prev_t->minute_at_pulse (pulse);
1863                         }
1864
1865                         prev_t = t;
1866                 }
1867         }
1868         /* must be treated as constant, irrespective of _type */
1869         double const dtime = ((pulse - prev_t->pulse()) * prev_t->note_type()) / prev_t->note_types_per_minute();
1870
1871         return dtime + prev_t->minute();
1872 }
1873
1874 /** Returns the BBT (meter-based) beat corresponding to the supplied BBT time.
1875  * @param bbt The BBT time (meter-based).
1876  * @return bbt The BBT beat (meter-based) at the supplied BBT time.
1877  *
1878  */
1879 double
1880 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1881 {
1882         Glib::Threads::RWLock::ReaderLock lm (lock);
1883         return beat_at_bbt_locked (_metrics, bbt);
1884 }
1885
1886
1887 double
1888 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1889 {
1890         /* CALLER HOLDS READ LOCK */
1891
1892         MeterSection* prev_m = 0;
1893
1894         /* because audio-locked meters have 'fake' integral beats,
1895            there is no pulse offset here.
1896         */
1897         MeterSection* m;
1898
1899         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1900                 if (!(*i)->is_tempo()) {
1901                         m = static_cast<MeterSection*> (*i);
1902                         if (prev_m) {
1903                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1904                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1905                                         break;
1906                                 }
1907                         }
1908                         prev_m = m;
1909                 }
1910         }
1911
1912         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1913         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1914         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1915
1916         return ret;
1917 }
1918
1919 /** Returns the BBT time corresponding to the supplied BBT (meter-based) beat.
1920  * @param beat The BBT (meter-based) beat.
1921  * @return The BBT time (meter-based) at the supplied meter-based beat.
1922  *
1923  */
1924 Timecode::BBT_Time
1925 TempoMap::bbt_at_beat (const double& beat)
1926 {
1927         Glib::Threads::RWLock::ReaderLock lm (lock);
1928         return bbt_at_beat_locked (_metrics, beat);
1929 }
1930
1931 Timecode::BBT_Time
1932 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1933 {
1934         /* CALLER HOLDS READ LOCK */
1935         MeterSection* prev_m = 0;
1936         const double beats = max (0.0, b);
1937
1938         MeterSection* m = 0;
1939
1940         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1941                 if (!(*i)->is_tempo()) {
1942                         m = static_cast<MeterSection*> (*i);
1943                         if (prev_m) {
1944                                 if (m->beat() > beats) {
1945                                         /* this is the meter after the one our beat is on*/
1946                                         break;
1947                                 }
1948                         }
1949
1950                         prev_m = m;
1951                 }
1952         }
1953         assert (prev_m);
1954
1955         const double beats_in_ms = beats - prev_m->beat();
1956         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1957         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1958         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1959         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1960
1961         BBT_Time ret;
1962
1963         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1964         ret.beats = (uint32_t) floor (remaining_beats);
1965         ret.bars = total_bars;
1966
1967         /* 0 0 0 to 1 1 0 - based mapping*/
1968         ++ret.bars;
1969         ++ret.beats;
1970
1971         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1972                 ++ret.beats;
1973                 ret.ticks -= BBT_Time::ticks_per_beat;
1974         }
1975
1976         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1977                 ++ret.bars;
1978                 ret.beats = 1;
1979         }
1980
1981         return ret;
1982 }
1983
1984 /** Returns the quarter-note beat corresponding to the supplied BBT time (meter-based).
1985  * @param bbt The BBT time (meter-based).
1986  * @return the quarter note beat at the supplied BBT time
1987  *
1988  * quarter-notes ignore meter and are based on pulse (the musical unit of MetricSection).
1989  *
1990  * while the input uses meter, the output does not.
1991  */
1992 double
1993 TempoMap::quarter_note_at_bbt (const Timecode::BBT_Time& bbt)
1994 {
1995         Glib::Threads::RWLock::ReaderLock lm (lock);
1996
1997         return pulse_at_bbt_locked (_metrics, bbt) * 4.0;
1998 }
1999
2000 double
2001 TempoMap::quarter_note_at_bbt_rt (const Timecode::BBT_Time& bbt)
2002 {
2003         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2004
2005         if (!lm.locked()) {
2006                 throw std::logic_error ("TempoMap::quarter_note_at_bbt_rt() could not lock tempo map");
2007         }
2008
2009         return pulse_at_bbt_locked (_metrics, bbt) * 4.0;
2010 }
2011
2012 double
2013 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
2014 {
2015         /* CALLER HOLDS READ LOCK */
2016
2017         MeterSection* prev_m = 0;
2018
2019         /* because audio-locked meters have 'fake' integral beats,
2020            there is no pulse offset here.
2021         */
2022         MeterSection* m;
2023
2024         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2025                 if (!(*i)->is_tempo()) {
2026                         m = static_cast<MeterSection*> (*i);
2027                         if (prev_m) {
2028                                 if (m->bbt().bars > bbt.bars) {
2029                                         break;
2030                                 }
2031                         }
2032                         prev_m = m;
2033                 }
2034         }
2035
2036         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
2037         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
2038         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
2039
2040         return ret;
2041 }
2042
2043 /** Returns the BBT time corresponding to the supplied quarter-note beat.
2044  * @param qn the quarter-note beat.
2045  * @return The BBT time (meter-based) at the supplied meter-based beat.
2046  *
2047  * quarter-notes ignore meter and are based on pulse (the musical unit of MetricSection).
2048  *
2049  */
2050 Timecode::BBT_Time
2051 TempoMap::bbt_at_quarter_note (const double& qn)
2052 {
2053         Glib::Threads::RWLock::ReaderLock lm (lock);
2054
2055         return bbt_at_pulse_locked (_metrics, qn / 4.0);
2056 }
2057
2058 /** Returns the BBT time (meter-based) corresponding to the supplied whole-note pulse position.
2059  * @param metrics The list of metric sections used to determine the result.
2060  * @param pulse The whole-note pulse.
2061  * @return The BBT time at the supplied whole-note pulse.
2062  *
2063  * a pulse or whole note is the basic musical position of a MetricSection.
2064  * it is equivalent to four quarter notes.
2065  * while the output uses meter, the input does not.
2066  */
2067 Timecode::BBT_Time
2068 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
2069 {
2070         MeterSection* prev_m = 0;
2071
2072         MeterSection* m = 0;
2073
2074         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2075
2076                 if (!(*i)->is_tempo()) {
2077                         m = static_cast<MeterSection*> (*i);
2078
2079                         if (prev_m) {
2080                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
2081                                 if (prev_m->pulse() + pulses_to_m > pulse) {
2082                                         /* this is the meter after the one our beat is on*/
2083                                         break;
2084                                 }
2085                         }
2086
2087                         prev_m = m;
2088                 }
2089         }
2090
2091         assert (prev_m);
2092
2093         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
2094         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2095         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2096         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2097         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2098
2099         BBT_Time ret;
2100
2101         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2102         ret.beats = (uint32_t) floor (remaining_beats);
2103         ret.bars = total_bars;
2104
2105         /* 0 0 0 to 1 1 0 mapping*/
2106         ++ret.bars;
2107         ++ret.beats;
2108
2109         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2110                 ++ret.beats;
2111                 ret.ticks -= BBT_Time::ticks_per_beat;
2112         }
2113
2114         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2115                 ++ret.bars;
2116                 ret.beats = 1;
2117         }
2118
2119         return ret;
2120 }
2121
2122 /** Returns the BBT time corresponding to the supplied frame position.
2123  * @param frame the position in audio samples.
2124  * @return the BBT time at the frame position .
2125  *
2126  */
2127 BBT_Time
2128 TempoMap::bbt_at_frame (framepos_t frame)
2129 {
2130         if (frame < 0) {
2131                 BBT_Time bbt;
2132                 bbt.bars = 1;
2133                 bbt.beats = 1;
2134                 bbt.ticks = 0;
2135                 warning << string_compose (_("tempo map was asked for BBT time at frame %1\n"), frame) << endmsg;
2136                 return bbt;
2137         }
2138         Glib::Threads::RWLock::ReaderLock lm (lock);
2139
2140         return bbt_at_minute_locked (_metrics, minute_at_frame (frame));
2141 }
2142
2143 BBT_Time
2144 TempoMap::bbt_at_frame_rt (framepos_t frame)
2145 {
2146         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2147
2148         if (!lm.locked()) {
2149                 throw std::logic_error ("TempoMap::bbt_at_frame_rt() could not lock tempo map");
2150         }
2151
2152         return bbt_at_minute_locked (_metrics, minute_at_frame (frame));
2153 }
2154
2155 Timecode::BBT_Time
2156 TempoMap::bbt_at_minute_locked (const Metrics& metrics, const double& minute) const
2157 {
2158         if (minute < 0) {
2159                 BBT_Time bbt;
2160                 bbt.bars = 1;
2161                 bbt.beats = 1;
2162                 bbt.ticks = 0;
2163                 return bbt;
2164         }
2165
2166         const TempoSection& ts = tempo_section_at_minute_locked (metrics, minute);
2167         MeterSection* prev_m = 0;
2168         MeterSection* next_m = 0;
2169
2170         MeterSection* m;
2171
2172         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2173                 if (!(*i)->is_tempo()) {
2174                         m = static_cast<MeterSection*> (*i);
2175                         if (prev_m && m->minute() > minute) {
2176                                 next_m = m;
2177                                 break;
2178                         }
2179                         prev_m = m;
2180                 }
2181         }
2182
2183         double beat = prev_m->beat() + (ts.pulse_at_minute (minute) - prev_m->pulse()) * prev_m->note_divisor();
2184
2185         /* handle frame before first meter */
2186         if (minute < prev_m->minute()) {
2187                 beat = 0.0;
2188         }
2189         /* audio locked meters fake their beat */
2190         if (next_m && next_m->beat() < beat) {
2191                 beat = next_m->beat();
2192         }
2193
2194         beat = max (0.0, beat);
2195
2196         const double beats_in_ms = beat - prev_m->beat();
2197         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2198         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2199         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2200         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2201
2202         BBT_Time ret;
2203
2204         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2205         ret.beats = (uint32_t) floor (remaining_beats);
2206         ret.bars = total_bars;
2207
2208         /* 0 0 0 to 1 1 0 - based mapping*/
2209         ++ret.bars;
2210         ++ret.beats;
2211
2212         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2213                 ++ret.beats;
2214                 ret.ticks -= BBT_Time::ticks_per_beat;
2215         }
2216
2217         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2218                 ++ret.bars;
2219                 ret.beats = 1;
2220         }
2221
2222         return ret;
2223 }
2224
2225 /** Returns the frame position corresponding to the supplied BBT time.
2226  * @param bbt the position in BBT time.
2227  * @return the frame position at bbt.
2228  *
2229  */
2230 framepos_t
2231 TempoMap::frame_at_bbt (const BBT_Time& bbt)
2232 {
2233         if (bbt.bars < 1) {
2234                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
2235                 return 0;
2236         }
2237
2238         if (bbt.beats < 1) {
2239                 throw std::logic_error ("beats are counted from one");
2240         }
2241         Glib::Threads::RWLock::ReaderLock lm (lock);
2242
2243         return frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
2244 }
2245
2246 /* meter & tempo section based */
2247 double
2248 TempoMap::minute_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
2249 {
2250         /* HOLD THE READER LOCK */
2251
2252         const double ret = minute_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
2253         return ret;
2254 }
2255
2256 /**
2257  * Returns the quarter-note beat position corresponding to the supplied frame.
2258  *
2259  * @param frame the position in frames.
2260  * @return The quarter-note position of the supplied frame. Ignores meter.
2261  *
2262 */
2263 double
2264 TempoMap::quarter_note_at_frame (const framepos_t frame) const
2265 {
2266         Glib::Threads::RWLock::ReaderLock lm (lock);
2267
2268         const double ret = quarter_note_at_minute_locked (_metrics, minute_at_frame (frame));
2269
2270         return ret;
2271 }
2272
2273 double
2274 TempoMap::quarter_note_at_minute_locked (const Metrics& metrics, const double minute) const
2275 {
2276         const double ret = pulse_at_minute_locked (metrics, minute) * 4.0;
2277
2278         return ret;
2279 }
2280
2281 double
2282 TempoMap::quarter_note_at_frame_rt (const framepos_t frame) const
2283 {
2284         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2285
2286         if (!lm.locked()) {
2287                 throw std::logic_error ("TempoMap::quarter_note_at_frame_rt() could not lock tempo map");
2288         }
2289
2290         const double ret = pulse_at_minute_locked (_metrics, minute_at_frame (frame)) * 4.0;
2291
2292         return ret;
2293 }
2294
2295 /**
2296  * Returns the frame position corresponding to the supplied quarter-note beat.
2297  *
2298  * @param quarter_note the quarter-note position.
2299  * @return the frame position of the supplied quarter-note. Ignores meter.
2300  *
2301  *
2302 */
2303 framepos_t
2304 TempoMap::frame_at_quarter_note (const double quarter_note) const
2305 {
2306         Glib::Threads::RWLock::ReaderLock lm (lock);
2307
2308         const framepos_t ret = frame_at_minute (minute_at_quarter_note_locked (_metrics, quarter_note));
2309
2310         return ret;
2311 }
2312
2313 double
2314 TempoMap::minute_at_quarter_note_locked (const Metrics& metrics, const double quarter_note) const
2315 {
2316         const double ret = minute_at_pulse_locked (metrics, quarter_note / 4.0);
2317
2318         return ret;
2319 }
2320
2321 /** Returns the quarter-note beats corresponding to the supplied BBT (meter-based) beat.
2322  * @param beat The BBT (meter-based) beat.
2323  * @return The quarter-note position of the supplied BBT (meter-based) beat.
2324  *
2325  * a quarter-note may be compared with and assigned to Evoral::Beats.
2326  *
2327  */
2328 double
2329 TempoMap::quarter_note_at_beat (const double beat)
2330 {
2331         Glib::Threads::RWLock::ReaderLock lm (lock);
2332
2333         const double ret = quarter_note_at_beat_locked (_metrics, beat);
2334
2335         return ret;
2336 }
2337
2338 double
2339 TempoMap::quarter_note_at_beat_locked (const Metrics& metrics, const double beat) const
2340 {
2341         const double ret = pulse_at_beat_locked (metrics, beat) * 4.0;
2342
2343         return ret;
2344 }
2345
2346 /** Returns the BBT (meter-based) beat position corresponding to the supplied quarter-note beats.
2347  * @param quarter_note The position in quarter-note beats.
2348  * @return the BBT (meter-based) beat position of the supplied quarter-note beats.
2349  *
2350  * a quarter-note is the musical unit of Evoral::Beats.
2351  *
2352  */
2353 double
2354 TempoMap::beat_at_quarter_note (const double quarter_note)
2355 {
2356         Glib::Threads::RWLock::ReaderLock lm (lock);
2357
2358         const double ret = beat_at_quarter_note_locked (_metrics, quarter_note);
2359
2360         return ret;
2361 }
2362
2363 double
2364 TempoMap::beat_at_quarter_note_locked (const Metrics& metrics, const double quarter_note) const
2365 {
2366
2367         return beat_at_pulse_locked (metrics, quarter_note / 4.0);
2368 }
2369
2370 /** Returns the duration in frames between two supplied quarter-note beat positions.
2371  * @param start the first position in quarter-note beats.
2372  * @param end the end position in quarter-note beats.
2373  * @return the frame distance ober the quarter-note beats duration.
2374  *
2375  * use this rather than e.g.
2376  * frame_at-quarter_note (end_beats) - frame_at_quarter_note (start_beats).
2377  * frames_between_quarter_notes() doesn't round to audio frames as an intermediate step,
2378  *
2379  */
2380 framecnt_t
2381 TempoMap::frames_between_quarter_notes (const double start, const double end) const
2382 {
2383         Glib::Threads::RWLock::ReaderLock lm (lock);
2384
2385         return frame_at_minute (minutes_between_quarter_notes_locked (_metrics, start, end));
2386 }
2387
2388 double
2389 TempoMap::minutes_between_quarter_notes_locked (const Metrics& metrics, const double start, const double end) const
2390 {
2391
2392         return minute_at_pulse_locked (metrics, end / 4.0) - minute_at_pulse_locked (metrics, start / 4.0);
2393 }
2394
2395 double
2396 TempoMap::quarter_notes_between_frames (const framecnt_t start, const framecnt_t end) const
2397 {
2398         Glib::Threads::RWLock::ReaderLock lm (lock);
2399
2400         return quarter_notes_between_frames_locked (_metrics, start, end);
2401 }
2402
2403 double
2404 TempoMap::quarter_notes_between_frames_locked (const Metrics& metrics, const framecnt_t start, const framecnt_t end) const
2405 {
2406         const TempoSection* prev_t = 0;
2407
2408         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2409                 TempoSection* t;
2410
2411                 if ((*i)->is_tempo()) {
2412                         t = static_cast<TempoSection*> (*i);
2413                         if (!t->active()) {
2414                                 continue;
2415                         }
2416                         if (prev_t && t->frame() > start) {
2417                                 break;
2418                         }
2419                         prev_t = t;
2420                 }
2421         }
2422         assert (prev_t);
2423         const double start_qn = prev_t->pulse_at_frame (start);
2424
2425         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2426                 TempoSection* t;
2427
2428                 if ((*i)->is_tempo()) {
2429                         t = static_cast<TempoSection*> (*i);
2430                         if (!t->active()) {
2431                                 continue;
2432                         }
2433                         if (prev_t && t->frame() > end) {
2434                                 break;
2435                         }
2436                         prev_t = t;
2437                 }
2438         }
2439         const double end_qn = prev_t->pulse_at_frame (end);
2440
2441         return (end_qn - start_qn) * 4.0;
2442 }
2443
2444 bool
2445 TempoMap::check_solved (const Metrics& metrics) const
2446 {
2447         TempoSection* prev_t = 0;
2448         MeterSection* prev_m = 0;
2449
2450         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2451                 TempoSection* t;
2452                 MeterSection* m;
2453                 if ((*i)->is_tempo()) {
2454                         t = static_cast<TempoSection*> (*i);
2455                         if (!t->active()) {
2456                                 continue;
2457                         }
2458                         if (prev_t) {
2459                                 /* check ordering */
2460                                 if ((t->minute() <= prev_t->minute()) || (t->pulse() <= prev_t->pulse())) {
2461                                         return false;
2462                                 }
2463
2464                                 /* precision check ensures tempo and frames align.*/
2465                                 if (t->frame() != frame_at_minute (prev_t->minute_at_ntpm (t->note_types_per_minute(), t->pulse()))) {
2466                                         if (!t->locked_to_meter()) {
2467                                                 return false;
2468                                         }
2469                                 }
2470
2471                                 /* gradient limit - who knows what it should be?
2472                                    things are also ok (if a little chaotic) without this
2473                                 */
2474                                 if (fabs (prev_t->c_func()) > 1000.0) {
2475                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
2476                                         return false;
2477                                 }
2478                         }
2479                         prev_t = t;
2480                 }
2481
2482                 if (!(*i)->is_tempo()) {
2483                         m = static_cast<MeterSection*> (*i);
2484                         if (prev_m && m->position_lock_style() == AudioTime) {
2485                                 const TempoSection* t = &tempo_section_at_minute_locked (metrics, minute_at_frame (m->frame() - 1));
2486                                 const double nascent_m_minute = t->minute_at_pulse (m->pulse());
2487                                 /* Here we check that a preceding section of music doesn't overlap a subsequent one.
2488                                 */
2489                                 if (t && (nascent_m_minute > m->minute() || nascent_m_minute < 0.0)) {
2490                                         return false;
2491                                 }
2492                         }
2493
2494                         prev_m = m;
2495                 }
2496
2497         }
2498
2499         return true;
2500 }
2501
2502 bool
2503 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
2504 {
2505         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2506                 TempoSection* t;
2507                 if ((*i)->is_tempo()) {
2508                         t = static_cast<TempoSection*> (*i);
2509                         if (!t->movable()) {
2510                                 t->set_active (true);
2511                                 continue;
2512                         }
2513                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
2514                                 t->set_active (false);
2515                                 t->set_pulse (0.0);
2516                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
2517                                 t->set_active (true);
2518                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
2519                                 return false;
2520                         }
2521                 }
2522         }
2523         return true;
2524 }
2525
2526 bool
2527 TempoMap::solve_map_minute (Metrics& imaginary, TempoSection* section, const double& minute)
2528 {
2529         TempoSection* prev_t = 0;
2530         TempoSection* section_prev = 0;
2531         double first_m_minute = 0.0;
2532
2533         /* can't move a tempo before the first meter */
2534         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2535                 MeterSection* m;
2536                 if (!(*i)->is_tempo()) {
2537                         m = static_cast<MeterSection*> (*i);
2538                         if (!m->movable()) {
2539                                 first_m_minute = m->minute();
2540                                 break;
2541                         }
2542                 }
2543         }
2544         if (section->movable() && minute <= first_m_minute) {
2545                 return false;
2546         }
2547
2548         section->set_active (true);
2549         section->set_minute (minute);
2550
2551         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2552                 TempoSection* t;
2553                 if ((*i)->is_tempo()) {
2554                         t = static_cast<TempoSection*> (*i);
2555
2556                         if (!t->active()) {
2557                                 continue;
2558                         }
2559                         if (prev_t) {
2560                                 if (t == section) {
2561                                         section_prev = prev_t;
2562                                         if (t->locked_to_meter()) {
2563                                                 prev_t = t;
2564                                         }
2565                                         continue;
2566                                 }
2567                                 if (t->position_lock_style() == MusicTime) {
2568                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->note_types_per_minute(), t->pulse()));
2569                                         t->set_minute (prev_t->minute_at_ntpm (t->note_types_per_minute(), t->pulse()));
2570                                 } else {
2571                                         prev_t->set_c_func (prev_t->compute_c_func_minute (t->note_types_per_minute(), t->minute()));
2572                                         if (!t->locked_to_meter()) {
2573                                                 t->set_pulse (prev_t->pulse_at_ntpm (t->note_types_per_minute(), t->minute()));
2574                                         }
2575                                 }
2576                         }
2577                         prev_t = t;
2578                 }
2579         }
2580
2581         if (section_prev) {
2582                 section_prev->set_c_func (section_prev->compute_c_func_minute (section->note_types_per_minute(), minute));
2583                 if (!section->locked_to_meter()) {
2584                         section->set_pulse (section_prev->pulse_at_ntpm (section->note_types_per_minute(), minute));
2585                 }
2586         }
2587
2588 #if (0)
2589         recompute_tempi (imaginary);
2590
2591         if (check_solved (imaginary)) {
2592                 return true;
2593         } else {
2594                 dunp (imaginary, std::cout);
2595         }
2596 #endif
2597
2598         MetricSectionFrameSorter fcmp;
2599         imaginary.sort (fcmp);
2600
2601         recompute_tempi (imaginary);
2602
2603         if (check_solved (imaginary)) {
2604                 return true;
2605         }
2606
2607         return false;
2608 }
2609
2610 bool
2611 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2612 {
2613         TempoSection* prev_t = 0;
2614         TempoSection* section_prev = 0;
2615
2616         section->set_pulse (pulse);
2617
2618         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2619                 TempoSection* t;
2620                 if ((*i)->is_tempo()) {
2621                         t = static_cast<TempoSection*> (*i);
2622                         if (!t->active()) {
2623                                 continue;
2624                         }
2625                         if (!t->movable()) {
2626                                 t->set_pulse (0.0);
2627                                 prev_t = t;
2628                                 continue;
2629                         }
2630                         if (prev_t) {
2631                                 if (t == section) {
2632                                         section_prev = prev_t;
2633                                         continue;
2634                                 }
2635                                 if (t->position_lock_style() == MusicTime) {
2636                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->note_types_per_minute(), t->pulse()));
2637                                         t->set_minute (prev_t->minute_at_ntpm (t->note_types_per_minute(), t->pulse()));
2638                                 } else {
2639                                         prev_t->set_c_func (prev_t->compute_c_func_minute (t->note_types_per_minute(), t->minute()));
2640                                         if (!t->locked_to_meter()) {
2641                                                 t->set_pulse (prev_t->pulse_at_ntpm (t->note_types_per_minute(), t->minute()));
2642                                         }
2643                                 }
2644                         }
2645                         prev_t = t;
2646                 }
2647         }
2648
2649         if (section_prev) {
2650                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->note_types_per_minute(), pulse));
2651                 section->set_minute (section_prev->minute_at_ntpm (section->note_types_per_minute(), pulse));
2652         }
2653
2654 #if (0)
2655         recompute_tempi (imaginary);
2656
2657         if (check_solved (imaginary)) {
2658                 return true;
2659         } else {
2660                 dunp (imaginary, std::cout);
2661         }
2662 #endif
2663
2664         MetricSectionSorter cmp;
2665         imaginary.sort (cmp);
2666
2667         recompute_tempi (imaginary);
2668         /* Reordering
2669          * XX need a restriction here, but only for this case,
2670          * as audio locked tempos don't interact in the same way.
2671          *
2672          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2673          * e.g.
2674          * |50 bpm                        |250 bpm |60 bpm
2675          *                drag 250 to the pulse after 60->
2676          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2677          */
2678         if (check_solved (imaginary)) {
2679                 return true;
2680         }
2681
2682         return false;
2683 }
2684
2685 bool
2686 TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const double& minute)
2687 {
2688         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2689         const MeterSection* other =  &meter_section_at_minute_locked (imaginary, minute);
2690         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->minute() >= minute)) {
2691                 return false;
2692         }
2693
2694         if (!section->movable()) {
2695                 /* lock the first tempo to our first meter */
2696                 if (!set_active_tempos (imaginary, section->frame_at_minute (minute))) {
2697                         return false;
2698                 }
2699         }
2700
2701         TempoSection* meter_locked_tempo = 0;
2702
2703         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2704                 TempoSection* t;
2705                 if ((*ii)->is_tempo()) {
2706                         t = static_cast<TempoSection*> (*ii);
2707                         if ((t->locked_to_meter() || !t->movable()) && t->minute() == section->minute()) {
2708                                 meter_locked_tempo = t;
2709                                 break;
2710                         }
2711                 }
2712         }
2713
2714         if (!meter_locked_tempo) {
2715                 return false;
2716         }
2717
2718         MeterSection* prev_m = 0;
2719         Metrics future_map;
2720         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2721         bool solved = false;
2722
2723         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2724                 MeterSection* m;
2725                 if (!(*i)->is_tempo()) {
2726                         m = static_cast<MeterSection*> (*i);
2727                         if (m == section){
2728                                 if (prev_m && section->movable()) {
2729                                         const double beats = (pulse_at_minute_locked (imaginary, minute) - prev_m->pulse()) * prev_m->note_divisor();
2730                                         if (beats + prev_m->beat() < section->beat()) {
2731                                                 /* set the section pulse according to its musical position,
2732                                                  * as an earlier time than this has been requested.
2733                                                 */
2734                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2735                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2736
2737                                                 tempo_copy->set_position_lock_style (MusicTime);
2738                                                 if ((solved = solve_map_pulse (future_map, tempo_copy, new_pulse))) {
2739                                                         meter_locked_tempo->set_position_lock_style (MusicTime);
2740                                                         section->set_position_lock_style (MusicTime);
2741                                                         section->set_pulse (new_pulse);
2742                                                         solve_map_pulse (imaginary, meter_locked_tempo, new_pulse);
2743                                                         meter_locked_tempo->set_position_lock_style (AudioTime);
2744                                                         section->set_position_lock_style (AudioTime);
2745                                                         section->set_minute (meter_locked_tempo->minute());
2746
2747                                                 } else {
2748                                                         solved = false;
2749                                                 }
2750
2751                                                 Metrics::const_iterator d = future_map.begin();
2752                                                 while (d != future_map.end()) {
2753                                                         delete (*d);
2754                                                         ++d;
2755                                                 }
2756
2757                                                 if (!solved) {
2758                                                         return false;
2759                                                 }
2760                                         } else {
2761                                                 /* all is ok. set section's locked tempo if allowed.
2762                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2763                                                    XX this check could possibly go. its never actually happened here.
2764                                                 */
2765                                                 MeterSection* meter_copy = const_cast<MeterSection*>
2766                                                         (&meter_section_at_minute_locked (future_map, section->minute()));
2767
2768                                                 meter_copy->set_minute (minute);
2769
2770                                                 if ((solved = solve_map_minute (future_map, tempo_copy, minute))) {
2771                                                         section->set_minute (minute);
2772                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2773                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2774                                                         solve_map_minute (imaginary, meter_locked_tempo, minute);
2775                                                 } else {
2776                                                         solved = false;
2777                                                 }
2778
2779                                                 Metrics::const_iterator d = future_map.begin();
2780                                                 while (d != future_map.end()) {
2781                                                         delete (*d);
2782                                                         ++d;
2783                                                 }
2784
2785                                                 if (!solved) {
2786                                                         return false;
2787                                                 }
2788                                         }
2789                                 } else {
2790                                         /* not movable (first meter atm) */
2791
2792                                         tempo_copy->set_minute (minute);
2793                                         tempo_copy->set_pulse (0.0);
2794
2795                                         if ((solved = solve_map_minute (future_map, tempo_copy, minute))) {
2796                                                 section->set_minute (minute);
2797                                                 meter_locked_tempo->set_minute (minute);
2798                                                 meter_locked_tempo->set_pulse (0.0);
2799                                                 solve_map_minute (imaginary, meter_locked_tempo, minute);
2800                                         } else {
2801                                                 solved = false;
2802                                         }
2803
2804                                         Metrics::const_iterator d = future_map.begin();
2805                                         while (d != future_map.end()) {
2806                                                 delete (*d);
2807                                                 ++d;
2808                                         }
2809
2810                                         if (!solved) {
2811                                                 return false;
2812                                         }
2813
2814                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2815                                         section->set_beat (b_bbt);
2816                                         section->set_pulse (0.0);
2817
2818                                 }
2819                                 break;
2820                         }
2821
2822                         prev_m = m;
2823                 }
2824         }
2825
2826         MetricSectionFrameSorter fcmp;
2827         imaginary.sort (fcmp);
2828
2829         recompute_meters (imaginary);
2830
2831         return true;
2832 }
2833
2834 bool
2835 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2836 {
2837         /* disallow setting section to an existing meter's bbt */
2838         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2839                 MeterSection* m;
2840                 if (!(*i)->is_tempo()) {
2841                         m = static_cast<MeterSection*> (*i);
2842                         if (m != section && m->bbt().bars == when.bars) {
2843                                 return false;
2844                         }
2845                 }
2846         }
2847
2848         MeterSection* prev_m = 0;
2849         MeterSection* section_prev = 0;
2850
2851         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2852                 MeterSection* m;
2853                 if (!(*i)->is_tempo()) {
2854                         m = static_cast<MeterSection*> (*i);
2855                         pair<double, BBT_Time> b_bbt;
2856                         double new_pulse = 0.0;
2857
2858                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2859                                 section_prev = prev_m;
2860                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2861                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2862                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2863
2864                                 section->set_beat (b_bbt);
2865                                 section->set_pulse (pulse);
2866                                 section->set_minute (minute_at_pulse_locked (imaginary, pulse));
2867                                 prev_m = section;
2868                                 continue;
2869                         }
2870
2871                         if (m->position_lock_style() == AudioTime) {
2872                                 TempoSection* meter_locked_tempo = 0;
2873
2874                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2875                                         TempoSection* t;
2876                                         if ((*ii)->is_tempo()) {
2877                                                 t = static_cast<TempoSection*> (*ii);
2878                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2879                                                         meter_locked_tempo = t;
2880                                                         break;
2881                                                 }
2882                                         }
2883                                 }
2884
2885                                 if (!meter_locked_tempo) {
2886                                         return false;
2887                                 }
2888
2889                                 if (prev_m) {
2890                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2891
2892                                         if (beats + prev_m->beat() != m->beat()) {
2893                                                 /* tempo/ meter change caused a change in beat (bar). */
2894                                                 b_bbt = make_pair (beats + prev_m->beat()
2895                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2896                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2897                                         } else if (m->movable()) {
2898                                                 b_bbt = make_pair (m->beat(), m->bbt());
2899                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2900                                         }
2901                                 } else {
2902                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2903                                 }
2904
2905                                 meter_locked_tempo->set_pulse (new_pulse);
2906                                 m->set_beat (b_bbt);
2907                                 m->set_pulse (new_pulse);
2908
2909                         } else {
2910                                 /* MusicTime */
2911                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2912                                 if (beats + prev_m->beat() != m->beat()) {
2913                                         /* tempo/ meter change caused a change in beat (bar). */
2914                                         b_bbt = make_pair (beats + prev_m->beat()
2915                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2916                                 } else {
2917                                         b_bbt = make_pair (beats + prev_m->beat()
2918                                                            , m->bbt());
2919                                 }
2920                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2921                                 m->set_beat (b_bbt);
2922                                 m->set_pulse (new_pulse);
2923                                 m->set_minute (minute_at_pulse_locked (imaginary, new_pulse));
2924                         }
2925
2926                         prev_m = m;
2927                 }
2928         }
2929
2930         if (!section_prev) {
2931
2932                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2933                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2934                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2935
2936                 section->set_beat (b_bbt);
2937                 section->set_pulse (pulse);
2938                 section->set_minute (minute_at_pulse_locked (imaginary, pulse));
2939         }
2940
2941         MetricSectionSorter cmp;
2942         imaginary.sort (cmp);
2943
2944         recompute_meters (imaginary);
2945
2946         return true;
2947 }
2948
2949 /** places a copy of _metrics into copy and returns a pointer
2950  *  to section's equivalent in copy.
2951  */
2952 TempoSection*
2953 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2954 {
2955         TempoSection* ret = 0;
2956
2957         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2958                 TempoSection* t;
2959                 MeterSection* m;
2960                 if ((*i)->is_tempo()) {
2961                         t = static_cast<TempoSection*> (*i);
2962                         if (t == section) {
2963                                 ret = new TempoSection (*t);
2964                                 copy.push_back (ret);
2965                                 continue;
2966                         }
2967
2968                         TempoSection* cp = new TempoSection (*t);
2969                         copy.push_back (cp);
2970                 }
2971                 if (!(*i)->is_tempo()) {
2972                         m = static_cast<MeterSection *> (*i);
2973                         MeterSection* cp = new MeterSection (*m);
2974                         copy.push_back (cp);
2975                 }
2976         }
2977
2978         return ret;
2979 }
2980
2981 MeterSection*
2982 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2983 {
2984         MeterSection* ret = 0;
2985
2986         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2987                 TempoSection* t;
2988                 MeterSection* m;
2989                 if ((*i)->is_tempo()) {
2990                         t = static_cast<TempoSection*> (*i);
2991                         TempoSection* cp = new TempoSection (*t);
2992                         copy.push_back (cp);
2993                 }
2994
2995                 if (!(*i)->is_tempo()) {
2996                         m = static_cast<MeterSection *> (*i);
2997                         if (m == section) {
2998                                 ret = new MeterSection (*m);
2999                                 copy.push_back (ret);
3000                                 continue;
3001                         }
3002                         MeterSection* cp = new MeterSection (*m);
3003                         copy.push_back (cp);
3004                 }
3005         }
3006
3007         return ret;
3008 }
3009
3010 /** answers the question "is this a valid beat position for this tempo section?".
3011  *  it returns true if the tempo section can be moved to the requested bbt position,
3012  *  leaving the tempo map in a solved state.
3013  * @param ts the tempo section to be moved
3014  * @param bbt the requested new position for the tempo section
3015  * @return true if the tempo section can be moved to the position, otherwise false.
3016  */
3017 bool
3018 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
3019 {
3020         Metrics copy;
3021         TempoSection* tempo_copy = 0;
3022
3023         {
3024                 Glib::Threads::RWLock::ReaderLock lm (lock);
3025                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
3026                 if (!tempo_copy) {
3027                         return false;
3028                 }
3029         }
3030
3031         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
3032
3033         Metrics::const_iterator d = copy.begin();
3034         while (d != copy.end()) {
3035                 delete (*d);
3036                 ++d;
3037         }
3038
3039         return ret;
3040 }
3041
3042 /**
3043 * 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,
3044 * taking any possible reordering as a consequence of this into account.
3045 * @param section - the section to be altered
3046 * @param bbt - the BBT time  where the altered tempo will fall
3047 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
3048 */
3049 pair<double, framepos_t>
3050 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
3051 {
3052         Metrics future_map;
3053         pair<double, framepos_t> ret = make_pair (0.0, 0);
3054
3055         Glib::Threads::RWLock::ReaderLock lm (lock);
3056
3057         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
3058
3059         const double beat = beat_at_bbt_locked (future_map, bbt);
3060
3061         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
3062                 ret.first = tempo_copy->pulse();
3063                 ret.second = tempo_copy->frame();
3064         } else {
3065                 ret.first = section->pulse();
3066                 ret.second = section->frame();
3067         }
3068
3069         Metrics::const_iterator d = future_map.begin();
3070         while (d != future_map.end()) {
3071                 delete (*d);
3072                 ++d;
3073         }
3074         return ret;
3075 }
3076
3077 /** moves a TempoSection to a specified position.
3078  * @param ts - the section to be moved
3079  * @param frame - the new position in frames for the tempo
3080  * @param sub_num - the snap division to use if using musical time.
3081  *
3082  * if sub_num is non-zero, the frame position is used to calculate an exact
3083  * musical position.
3084  * sub_num   | effect
3085  * -1        | snap to bars (meter-based)
3086  *  0        | no snap - use audio frame for musical position
3087  *  1        | snap to meter-based (BBT) beat
3088  * >1        | snap to quarter-note subdivision (i.e. 4 will snap to sixteenth notes)
3089  *
3090  * this follows the snap convention in the gui.
3091  * if sub_num is zero, the musical position will be taken from the supplied frame.
3092  */
3093 void
3094 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame, const int& sub_num)
3095 {
3096         Metrics future_map;
3097
3098         if (ts->position_lock_style() == MusicTime) {
3099                 {
3100                         /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
3101                         Glib::Threads::RWLock::WriterLock lm (lock);
3102                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3103
3104                         tempo_copy->set_position_lock_style (AudioTime);
3105
3106                         if (solve_map_minute (future_map, tempo_copy, minute_at_frame (frame))) {
3107                                 const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
3108                                 const double pulse = pulse_at_beat_locked (future_map, beat);
3109
3110                                 if (solve_map_pulse (future_map, tempo_copy, pulse)) {
3111                                         solve_map_pulse (_metrics, ts, pulse);
3112                                         recompute_meters (_metrics);
3113                                 }
3114                         }
3115                 }
3116
3117         } else {
3118
3119                 {
3120                         Glib::Threads::RWLock::WriterLock lm (lock);
3121                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3122
3123                         if (solve_map_minute (future_map, tempo_copy, minute_at_frame (frame))) {
3124                                 if (sub_num != 0) {
3125                                         /* We're moving the object that defines the grid while snapping to it...
3126                                          * Placing the ts at the beat corresponding to the requested frame may shift the
3127                                          * grid in such a way that the mouse is left hovering over a completerly different division,
3128                                          * causing jittering when the mouse next moves (esp. large tempo deltas).
3129                                          * To avoid this, place the ts at the requested frame in a dummy map
3130                                          * then find the closest beat subdivision to that frame in the dummy.
3131                                          * This alters the snap behaviour slightly in that we snap to beat divisions
3132                                          * in the future map rather than the existing one.
3133                                          */
3134                                         const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
3135                                         const double pulse = pulse_at_beat_locked (future_map, beat);
3136
3137                                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
3138                                                 /* snapping to a grid. force MusicTime temporarily. */
3139                                                 ts->set_position_lock_style (MusicTime);
3140                                                 solve_map_pulse (_metrics, ts, pulse);
3141                                                 ts->set_position_lock_style (AudioTime);
3142
3143                                                 recompute_meters (_metrics);
3144                                         }
3145                                 } else {
3146                                         solve_map_minute (_metrics, ts, minute_at_frame (frame));
3147                                         recompute_meters (_metrics);
3148                                 }
3149                         }
3150                 }
3151         }
3152
3153         Metrics::const_iterator d = future_map.begin();
3154         while (d != future_map.end()) {
3155                 delete (*d);
3156                 ++d;
3157         }
3158
3159         MetricPositionChanged (); // Emit Signal
3160 }
3161
3162 /** moves a MeterSection to a specified position.
3163  * @param ms - the section to be moved
3164  * @param frame - the new position in frames for the meter
3165  *
3166  * as a meter cannot snap to anything but bars,
3167  * the supplied frame is rounded to the nearest bar, possibly
3168  * leaving the meter position unchanged.
3169  */
3170 void
3171 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
3172 {
3173         Metrics future_map;
3174
3175         if (ms->position_lock_style() == AudioTime) {
3176
3177                 {
3178                         Glib::Threads::RWLock::WriterLock lm (lock);
3179                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
3180
3181                         if (solve_map_minute (future_map, copy, minute_at_frame (frame))) {
3182                                 solve_map_minute (_metrics, ms, minute_at_frame (frame));
3183                                 recompute_tempi (_metrics);
3184                         }
3185                 }
3186         } else {
3187                 {
3188                         Glib::Threads::RWLock::WriterLock lm (lock);
3189                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
3190
3191                         const double beat = beat_at_minute_locked (_metrics, minute_at_frame (frame));
3192                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
3193
3194                         if (solve_map_bbt (future_map, copy, bbt)) {
3195                                 solve_map_bbt (_metrics, ms, bbt);
3196                                 recompute_tempi (_metrics);
3197                         }
3198                 }
3199         }
3200
3201         Metrics::const_iterator d = future_map.begin();
3202         while (d != future_map.end()) {
3203                 delete (*d);
3204                 ++d;
3205         }
3206
3207         MetricPositionChanged (); // Emit Signal
3208 }
3209
3210 bool
3211 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
3212 {
3213         Metrics future_map;
3214         bool can_solve = false;
3215         {
3216                 Glib::Threads::RWLock::WriterLock lm (lock);
3217                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3218                 tempo_copy->set_note_types_per_minute (bpm.note_types_per_minute());
3219                 recompute_tempi (future_map);
3220
3221                 if (check_solved (future_map)) {
3222                         ts->set_note_types_per_minute (bpm.note_types_per_minute());
3223                         recompute_map (_metrics);
3224                         can_solve = true;
3225                 }
3226         }
3227
3228         Metrics::const_iterator d = future_map.begin();
3229         while (d != future_map.end()) {
3230                 delete (*d);
3231                 ++d;
3232         }
3233         if (can_solve) {
3234                 MetricPositionChanged (); // Emit Signal
3235         }
3236         return can_solve;
3237 }
3238
3239 void
3240 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame)
3241 {
3242         /*
3243           Ts (future prev_t)   Tnext
3244           |                    |
3245           |     [drag^]        |
3246           |----------|----------
3247                 e_f  qn_beats(frame)
3248         */
3249
3250         Metrics future_map;
3251
3252         {
3253                 Glib::Threads::RWLock::WriterLock lm (lock);
3254
3255                 if (!ts) {
3256                         return;
3257                 }
3258
3259                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
3260                 TempoSection* prev_to_prev_t = 0;
3261                 const frameoffset_t fr_off = end_frame - frame;
3262
3263                 assert (prev_t);
3264
3265                 if (prev_t->pulse() > 0.0) {
3266                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_minute_locked (future_map, minute_at_frame (prev_t->frame() - 1)));
3267                 }
3268
3269                 TempoSection* next_t = 0;
3270                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
3271                         TempoSection* t = 0;
3272                         if ((*i)->is_tempo()) {
3273                                 t = static_cast<TempoSection*> (*i);
3274                                 if (t->frame() > ts->frame()) {
3275                                         next_t = t;
3276                                         break;
3277                                 }
3278                         }
3279                 }
3280                 /* minimum allowed measurement distance in frames */
3281                 const framepos_t min_dframe = 2;
3282
3283                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
3284                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
3285                 */
3286                 double contribution = 0.0;
3287
3288                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3289                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
3290                 }
3291
3292                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
3293
3294                 const double start_pulse = prev_t->pulse_at_minute (minute_at_frame (frame));
3295                 const double end_pulse = prev_t->pulse_at_minute (minute_at_frame (end_frame));
3296
3297                 double new_bpm;
3298
3299                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
3300
3301                         if (prev_t->position_lock_style() == MusicTime) {
3302                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3303                                         if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
3304
3305                                                 new_bpm = prev_t->note_types_per_minute() * ((frame - prev_to_prev_t->frame())
3306                                                                                         / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
3307                                         } else {
3308                                                 new_bpm = prev_t->note_types_per_minute();
3309                                         }
3310                                 } else {
3311                                         /* prev to prev is irrelevant */
3312
3313                                         if (start_pulse > prev_t->pulse() && end_pulse > prev_t->pulse()) {
3314                                                 new_bpm = prev_t->note_types_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
3315                                         } else {
3316                                                 new_bpm = prev_t->note_types_per_minute();
3317                                         }
3318                                 }
3319                         } else {
3320                                 /* AudioTime */
3321                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3322                                         if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
3323
3324                                                 new_bpm = prev_t->note_types_per_minute() * ((frame - prev_to_prev_t->frame())
3325                                                                                         / (double) ((end_frame) - prev_to_prev_t->frame()));
3326                                         } else {
3327                                                 new_bpm = prev_t->note_types_per_minute();
3328                                         }
3329                                 } else {
3330                                         /* prev_to_prev_t is irrelevant */
3331
3332                                         if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
3333                                                 new_bpm = prev_t->note_types_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
3334                                         } else {
3335                                                 new_bpm = prev_t->note_types_per_minute();
3336                                         }
3337                                 }
3338                         }
3339                 } else {
3340
3341                         double frame_ratio = 1.0;
3342                         double pulse_ratio = 1.0;
3343                         const double pulse_pos = frame;
3344
3345                         if (prev_to_prev_t) {
3346                                 if (pulse_pos > prev_to_prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_to_prev_t->frame() + min_dframe) {
3347                                         frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
3348                                 }
3349                                 if (end_pulse > prev_to_prev_t->pulse() && start_pulse > prev_to_prev_t->pulse()) {
3350                                         pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
3351                                 }
3352                         } else {
3353                                 if (pulse_pos > prev_t->frame() + min_dframe && (pulse_pos - fr_off) > prev_t->frame() + min_dframe) {
3354                                         frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
3355                                 }
3356                                 pulse_ratio = (start_pulse / end_pulse);
3357                         }
3358                         new_bpm = prev_t->note_types_per_minute() * (pulse_ratio * frame_ratio);
3359                 }
3360
3361                 /* don't clamp and proceed here.
3362                    testing has revealed that this can go negative,
3363                    which is an entirely different thing to just being too low.
3364                 */
3365                 if (new_bpm < 0.5) {
3366                         return;
3367                 }
3368                 new_bpm = min (new_bpm, (double) 1000.0);
3369                 prev_t->set_note_types_per_minute (new_bpm);
3370                 recompute_tempi (future_map);
3371                 recompute_meters (future_map);
3372
3373                 if (check_solved (future_map)) {
3374                         ts->set_note_types_per_minute (new_bpm);
3375                         recompute_tempi (_metrics);
3376                         recompute_meters (_metrics);
3377                 }
3378         }
3379
3380         Metrics::const_iterator d = future_map.begin();
3381         while (d != future_map.end()) {
3382                 delete (*d);
3383                 ++d;
3384         }
3385
3386         MetricPositionChanged (); // Emit Signal
3387 }
3388
3389 /** Returns the exact bbt-based beat corresponding to the bar, beat or quarter note subdivision nearest to
3390  * the supplied frame, possibly returning a negative value.
3391  *
3392  * @param frame  The session frame position.
3393  * @param sub_num The subdivision to use when rounding the beat.
3394  *                A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3395  *                Positive integers indicate quarter note (non BBT) divisions.
3396  *                0 indicates that the returned beat should not be rounded (equivalent to quarter_note_at_frame()).
3397  * @return The beat position of the supplied frame.
3398  *
3399  * when working to a musical grid, the use of sub_nom indicates that
3400  * the position should be interpreted musically.
3401  *
3402  * it effectively snaps to meter bars, meter beats or quarter note divisions
3403  * (as per current gui convention) and returns a musical position independent of frame rate.
3404  *
3405  * If the supplied frame lies before the first meter, the return will be negative,
3406  * in which case the returned beat uses the first meter (for BBT subdivisions) and
3407  * the continuation of the tempo curve (backwards).
3408  *
3409  * This function is sensitive to tempo and meter.
3410  */
3411 double
3412 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num)
3413 {
3414         Glib::Threads::RWLock::ReaderLock lm (lock);
3415
3416         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
3417 }
3418
3419 double
3420 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions)
3421 {
3422         return beat_at_pulse_locked (_metrics, exact_qn_at_frame_locked (metrics, frame, divisions) / 4.0);
3423 }
3424
3425 /** Returns the exact quarter note corresponding to the bar, beat or quarter note subdivision nearest to
3426  * the supplied frame, possibly returning a negative value.
3427  *
3428  * @param frame  The session frame position.
3429  * @param sub_num The subdivision to use when rounding the quarter note.
3430  *                A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3431  *                Positive integers indicate quarter note (non BBT) divisions.
3432  *                0 indicates that the returned quarter note should not be rounded (equivalent to quarter_note_at_frame()).
3433  * @return The quarter note position of the supplied frame.
3434  *
3435  * When working to a musical grid, the use of sub_nom indicates that
3436  * the frame position should be interpreted musically.
3437  *
3438  * it effectively snaps to meter bars, meter beats or quarter note divisions
3439  * (as per current gui convention) and returns a musical position independent of frame rate.
3440  *
3441  * If the supplied frame lies before the first meter, the return will be negative,
3442  * in which case the returned quarter note uses the first meter (for BBT subdivisions) and
3443  * the continuation of the tempo curve (backwards).
3444  *
3445  * This function is tempo-sensitive.
3446  */
3447 double
3448 TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num)
3449 {
3450         Glib::Threads::RWLock::ReaderLock lm (lock);
3451
3452         return exact_qn_at_frame_locked (_metrics, frame, sub_num);
3453 }
3454
3455 double
3456 TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num)
3457 {
3458         double qn = quarter_note_at_minute_locked (metrics, minute_at_frame (frame));
3459
3460         if (sub_num > 1) {
3461                 qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
3462         } else if (sub_num == 1) {
3463                 /* the gui requested exact musical (BBT) beat */
3464                 qn = quarter_note_at_beat_locked (metrics, floor (beat_at_minute_locked (metrics, minute_at_frame (frame)) + 0.5));
3465         } else if (sub_num == -1) {
3466                 /* snap to  bar */
3467                 Timecode::BBT_Time bbt = bbt_at_pulse_locked (metrics, qn / 4.0);
3468                 bbt.beats = 1;
3469                 bbt.ticks = 0;
3470
3471                 const double prev_b = pulse_at_bbt_locked (metrics, bbt) * 4.0;
3472                 ++bbt.bars;
3473                 const double next_b = pulse_at_bbt_locked (metrics, bbt) * 4.0;
3474
3475                 if ((qn - prev_b) > (next_b - prev_b) / 2.0) {
3476                         qn = next_b;
3477                 } else {
3478                         qn = prev_b;
3479                 }
3480         }
3481
3482         return qn;
3483 }
3484
3485 /** returns the frame duration of the supplied BBT time at a specified frame position in the tempo map.
3486  * @param pos the frame position in the tempo map.
3487  * @param bbt the distance in BBT time from pos to calculate.
3488  * @param dir the rounding direction..
3489  * @return the duration in frames between pos and bbt
3490 */
3491 framecnt_t
3492 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
3493 {
3494         Glib::Threads::RWLock::ReaderLock lm (lock);
3495
3496         BBT_Time pos_bbt = bbt_at_minute_locked (_metrics, minute_at_frame (pos));
3497
3498         const double divisions = meter_section_at_minute_locked (_metrics, minute_at_frame (pos)).divisions_per_bar();
3499
3500         if (dir > 0) {
3501                 pos_bbt.bars += bbt.bars;
3502
3503                 pos_bbt.ticks += bbt.ticks;
3504                 if ((double) pos_bbt.ticks > BBT_Time::ticks_per_beat) {
3505                         pos_bbt.beats += 1;
3506                         pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3507                 }
3508
3509                 pos_bbt.beats += bbt.beats;
3510                 if ((double) pos_bbt.beats > divisions) {
3511                         pos_bbt.bars += 1;
3512                         pos_bbt.beats -= divisions;
3513                 }
3514                 const framecnt_t pos_bbt_frame = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
3515
3516                 return pos_bbt_frame - pos;
3517
3518         } else {
3519
3520                 if (pos_bbt.bars <= bbt.bars) {
3521                         pos_bbt.bars = 1;
3522                 } else {
3523                         pos_bbt.bars -= bbt.bars;
3524                 }
3525
3526                 if (pos_bbt.ticks < bbt.ticks) {
3527                         if (pos_bbt.bars > 1) {
3528                                 if (pos_bbt.beats == 1) {
3529                                         pos_bbt.bars--;
3530                                         pos_bbt.beats = divisions;
3531                                 } else {
3532                                         pos_bbt.beats--;
3533                                 }
3534                                 pos_bbt.ticks = BBT_Time::ticks_per_beat - (bbt.ticks - pos_bbt.ticks);
3535                         } else {
3536                                 pos_bbt.beats = 1;
3537                                 pos_bbt.ticks = 0;
3538                         }
3539                 } else {
3540                         pos_bbt.ticks -= bbt.ticks;
3541                 }
3542
3543                 if (pos_bbt.beats <= bbt.beats) {
3544                         if (pos_bbt.bars > 1) {
3545                                 pos_bbt.bars--;
3546                                 pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
3547                         } else {
3548                                 pos_bbt.beats = 1;
3549                         }
3550                 } else {
3551                         pos_bbt.beats -= bbt.beats;
3552                 }
3553
3554                 return pos - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
3555         }
3556
3557         return 0;
3558 }
3559
3560 framepos_t
3561 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
3562 {
3563         return round_to_type (fr, dir, Bar);
3564 }
3565
3566 framepos_t
3567 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
3568 {
3569         return round_to_type (fr, dir, Beat);
3570 }
3571
3572 framepos_t
3573 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3574 {
3575         Glib::Threads::RWLock::ReaderLock lm (lock);
3576         uint32_t ticks = (uint32_t) floor (max (0.0, beat_at_minute_locked (_metrics, minute_at_frame (fr))) * BBT_Time::ticks_per_beat);
3577         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3578         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3579
3580         ticks -= beats * BBT_Time::ticks_per_beat;
3581
3582         if (dir > 0) {
3583                 /* round to next (or same iff dir == RoundUpMaybe) */
3584
3585                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3586
3587                 if (mod == 0 && dir == RoundUpMaybe) {
3588                         /* right on the subdivision, which is fine, so do nothing */
3589
3590                 } else if (mod == 0) {
3591                         /* right on the subdivision, so the difference is just the subdivision ticks */
3592                         ticks += ticks_one_subdivisions_worth;
3593
3594                 } else {
3595                         /* not on subdivision, compute distance to next subdivision */
3596
3597                         ticks += ticks_one_subdivisions_worth - mod;
3598                 }
3599
3600                 if (ticks >= BBT_Time::ticks_per_beat) {
3601                         ticks -= BBT_Time::ticks_per_beat;
3602                 }
3603         } else if (dir < 0) {
3604
3605                 /* round to previous (or same iff dir == RoundDownMaybe) */
3606
3607                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3608
3609                 if (difference == 0 && dir == RoundDownAlways) {
3610                         /* right on the subdivision, but force-rounding down,
3611                            so the difference is just the subdivision ticks */
3612                         difference = ticks_one_subdivisions_worth;
3613                 }
3614
3615                 if (ticks < difference) {
3616                         ticks = BBT_Time::ticks_per_beat - ticks;
3617                 } else {
3618                         ticks -= difference;
3619                 }
3620
3621         } else {
3622                 /* round to nearest */
3623                 double rem;
3624
3625                 /* compute the distance to the previous and next subdivision */
3626
3627                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3628
3629                         /* closer to the next subdivision, so shift forward */
3630
3631                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3632
3633                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3634
3635                         if (ticks > BBT_Time::ticks_per_beat) {
3636                                 ++beats;
3637                                 ticks -= BBT_Time::ticks_per_beat;
3638                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3639                         }
3640
3641                 } else if (rem > 0) {
3642
3643                         /* closer to previous subdivision, so shift backward */
3644
3645                         if (rem > ticks) {
3646                                 if (beats == 0) {
3647                                         /* can't go backwards past zero, so ... */
3648                                         return 0;
3649                                 }
3650                                 /* step back to previous beat */
3651                                 --beats;
3652                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3653                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3654                         } else {
3655                                 ticks = lrint (ticks - rem);
3656                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3657                         }
3658                 } else {
3659                         /* on the subdivision, do nothing */
3660                 }
3661         }
3662
3663         const framepos_t ret_frame = frame_at_minute (minute_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat)));
3664
3665         return ret_frame;
3666 }
3667
3668 framepos_t
3669 TempoMap::round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3670 {
3671         Glib::Threads::RWLock::ReaderLock lm (lock);
3672         uint32_t ticks = (uint32_t) floor (max (0.0, quarter_note_at_minute_locked (_metrics, minute_at_frame (fr))) * BBT_Time::ticks_per_beat);
3673         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3674         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3675
3676         ticks -= beats * BBT_Time::ticks_per_beat;
3677
3678         if (dir > 0) {
3679                 /* round to next (or same iff dir == RoundUpMaybe) */
3680
3681                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3682
3683                 if (mod == 0 && dir == RoundUpMaybe) {
3684                         /* right on the subdivision, which is fine, so do nothing */
3685
3686                 } else if (mod == 0) {
3687                         /* right on the subdivision, so the difference is just the subdivision ticks */
3688                         ticks += ticks_one_subdivisions_worth;
3689
3690                 } else {
3691                         /* not on subdivision, compute distance to next subdivision */
3692
3693                         ticks += ticks_one_subdivisions_worth - mod;
3694                 }
3695
3696                 if (ticks >= BBT_Time::ticks_per_beat) {
3697                         ticks -= BBT_Time::ticks_per_beat;
3698                 }
3699         } else if (dir < 0) {
3700
3701                 /* round to previous (or same iff dir == RoundDownMaybe) */
3702
3703                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
3704
3705                 if (difference == 0 && dir == RoundDownAlways) {
3706                         /* right on the subdivision, but force-rounding down,
3707                            so the difference is just the subdivision ticks */
3708                         difference = ticks_one_subdivisions_worth;
3709                 }
3710
3711                 if (ticks < difference) {
3712                         ticks = BBT_Time::ticks_per_beat - ticks;
3713                 } else {
3714                         ticks -= difference;
3715                 }
3716
3717         } else {
3718                 /* round to nearest */
3719                 double rem;
3720
3721                 /* compute the distance to the previous and next subdivision */
3722
3723                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
3724
3725                         /* closer to the next subdivision, so shift forward */
3726
3727                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
3728
3729                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
3730
3731                         if (ticks > BBT_Time::ticks_per_beat) {
3732                                 ++beats;
3733                                 ticks -= BBT_Time::ticks_per_beat;
3734                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
3735                         }
3736
3737                 } else if (rem > 0) {
3738
3739                         /* closer to previous subdivision, so shift backward */
3740
3741                         if (rem > ticks) {
3742                                 if (beats == 0) {
3743                                         /* can't go backwards past zero, so ... */
3744                                         return 0;
3745                                 }
3746                                 /* step back to previous beat */
3747                                 --beats;
3748                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
3749                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
3750                         } else {
3751                                 ticks = lrint (ticks - rem);
3752                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
3753                         }
3754                 } else {
3755                         /* on the subdivision, do nothing */
3756                 }
3757         }
3758
3759         const framepos_t ret_frame = frame_at_minute (minute_at_quarter_note_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat)));
3760
3761         return ret_frame;
3762 }
3763
3764 framepos_t
3765 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
3766 {
3767         Glib::Threads::RWLock::ReaderLock lm (lock);
3768
3769         const double beat_at_framepos = max (0.0, beat_at_minute_locked (_metrics, minute_at_frame (frame)));
3770         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
3771
3772         switch (type) {
3773         case Bar:
3774                 if (dir < 0) {
3775                         /* find bar previous to 'frame' */
3776                         bbt.beats = 1;
3777                         bbt.ticks = 0;
3778                         return frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
3779
3780                 } else if (dir > 0) {
3781                         /* find bar following 'frame' */
3782                         ++bbt.bars;
3783                         bbt.beats = 1;
3784                         bbt.ticks = 0;
3785                         return frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
3786                 } else {
3787                         /* true rounding: find nearest bar */
3788                         framepos_t raw_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
3789                         bbt.beats = 1;
3790                         bbt.ticks = 0;
3791                         framepos_t prev_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
3792                         ++bbt.bars;
3793                         framepos_t next_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
3794
3795                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
3796                                 return next_ft;
3797                         } else {
3798                                 return prev_ft;
3799                         }
3800                 }
3801
3802                 break;
3803
3804         case Beat:
3805                 if (dir < 0) {
3806                         return frame_at_minute (minute_at_beat_locked (_metrics, floor (beat_at_framepos)));
3807                 } else if (dir > 0) {
3808                         return frame_at_minute (minute_at_beat_locked (_metrics, ceil (beat_at_framepos)));
3809                 } else {
3810                         return frame_at_minute (minute_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5)));
3811                 }
3812                 break;
3813         }
3814
3815         return 0;
3816 }
3817
3818 void
3819 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
3820                     framepos_t lower, framepos_t upper, uint32_t bar_mod)
3821 {
3822         Glib::Threads::RWLock::ReaderLock lm (lock);
3823         int32_t cnt = ceil (beat_at_minute_locked (_metrics, minute_at_frame (lower)));
3824         framecnt_t pos = 0;
3825         /* although the map handles negative beats, bbt doesn't. */
3826         if (cnt < 0.0) {
3827                 cnt = 0.0;
3828         }
3829
3830         if (minute_at_beat_locked (_metrics, cnt) >= minute_at_frame (upper)) {
3831                 return;
3832         }
3833         if (bar_mod == 0) {
3834                 while (pos >= 0 && pos < upper) {
3835                         pos = frame_at_minute (minute_at_beat_locked (_metrics, cnt));
3836                         const TempoSection tempo = tempo_section_at_minute_locked (_metrics, minute_at_frame (pos));
3837                         const MeterSection meter = meter_section_at_minute_locked (_metrics, minute_at_frame (pos));
3838                         const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
3839                         points.push_back (BBTPoint (meter, tempo_at_minute_locked (_metrics, minute_at_frame (pos)), pos, bbt.bars, bbt.beats, tempo.c_func()));
3840                         ++cnt;
3841                 }
3842         } else {
3843                 BBT_Time bbt = bbt_at_minute_locked (_metrics, minute_at_frame (lower));
3844                 bbt.beats = 1;
3845                 bbt.ticks = 0;
3846
3847                 if (bar_mod != 1) {
3848                         bbt.bars -= bbt.bars % bar_mod;
3849                         ++bbt.bars;
3850                 }
3851
3852                 while (pos >= 0 && pos < upper) {
3853                         pos = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
3854                         const TempoSection tempo = tempo_section_at_minute_locked (_metrics, minute_at_frame (pos));
3855                         const MeterSection meter = meter_section_at_minute_locked (_metrics, minute_at_frame (pos));
3856                         points.push_back (BBTPoint (meter, tempo_at_minute_locked (_metrics, minute_at_frame (pos)), pos, bbt.bars, bbt.beats, tempo.c_func()));
3857                         bbt.bars += bar_mod;
3858                 }
3859         }
3860 }
3861
3862 const TempoSection&
3863 TempoMap::tempo_section_at_frame (framepos_t frame) const
3864 {
3865         Glib::Threads::RWLock::ReaderLock lm (lock);
3866
3867         return tempo_section_at_minute_locked (_metrics, minute_at_frame (frame));
3868 }
3869
3870 const TempoSection&
3871 TempoMap::tempo_section_at_minute_locked (const Metrics& metrics, double minute) const
3872 {
3873         TempoSection* prev = 0;
3874
3875         TempoSection* t;
3876
3877         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3878
3879                 if ((*i)->is_tempo()) {
3880                         t = static_cast<TempoSection*> (*i);
3881                         if (!t->active()) {
3882                                 continue;
3883                         }
3884                         if (prev && t->minute() > minute) {
3885                                 break;
3886                         }
3887
3888                         prev = t;
3889                 }
3890         }
3891
3892         if (prev == 0) {
3893                 fatal << endmsg;
3894                 abort(); /*NOTREACHED*/
3895         }
3896
3897         return *prev;
3898 }
3899
3900 const TempoSection&
3901 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3902 {
3903         TempoSection* prev_t = 0;
3904         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
3905
3906         TempoSection* t;
3907
3908         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3909                 if ((*i)->is_tempo()) {
3910                         t = static_cast<TempoSection*> (*i);
3911                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
3912                                 break;
3913                         }
3914                         prev_t = t;
3915                 }
3916
3917         }
3918         return *prev_t;
3919 }
3920
3921 /* don't use this to calculate length (the tempo is only correct for this frame).
3922    do that stuff based on the beat_at_frame and frame_at_beat api
3923 */
3924 double
3925 TempoMap::frames_per_quarter_note_at (const framepos_t& frame, const framecnt_t& sr) const
3926 {
3927         Glib::Threads::RWLock::ReaderLock lm (lock);
3928
3929         const TempoSection* ts_at = 0;
3930         const TempoSection* ts_after = 0;
3931         Metrics::const_iterator i;
3932         TempoSection* t;
3933
3934         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3935
3936                 if ((*i)->is_tempo()) {
3937                         t = static_cast<TempoSection*> (*i);
3938                         if (!t->active()) {
3939                                 continue;
3940                         }
3941                         if (ts_at && (*i)->frame() > frame) {
3942                                 ts_after = t;
3943                                 break;
3944                         }
3945                         ts_at = t;
3946                 }
3947         }
3948         assert (ts_at);
3949
3950         if (ts_after) {
3951                 return  (60.0 * _frame_rate) / ts_at->tempo_at_minute (minute_at_frame (frame)).quarter_notes_per_minute();
3952         }
3953         /* must be treated as constant tempo */
3954         return ts_at->frames_per_quarter_note (_frame_rate);
3955 }
3956
3957 const MeterSection&
3958 TempoMap::meter_section_at_frame (framepos_t frame) const
3959 {
3960         Glib::Threads::RWLock::ReaderLock lm (lock);
3961         return meter_section_at_minute_locked (_metrics, minute_at_frame (frame));
3962 }
3963
3964 const MeterSection&
3965 TempoMap::meter_section_at_minute_locked (const Metrics& metrics, double minute) const
3966 {
3967         Metrics::const_iterator i;
3968         MeterSection* prev = 0;
3969
3970         MeterSection* m;
3971
3972         for (i = metrics.begin(); i != metrics.end(); ++i) {
3973
3974                 if (!(*i)->is_tempo()) {
3975                         m = static_cast<MeterSection*> (*i);
3976
3977                         if (prev && (*i)->minute() > minute) {
3978                                 break;
3979                         }
3980
3981                         prev = m;
3982                 }
3983         }
3984
3985         if (prev == 0) {
3986                 fatal << endmsg;
3987                 abort(); /*NOTREACHED*/
3988         }
3989
3990         return *prev;
3991 }
3992
3993 const MeterSection&
3994 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3995 {
3996         MeterSection* prev_m = 0;
3997
3998         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3999                 MeterSection* m;
4000                 if (!(*i)->is_tempo()) {
4001                         m = static_cast<MeterSection*> (*i);
4002                         if (prev_m && m->beat() > beat) {
4003                                 break;
4004                         }
4005                         prev_m = m;
4006                 }
4007
4008         }
4009         return *prev_m;
4010 }
4011
4012 const MeterSection&
4013 TempoMap::meter_section_at_beat (double beat) const
4014 {
4015         Glib::Threads::RWLock::ReaderLock lm (lock);
4016         return meter_section_at_beat_locked (_metrics, beat);
4017 }
4018
4019 const Meter&
4020 TempoMap::meter_at_frame (framepos_t frame) const
4021 {
4022         TempoMetric m (metric_at (frame));
4023         return m.meter();
4024 }
4025
4026 void
4027 TempoMap::fix_legacy_session ()
4028 {
4029         MeterSection* prev_m = 0;
4030         TempoSection* prev_t = 0;
4031
4032         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4033                 MeterSection* m;
4034                 TempoSection* t;
4035
4036                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
4037                         if (!m->movable()) {
4038                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
4039                                 m->set_beat (bbt);
4040                                 m->set_pulse (0.0);
4041                                 m->set_minute (0.0);
4042                                 m->set_position_lock_style (AudioTime);
4043                                 prev_m = m;
4044                                 continue;
4045                         }
4046                         if (prev_m) {
4047                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
4048                                                                           + (m->bbt().beats - 1)
4049                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
4050                                                                           , m->bbt());
4051                                 m->set_beat (start);
4052                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
4053                                         + (m->bbt().beats - 1)
4054                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
4055                                 m->set_pulse (start_beat / prev_m->note_divisor());
4056                         }
4057                         prev_m = m;
4058                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
4059
4060                         if (!t->active()) {
4061                                 continue;
4062                         }
4063
4064                         if (!t->movable()) {
4065                                 t->set_pulse (0.0);
4066                                 t->set_minute (0.0);
4067                                 t->set_position_lock_style (AudioTime);
4068                                 prev_t = t;
4069                                 continue;
4070                         }
4071
4072                         if (prev_t) {
4073                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
4074                                         + (t->legacy_bbt().beats - 1)
4075                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
4076                                 if (prev_m) {
4077                                         t->set_pulse (beat / prev_m->note_divisor());
4078                                 } else {
4079                                         /* really shouldn't happen but.. */
4080                                         t->set_pulse (beat / 4.0);
4081                                 }
4082                         }
4083                         prev_t = t;
4084                 }
4085         }
4086 }
4087
4088 XMLNode&
4089 TempoMap::get_state ()
4090 {
4091         Metrics::const_iterator i;
4092         XMLNode *root = new XMLNode ("TempoMap");
4093
4094         {
4095                 Glib::Threads::RWLock::ReaderLock lm (lock);
4096                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
4097                         root->add_child_nocopy ((*i)->get_state());
4098                 }
4099         }
4100
4101         return *root;
4102 }
4103
4104 int
4105 TempoMap::set_state (const XMLNode& node, int /*version*/)
4106 {
4107         {
4108                 Glib::Threads::RWLock::WriterLock lm (lock);
4109
4110                 XMLNodeList nlist;
4111                 XMLNodeConstIterator niter;
4112                 Metrics old_metrics (_metrics);
4113                 _metrics.clear();
4114
4115                 nlist = node.children();
4116
4117                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
4118                         XMLNode* child = *niter;
4119
4120                         if (child->name() == TempoSection::xml_state_node_name) {
4121
4122                                 try {
4123                                         TempoSection* ts = new TempoSection (*child, _frame_rate);
4124                                         _metrics.push_back (ts);
4125                                 }
4126
4127                                 catch (failed_constructor& err){
4128                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
4129                                         _metrics = old_metrics;
4130                                         old_metrics.clear();
4131                                         break;
4132                                 }
4133
4134                         } else if (child->name() == MeterSection::xml_state_node_name) {
4135
4136                                 try {
4137                                         MeterSection* ms = new MeterSection (*child, _frame_rate);
4138                                         _metrics.push_back (ms);
4139                                 }
4140
4141                                 catch (failed_constructor& err) {
4142                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
4143                                         _metrics = old_metrics;
4144                                         old_metrics.clear();
4145                                         break;
4146                                 }
4147                         }
4148                 }
4149
4150                 if (niter == nlist.end()) {
4151                         MetricSectionSorter cmp;
4152                         _metrics.sort (cmp);
4153                 }
4154
4155                 /* check for legacy sessions where bbt was the base musical unit for tempo */
4156                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4157                         TempoSection* t;
4158                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
4159                                 if (t->legacy_bbt().bars != 0) {
4160                                         fix_legacy_session();
4161                                         break;
4162                                 }
4163                                 break;
4164                         }
4165                 }
4166
4167                 /* check for multiple tempo/meters at the same location, which
4168                    ardour2 somehow allowed.
4169                 */
4170
4171                 Metrics::iterator prev = _metrics.end();
4172                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4173                         if (prev != _metrics.end()) {
4174                                 MeterSection* ms;
4175                                 MeterSection* prev_m;
4176                                 TempoSection* ts;
4177                                 TempoSection* prev_t;
4178                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
4179                                         if (prev_m->pulse() == ms->pulse()) {
4180                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
4181                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
4182                                                 return -1;
4183                                         }
4184                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
4185                                         if (prev_t->pulse() == ts->pulse()) {
4186                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
4187                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
4188                                                 return -1;
4189                                         }
4190                                 }
4191                         }
4192                         prev = i;
4193                 }
4194
4195                 recompute_map (_metrics);
4196
4197                 Metrics::const_iterator d = old_metrics.begin();
4198                 while (d != old_metrics.end()) {
4199                         delete (*d);
4200                         ++d;
4201                 }
4202                 old_metrics.clear ();
4203         }
4204
4205         PropertyChanged (PropertyChange ());
4206
4207         return 0;
4208 }
4209
4210 void
4211 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
4212 {
4213         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
4214         const MeterSection* m;
4215         const TempoSection* t;
4216         const TempoSection* prev_t = 0;
4217
4218         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4219
4220                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
4221                         o << "Tempo @ " << *i << t->note_types_per_minute() << " BPM (pulse = 1/" << t->note_type()
4222                           << " type= " << enum_2_string (t->type()) << ") "  << " at pulse= " << t->pulse()
4223                           << " minute= " << t->minute() << " frame= " << t->frame() << " (movable? " << t->movable() << ')'
4224                           << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
4225                         if (prev_t) {
4226                                 o << std::setprecision (17) << "  current      : " << t->note_types_per_minute()
4227                                   << " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl;
4228                                 o << "  previous     : " << prev_t->note_types_per_minute()
4229                                   << " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl;
4230                                 o << "  calculated   : " << prev_t->tempo_at_pulse (t->pulse())
4231                                   << " | " << prev_t->pulse_at_ntpm (t->note_types_per_minute(), t->minute())
4232                                   << " | " << frame_at_minute (prev_t->minute_at_ntpm (t->note_types_per_minute(), t->pulse()))
4233                                   << " | " << prev_t->minute_at_ntpm (t->note_types_per_minute(), t->pulse()) << std::endl;
4234                         }
4235                         prev_t = t;
4236                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
4237                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt()
4238                           << " frame= " << m->frame() << " pulse: " << m->pulse() <<  " beat : " << m->beat()
4239                           << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
4240                 }
4241         }
4242         o << "------" << std::endl;
4243 }
4244
4245 int
4246 TempoMap::n_tempos() const
4247 {
4248         Glib::Threads::RWLock::ReaderLock lm (lock);
4249         int cnt = 0;
4250
4251         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4252                 if ((*i)->is_tempo()) {
4253                         cnt++;
4254                 }
4255         }
4256
4257         return cnt;
4258 }
4259
4260 int
4261 TempoMap::n_meters() const
4262 {
4263         Glib::Threads::RWLock::ReaderLock lm (lock);
4264         int cnt = 0;
4265
4266         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4267                 if (!(*i)->is_tempo()) {
4268                         cnt++;
4269                 }
4270         }
4271
4272         return cnt;
4273 }
4274
4275 void
4276 TempoMap::insert_time (framepos_t where, framecnt_t amount)
4277 {
4278         for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
4279                 if ((*i)->frame() >= where && (*i)->movable ()) {
4280                         MeterSection* ms;
4281                         TempoSection* ts;
4282
4283                         if ((ms = dynamic_cast <MeterSection*>(*i)) != 0) {
4284                                 gui_move_meter (ms, (*i)->frame() + amount);
4285                         }
4286
4287                         if ((ts = dynamic_cast <TempoSection*>(*i)) != 0) {
4288                                 gui_move_tempo (ts, (*i)->frame() + amount, 0);
4289                         }
4290                 }
4291         }
4292
4293         PropertyChanged (PropertyChange ());
4294 }
4295
4296 bool
4297 TempoMap::remove_time (framepos_t where, framecnt_t amount)
4298 {
4299         bool moved = false;
4300
4301         std::list<MetricSection*> metric_kill_list;
4302
4303         TempoSection* last_tempo = NULL;
4304         MeterSection* last_meter = NULL;
4305         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
4306         bool meter_after = false; // is there a meter marker likewise?
4307         {
4308                 Glib::Threads::RWLock::WriterLock lm (lock);
4309                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4310                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
4311                                 metric_kill_list.push_back(*i);
4312                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
4313                                 if (lt)
4314                                         last_tempo = lt;
4315                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
4316                                 if (lm)
4317                                         last_meter = lm;
4318                         }
4319                         else if ((*i)->frame() >= where) {
4320                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
4321                                 (*i)->set_minute ((*i)->minute() - minute_at_frame (amount));
4322                                 if ((*i)->frame() == where) {
4323                                         // marker was immediately after end of range
4324                                         tempo_after = dynamic_cast<TempoSection*> (*i);
4325                                         meter_after = dynamic_cast<MeterSection*> (*i);
4326                                 }
4327                                 moved = true;
4328                         }
4329                 }
4330
4331                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
4332                 if (last_tempo && !tempo_after) {
4333                         metric_kill_list.remove(last_tempo);
4334                         last_tempo->set_minute (minute_at_frame (where));
4335                         moved = true;
4336                 }
4337                 if (last_meter && !meter_after) {
4338                         metric_kill_list.remove(last_meter);
4339                         last_meter->set_minute (minute_at_frame (where));
4340                         moved = true;
4341                 }
4342
4343                 //remove all the remaining metrics
4344                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
4345                         _metrics.remove(*i);
4346                         moved = true;
4347                 }
4348
4349                 if (moved) {
4350                         recompute_map (_metrics);
4351                 }
4352         }
4353         PropertyChanged (PropertyChange ());
4354         return moved;
4355 }
4356
4357 /** Add some (fractional) Beats to a session frame position, and return the result in frames.
4358  *  pos can be -ve, if required.
4359  */
4360 framepos_t
4361 TempoMap::framepos_plus_qn (framepos_t frame, Evoral::Beats beats) const
4362 {
4363         Glib::Threads::RWLock::ReaderLock lm (lock);
4364         const double frame_qn = quarter_notes_between_frames_locked (_metrics, 0, frame);
4365
4366         return frame_at_minute (minute_at_quarter_note_locked (_metrics, frame_qn + beats.to_double()));
4367 }
4368
4369 framepos_t
4370 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
4371 {
4372         Glib::Threads::RWLock::ReaderLock lm (lock);
4373
4374         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_minute_locked (_metrics, minute_at_frame (pos)));
4375         pos_bbt.ticks += op.ticks;
4376         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
4377                 ++pos_bbt.beats;
4378                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
4379         }
4380         pos_bbt.beats += op.beats;
4381         /* the meter in effect will start on the bar */
4382         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();
4383         while (pos_bbt.beats >= divisions_per_bar + 1) {
4384                 ++pos_bbt.bars;
4385                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
4386                 pos_bbt.beats -= divisions_per_bar;
4387         }
4388         pos_bbt.bars += op.bars;
4389
4390         return frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
4391 }
4392
4393 /** Count the number of beats that are equivalent to distance when going forward,
4394     starting at pos.
4395 */
4396 Evoral::Beats
4397 TempoMap::framewalk_to_qn (framepos_t pos, framecnt_t distance) const
4398 {
4399         Glib::Threads::RWLock::ReaderLock lm (lock);
4400
4401         return Evoral::Beats (quarter_notes_between_frames_locked (_metrics, pos, pos + distance));
4402 }
4403
4404 struct bbtcmp {
4405     bool operator() (const BBT_Time& a, const BBT_Time& b) {
4406             return a < b;
4407     }
4408 };
4409
4410 std::ostream&
4411 operator<< (std::ostream& o, const Meter& m) {
4412         return o << m.divisions_per_bar() << '/' << m.note_divisor();
4413 }
4414
4415 std::ostream&
4416 operator<< (std::ostream& o, const Tempo& t) {
4417         return o << t.note_types_per_minute() << " 1/" << t.note_type() << "'s per minute";
4418 }
4419
4420 std::ostream&
4421 operator<< (std::ostream& o, const MetricSection& section) {
4422
4423         o << "MetricSection @ " << section.frame() << ' ';
4424
4425         const TempoSection* ts;
4426         const MeterSection* ms;
4427
4428         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
4429                 o << *((const Tempo*) ts);
4430         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
4431                 o << *((const Meter*) ms);
4432         }
4433
4434         return o;
4435 }