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