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