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