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