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