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