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