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