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