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