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