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