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