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