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