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