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