Lua bindings to access MIDI region/source note-events
[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         if (last) {
1613                 *last = ++_metrics.begin();
1614         }
1615
1616         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1617            at something, because we insert the default tempo and meter during
1618            TempoMap construction.
1619
1620            now see if we can find better candidates.
1621         */
1622
1623         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1624
1625                 if ((*i)->frame() > frame) {
1626                         break;
1627                 }
1628
1629                 m.set_metric(*i);
1630
1631                 if (last) {
1632                         *last = i;
1633                 }
1634         }
1635
1636         return m;
1637 }
1638
1639 /* XX meters only */
1640 TempoMetric
1641 TempoMap::metric_at (BBT_Time bbt) const
1642 {
1643         Glib::Threads::RWLock::ReaderLock lm (lock);
1644         TempoMetric m (first_meter(), first_tempo());
1645
1646         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1647            at something, because we insert the default tempo and meter during
1648            TempoMap construction.
1649
1650            now see if we can find better candidates.
1651         */
1652
1653         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1654                 MeterSection* mw;
1655                 if (!(*i)->is_tempo()) {
1656                         mw = static_cast<MeterSection*> (*i);
1657                         BBT_Time section_start (mw->bbt());
1658
1659                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1660                                 break;
1661                         }
1662
1663                         m.set_metric (*i);
1664                 }
1665         }
1666
1667         return m;
1668 }
1669
1670 /** Returns the BBT (meter-based) beat corresponding to the supplied frame, possibly returning a negative value.
1671  * @param frame The session frame position.
1672  * @return The beat duration according to the tempo map at the supplied frame.
1673  *
1674  * If the supplied frame lies before the first meter, the returned beat duration will be negative.
1675  * The returned beat is obtained using the first meter and the continuation of the tempo curve (backwards).
1676  *
1677  * This function uses both tempo and meter.
1678  */
1679 double
1680 TempoMap::beat_at_frame (const framecnt_t& frame) const
1681 {
1682         Glib::Threads::RWLock::ReaderLock lm (lock);
1683
1684         return beat_at_minute_locked (_metrics, minute_at_frame (frame));
1685 }
1686
1687 /* This function uses both tempo and meter.*/
1688 double
1689 TempoMap::beat_at_minute_locked (const Metrics& metrics, const double& minute) const
1690 {
1691         const TempoSection& ts = tempo_section_at_minute_locked (metrics, minute);
1692         MeterSection* prev_m = 0;
1693         MeterSection* next_m = 0;
1694
1695         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1696                 if (!(*i)->is_tempo()) {
1697                         if (prev_m && (*i)->minute() > minute) {
1698                                 next_m = static_cast<MeterSection*> (*i);
1699                                 break;
1700                         }
1701                         prev_m = static_cast<MeterSection*> (*i);
1702                 }
1703         }
1704
1705         const double beat = prev_m->beat() + (ts.pulse_at_minute (minute) - prev_m->pulse()) * prev_m->note_divisor();
1706
1707         /* audio locked meters fake their beat */
1708         if (next_m && next_m->beat() < beat) {
1709                 return next_m->beat();
1710         }
1711
1712         return beat;
1713 }
1714
1715 /** Returns the frame corresponding to the supplied BBT (meter-based) beat.
1716  * @param beat The BBT (meter-based) beat.
1717  * @return The frame duration according to the tempo map at the supplied BBT (meter-based) beat.
1718  *
1719  * This function uses both tempo and meter.
1720  */
1721 framepos_t
1722 TempoMap::frame_at_beat (const double& beat) const
1723 {
1724         Glib::Threads::RWLock::ReaderLock lm (lock);
1725
1726         return frame_at_minute (minute_at_beat_locked (_metrics, beat));
1727 }
1728
1729 /* meter & tempo section based */
1730 double
1731 TempoMap::minute_at_beat_locked (const Metrics& metrics, const double& beat) const
1732 {
1733         MeterSection* prev_m = 0;
1734         TempoSection* prev_t = 0;
1735
1736         MeterSection* m;
1737
1738         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1739                 if (!(*i)->is_tempo()) {
1740                         m = static_cast<MeterSection*> (*i);
1741                         if (prev_m && m->beat() > beat) {
1742                                 break;
1743                         }
1744                         prev_m = m;
1745                 }
1746         }
1747         assert (prev_m);
1748
1749         TempoSection* t;
1750
1751         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1752                 if ((*i)->is_tempo()) {
1753                         t = static_cast<TempoSection*> (*i);
1754
1755                         if (!t->active()) {
1756                                 continue;
1757                         }
1758
1759                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
1760                                 break;
1761                         }
1762                         prev_t = t;
1763                 }
1764
1765         }
1766         assert (prev_t);
1767
1768         return prev_t->minute_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse());
1769 }
1770
1771 /** Returns a Tempo corresponding to the supplied frame position.
1772  * @param frame The audio frame.
1773  * @return a Tempo according to the tempo map at the supplied frame.
1774  *
1775  */
1776 Tempo
1777 TempoMap::tempo_at_frame (const framepos_t& frame) const
1778 {
1779         Glib::Threads::RWLock::ReaderLock lm (lock);
1780
1781         return tempo_at_minute_locked (_metrics, minute_at_frame (frame));
1782 }
1783
1784 Tempo
1785 TempoMap::tempo_at_minute_locked (const Metrics& metrics, const double& minute) const
1786 {
1787         TempoSection* prev_t = 0;
1788
1789         TempoSection* t;
1790
1791         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1792                 if ((*i)->is_tempo()) {
1793                         t = static_cast<TempoSection*> (*i);
1794                         if (!t->active()) {
1795                                 continue;
1796                         }
1797                         if ((prev_t) && t->minute() > minute) {
1798                                 /* t is the section past frame */
1799                                 return prev_t->tempo_at_minute (minute);
1800                         }
1801                         prev_t = t;
1802                 }
1803         }
1804
1805         return Tempo (prev_t->note_types_per_minute(), prev_t->note_type(), prev_t->end_note_types_per_minute());
1806 }
1807
1808 /** returns the frame at which the supplied tempo occurs, or
1809  *  the frame of the last tempo section (search exhausted)
1810  *  only the position of the first occurence will be returned
1811  *  (extend me)
1812 */
1813 framepos_t
1814 TempoMap::frame_at_tempo (const Tempo& tempo) const
1815 {
1816         Glib::Threads::RWLock::ReaderLock lm (lock);
1817
1818         return frame_at_minute (minute_at_tempo_locked (_metrics, tempo));
1819 }
1820
1821 double
1822 TempoMap::minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1823 {
1824         TempoSection* prev_t = 0;
1825         const double tempo_bpm = tempo.note_types_per_minute();
1826
1827         Metrics::const_iterator i;
1828
1829         for (i = metrics.begin(); i != metrics.end(); ++i) {
1830                 TempoSection* t;
1831                 if ((*i)->is_tempo()) {
1832                         t = static_cast<TempoSection*> (*i);
1833
1834                         if (!t->active()) {
1835                                 continue;
1836                         }
1837
1838
1839
1840                         if (t->note_types_per_minute() == tempo_bpm) {
1841                                 return t->minute();
1842                         }
1843
1844                         if (prev_t) {
1845                                 const double prev_t_bpm = prev_t->note_types_per_minute();
1846                                 const double prev_t_end_bpm = prev_t->end_note_types_per_minute();
1847                                 if ((prev_t_bpm > tempo_bpm && prev_t_end_bpm < tempo_bpm)
1848                                     || (prev_t_bpm < tempo_bpm && prev_t_end_bpm > tempo_bpm)
1849                                     || (prev_t_end_bpm == tempo_bpm)) {
1850
1851                                         return prev_t->minute_at_ntpm (tempo_bpm, t->pulse());
1852                                 }
1853                         }
1854                         prev_t = t;
1855                 }
1856         }
1857
1858         return prev_t->minute();
1859 }
1860
1861 Tempo
1862 TempoMap::tempo_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1863 {
1864         TempoSection* prev_t = 0;
1865
1866         TempoSection* t;
1867
1868         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1869                 if ((*i)->is_tempo()) {
1870                         t = static_cast<TempoSection*> (*i);
1871                         if (!t->active()) {
1872                                 continue;
1873                         }
1874                         if ((prev_t) && t->pulse() > pulse) {
1875                                 /* t is the section past frame */
1876                                 return prev_t->tempo_at_pulse (pulse);
1877                         }
1878                         prev_t = t;
1879                 }
1880         }
1881
1882         return Tempo (prev_t->note_types_per_minute(), prev_t->note_type(), prev_t->end_note_types_per_minute());
1883 }
1884
1885 double
1886 TempoMap::pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1887 {
1888         TempoSection* prev_t = 0;
1889         const double tempo_bpm = tempo.note_types_per_minute();
1890
1891         Metrics::const_iterator i;
1892
1893         for (i = metrics.begin(); i != metrics.end(); ++i) {
1894                 TempoSection* t;
1895                 if ((*i)->is_tempo()) {
1896                         t = static_cast<TempoSection*> (*i);
1897
1898                         if (!t->active()) {
1899                                 continue;
1900                         }
1901
1902                         const double t_bpm = t->note_types_per_minute();
1903
1904                         if (t_bpm == tempo_bpm) {
1905                                 return t->pulse();
1906                         }
1907
1908                         if (prev_t) {
1909                                 const double prev_t_bpm = prev_t->note_types_per_minute();
1910
1911                                 if ((t_bpm > tempo_bpm && prev_t_bpm < tempo_bpm) || (t_bpm < tempo_bpm && prev_t_bpm > tempo_bpm)) {
1912                                         return prev_t->pulse_at_ntpm (prev_t->note_types_per_minute(), prev_t->minute());
1913                                 }
1914                         }
1915                         prev_t = t;
1916                 }
1917         }
1918
1919         return prev_t->pulse();
1920 }
1921
1922 /** Returns a Tempo corresponding to the supplied position in quarter-note beats.
1923  * @param qn the position in quarter note beats.
1924  * @return the Tempo at the supplied quarter-note.
1925  */
1926 Tempo
1927 TempoMap::tempo_at_quarter_note (const double& qn) const
1928 {
1929         Glib::Threads::RWLock::ReaderLock lm (lock);
1930
1931         return tempo_at_pulse_locked (_metrics, qn / 4.0);
1932 }
1933
1934 /** Returns the position in quarter-note beats corresponding to the supplied Tempo.
1935  * @param tempo the tempo.
1936  * @return the position in quarter-note beats where the map bpm
1937  * is equal to that of the Tempo. currently ignores note_type.
1938  */
1939 double
1940 TempoMap::quarter_note_at_tempo (const Tempo& tempo) const
1941 {
1942         Glib::Threads::RWLock::ReaderLock lm (lock);
1943
1944         return pulse_at_tempo_locked (_metrics, tempo) * 4.0;;
1945 }
1946
1947 /** Returns the whole-note pulse corresponding to the supplied  BBT (meter-based) beat.
1948  * @param metrics the list of metric sections used to calculate the pulse.
1949  * @param beat The BBT (meter-based) beat.
1950  * @return the whole-note pulse at the supplied BBT (meter-based) beat.
1951  *
1952  * a pulse or whole note is the base musical position of a MetricSection.
1953  * it is equivalent to four quarter notes.
1954  *
1955  */
1956 double
1957 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1958 {
1959         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
1960
1961         return prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1962 }
1963
1964 /** Returns the BBT (meter-based) beat corresponding to the supplied whole-note pulse .
1965  * @param metrics the list of metric sections used to calculate the beat.
1966  * @param pulse the whole-note pulse.
1967  * @return the meter-based beat at the supplied whole-note pulse.
1968  *
1969  * a pulse or whole note is the base musical position of a MetricSection.
1970  * it is equivalent to four quarter notes.
1971  */
1972 double
1973 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1974 {
1975         MeterSection* prev_m = 0;
1976
1977         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1978                 MeterSection* m;
1979                 if (!(*i)->is_tempo()) {
1980                         m = static_cast<MeterSection*> (*i);
1981                         if (prev_m && m->pulse() > pulse) {
1982                                 break;
1983                         }
1984                         prev_m = m;
1985                 }
1986         }
1987         assert (prev_m);
1988
1989         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1990         return ret;
1991 }
1992
1993 /* tempo section based */
1994 double
1995 TempoMap::pulse_at_minute_locked (const Metrics& metrics, const double& minute) const
1996 {
1997         /* HOLD (at least) THE READER LOCK */
1998         TempoSection* prev_t = 0;
1999
2000         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2001                 TempoSection* t;
2002                 if ((*i)->is_tempo()) {
2003                         t = static_cast<TempoSection*> (*i);
2004                         if (!t->active()) {
2005                                 continue;
2006                         }
2007                         if (prev_t && t->minute() > minute) {
2008                                 /*the previous ts is the one containing the frame */
2009                                 const double ret = prev_t->pulse_at_minute (minute);
2010                                 /* audio locked section in new meter*/
2011                                 if (t->pulse() < ret) {
2012                                         return t->pulse();
2013                                 }
2014                                 return ret;
2015                         }
2016                         prev_t = t;
2017                 }
2018         }
2019
2020         /* treated as constant for this ts */
2021         const double pulses_in_section = ((minute - prev_t->minute()) * prev_t->note_types_per_minute()) / prev_t->note_type();
2022
2023         return pulses_in_section + prev_t->pulse();
2024 }
2025
2026 /* tempo section based */
2027 double
2028 TempoMap::minute_at_pulse_locked (const Metrics& metrics, const double& pulse) const
2029 {
2030         /* HOLD THE READER LOCK */
2031
2032         const TempoSection* prev_t = 0;
2033
2034         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2035                 TempoSection* t;
2036
2037                 if ((*i)->is_tempo()) {
2038                         t = static_cast<TempoSection*> (*i);
2039                         if (!t->active()) {
2040                                 continue;
2041                         }
2042                         if (prev_t && t->pulse() > pulse) {
2043                                 return prev_t->minute_at_pulse (pulse);
2044                         }
2045
2046                         prev_t = t;
2047                 }
2048         }
2049         /* must be treated as constant, irrespective of _type */
2050         double const dtime = ((pulse - prev_t->pulse()) * prev_t->note_type()) / prev_t->note_types_per_minute();
2051
2052         return dtime + prev_t->minute();
2053 }
2054
2055 /** Returns the BBT (meter-based) beat corresponding to the supplied BBT time.
2056  * @param bbt The BBT time (meter-based).
2057  * @return bbt The BBT beat (meter-based) at the supplied BBT time.
2058  *
2059  */
2060 double
2061 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
2062 {
2063         Glib::Threads::RWLock::ReaderLock lm (lock);
2064         return beat_at_bbt_locked (_metrics, bbt);
2065 }
2066
2067
2068 double
2069 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
2070 {
2071         /* CALLER HOLDS READ LOCK */
2072
2073         MeterSection* prev_m = 0;
2074
2075         /* because audio-locked meters have 'fake' integral beats,
2076            there is no pulse offset here.
2077         */
2078         MeterSection* m;
2079
2080         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2081                 if (!(*i)->is_tempo()) {
2082                         m = static_cast<MeterSection*> (*i);
2083                         if (prev_m) {
2084                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
2085                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
2086                                         break;
2087                                 }
2088                         }
2089                         prev_m = m;
2090                 }
2091         }
2092
2093         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
2094         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
2095         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
2096
2097         return ret;
2098 }
2099
2100 /** Returns the BBT time corresponding to the supplied BBT (meter-based) beat.
2101  * @param beat The BBT (meter-based) beat.
2102  * @return The BBT time (meter-based) at the supplied meter-based beat.
2103  *
2104  */
2105 Timecode::BBT_Time
2106 TempoMap::bbt_at_beat (const double& beat)
2107 {
2108         Glib::Threads::RWLock::ReaderLock lm (lock);
2109         return bbt_at_beat_locked (_metrics, beat);
2110 }
2111
2112 Timecode::BBT_Time
2113 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
2114 {
2115         /* CALLER HOLDS READ LOCK */
2116         MeterSection* prev_m = 0;
2117         const double beats = max (0.0, b);
2118
2119         MeterSection* m = 0;
2120
2121         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2122                 if (!(*i)->is_tempo()) {
2123                         m = static_cast<MeterSection*> (*i);
2124                         if (prev_m) {
2125                                 if (m->beat() > beats) {
2126                                         /* this is the meter after the one our beat is on*/
2127                                         break;
2128                                 }
2129                         }
2130
2131                         prev_m = m;
2132                 }
2133         }
2134         assert (prev_m);
2135
2136         const double beats_in_ms = beats - prev_m->beat();
2137         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2138         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2139         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2140         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2141
2142         BBT_Time ret;
2143
2144         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2145         ret.beats = (uint32_t) floor (remaining_beats);
2146         ret.bars = total_bars;
2147
2148         /* 0 0 0 to 1 1 0 - based mapping*/
2149         ++ret.bars;
2150         ++ret.beats;
2151
2152         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2153                 ++ret.beats;
2154                 ret.ticks -= BBT_Time::ticks_per_beat;
2155         }
2156
2157         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2158                 ++ret.bars;
2159                 ret.beats = 1;
2160         }
2161
2162         return ret;
2163 }
2164
2165 /** Returns the quarter-note beat corresponding to the supplied BBT time (meter-based).
2166  * @param bbt The BBT time (meter-based).
2167  * @return the quarter note beat at the supplied BBT time
2168  *
2169  * quarter-notes ignore meter and are based on pulse (the musical unit of MetricSection).
2170  *
2171  * while the input uses meter, the output does not.
2172  */
2173 double
2174 TempoMap::quarter_note_at_bbt (const Timecode::BBT_Time& bbt)
2175 {
2176         Glib::Threads::RWLock::ReaderLock lm (lock);
2177
2178         return pulse_at_bbt_locked (_metrics, bbt) * 4.0;
2179 }
2180
2181 double
2182 TempoMap::quarter_note_at_bbt_rt (const Timecode::BBT_Time& bbt)
2183 {
2184         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2185
2186         if (!lm.locked()) {
2187                 throw std::logic_error ("TempoMap::quarter_note_at_bbt_rt() could not lock tempo map");
2188         }
2189
2190         return pulse_at_bbt_locked (_metrics, bbt) * 4.0;
2191 }
2192
2193 double
2194 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
2195 {
2196         /* CALLER HOLDS READ LOCK */
2197
2198         MeterSection* prev_m = 0;
2199
2200         /* because audio-locked meters have 'fake' integral beats,
2201            there is no pulse offset here.
2202         */
2203         MeterSection* m;
2204
2205         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2206                 if (!(*i)->is_tempo()) {
2207                         m = static_cast<MeterSection*> (*i);
2208                         if (prev_m) {
2209                                 if (m->bbt().bars > bbt.bars) {
2210                                         break;
2211                                 }
2212                         }
2213                         prev_m = m;
2214                 }
2215         }
2216
2217         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
2218         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
2219         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
2220
2221         return ret;
2222 }
2223
2224 /** Returns the BBT time corresponding to the supplied quarter-note beat.
2225  * @param qn the quarter-note beat.
2226  * @return The BBT time (meter-based) at the supplied meter-based beat.
2227  *
2228  * quarter-notes ignore meter and are based on pulse (the musical unit of MetricSection).
2229  *
2230  */
2231 Timecode::BBT_Time
2232 TempoMap::bbt_at_quarter_note (const double& qn)
2233 {
2234         Glib::Threads::RWLock::ReaderLock lm (lock);
2235
2236         return bbt_at_pulse_locked (_metrics, qn / 4.0);
2237 }
2238
2239 /** Returns the BBT time (meter-based) corresponding to the supplied whole-note pulse position.
2240  * @param metrics The list of metric sections used to determine the result.
2241  * @param pulse The whole-note pulse.
2242  * @return The BBT time at the supplied whole-note pulse.
2243  *
2244  * a pulse or whole note is the basic musical position of a MetricSection.
2245  * it is equivalent to four quarter notes.
2246  * while the output uses meter, the input does not.
2247  */
2248 Timecode::BBT_Time
2249 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
2250 {
2251         MeterSection* prev_m = 0;
2252
2253         MeterSection* m = 0;
2254
2255         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2256
2257                 if (!(*i)->is_tempo()) {
2258                         m = static_cast<MeterSection*> (*i);
2259
2260                         if (prev_m) {
2261                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
2262                                 if (prev_m->pulse() + pulses_to_m > pulse) {
2263                                         /* this is the meter after the one our beat is on*/
2264                                         break;
2265                                 }
2266                         }
2267
2268                         prev_m = m;
2269                 }
2270         }
2271
2272         assert (prev_m);
2273
2274         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
2275         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2276         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2277         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2278         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2279
2280         BBT_Time ret;
2281
2282         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2283         ret.beats = (uint32_t) floor (remaining_beats);
2284         ret.bars = total_bars;
2285
2286         /* 0 0 0 to 1 1 0 mapping*/
2287         ++ret.bars;
2288         ++ret.beats;
2289
2290         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2291                 ++ret.beats;
2292                 ret.ticks -= BBT_Time::ticks_per_beat;
2293         }
2294
2295         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2296                 ++ret.bars;
2297                 ret.beats = 1;
2298         }
2299
2300         return ret;
2301 }
2302
2303 /** Returns the BBT time corresponding to the supplied frame position.
2304  * @param frame the position in audio samples.
2305  * @return the BBT time at the frame position .
2306  *
2307  */
2308 BBT_Time
2309 TempoMap::bbt_at_frame (framepos_t frame)
2310 {
2311         if (frame < 0) {
2312                 BBT_Time bbt;
2313                 bbt.bars = 1;
2314                 bbt.beats = 1;
2315                 bbt.ticks = 0;
2316 #ifndef NDEBUG
2317                 warning << string_compose (_("tempo map was asked for BBT time at frame %1\n"), frame) << endmsg;
2318 #endif
2319                 return bbt;
2320         }
2321
2322         const double minute =  minute_at_frame (frame);
2323
2324         Glib::Threads::RWLock::ReaderLock lm (lock);
2325
2326         return bbt_at_minute_locked (_metrics, minute);
2327 }
2328
2329 BBT_Time
2330 TempoMap::bbt_at_frame_rt (framepos_t frame)
2331 {
2332         const double minute =  minute_at_frame (frame);
2333
2334         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2335
2336         if (!lm.locked()) {
2337                 throw std::logic_error ("TempoMap::bbt_at_frame_rt() could not lock tempo map");
2338         }
2339
2340         return bbt_at_minute_locked (_metrics, minute);
2341 }
2342
2343 Timecode::BBT_Time
2344 TempoMap::bbt_at_minute_locked (const Metrics& metrics, const double& minute) const
2345 {
2346         if (minute < 0) {
2347                 BBT_Time bbt;
2348                 bbt.bars = 1;
2349                 bbt.beats = 1;
2350                 bbt.ticks = 0;
2351                 return bbt;
2352         }
2353
2354         const TempoSection& ts = tempo_section_at_minute_locked (metrics, minute);
2355         MeterSection* prev_m = 0;
2356         MeterSection* next_m = 0;
2357
2358         MeterSection* m;
2359
2360         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2361                 if (!(*i)->is_tempo()) {
2362                         m = static_cast<MeterSection*> (*i);
2363                         if (prev_m && m->minute() > minute) {
2364                                 next_m = m;
2365                                 break;
2366                         }
2367                         prev_m = m;
2368                 }
2369         }
2370
2371         double beat = prev_m->beat() + (ts.pulse_at_minute (minute) - prev_m->pulse()) * prev_m->note_divisor();
2372
2373         /* handle frame before first meter */
2374         if (minute < prev_m->minute()) {
2375                 beat = 0.0;
2376         }
2377         /* audio locked meters fake their beat */
2378         if (next_m && next_m->beat() < beat) {
2379                 beat = next_m->beat();
2380         }
2381
2382         beat = max (0.0, beat);
2383
2384         const double beats_in_ms = beat - prev_m->beat();
2385         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
2386         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
2387         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
2388         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
2389
2390         BBT_Time ret;
2391
2392         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
2393         ret.beats = (uint32_t) floor (remaining_beats);
2394         ret.bars = total_bars;
2395
2396         /* 0 0 0 to 1 1 0 - based mapping*/
2397         ++ret.bars;
2398         ++ret.beats;
2399
2400         if (ret.ticks >= BBT_Time::ticks_per_beat) {
2401                 ++ret.beats;
2402                 ret.ticks -= BBT_Time::ticks_per_beat;
2403         }
2404
2405         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
2406                 ++ret.bars;
2407                 ret.beats = 1;
2408         }
2409
2410         return ret;
2411 }
2412
2413 /** Returns the frame position corresponding to the supplied BBT time.
2414  * @param bbt the position in BBT time.
2415  * @return the frame position at bbt.
2416  *
2417  */
2418 framepos_t
2419 TempoMap::frame_at_bbt (const BBT_Time& bbt)
2420 {
2421         if (bbt.bars < 1) {
2422 #ifndef NDEBUG
2423                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
2424 #endif
2425                 return 0;
2426         }
2427
2428         if (bbt.beats < 1) {
2429                 throw std::logic_error ("beats are counted from one");
2430         }
2431
2432         double minute;
2433         {
2434                 Glib::Threads::RWLock::ReaderLock lm (lock);
2435                 minute = minute_at_bbt_locked (_metrics, bbt);
2436         }
2437
2438         return frame_at_minute (minute);
2439 }
2440
2441 /* meter & tempo section based */
2442 double
2443 TempoMap::minute_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
2444 {
2445         /* HOLD THE READER LOCK */
2446
2447         const double ret = minute_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
2448         return ret;
2449 }
2450
2451 /**
2452  * Returns the quarter-note beat position corresponding to the supplied frame.
2453  *
2454  * @param frame the position in frames.
2455  * @return The quarter-note position of the supplied frame. Ignores meter.
2456  *
2457 */
2458 double
2459 TempoMap::quarter_note_at_frame (const framepos_t frame) const
2460 {
2461         const double minute =  minute_at_frame (frame);
2462
2463         Glib::Threads::RWLock::ReaderLock lm (lock);
2464
2465         return pulse_at_minute_locked (_metrics, minute) * 4.0;
2466 }
2467
2468 double
2469 TempoMap::quarter_note_at_frame_rt (const framepos_t frame) const
2470 {
2471         const double minute =  minute_at_frame (frame);
2472
2473         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2474
2475         if (!lm.locked()) {
2476                 throw std::logic_error ("TempoMap::quarter_note_at_frame_rt() could not lock tempo map");
2477         }
2478
2479         return pulse_at_minute_locked (_metrics, minute) * 4.0;
2480 }
2481
2482 /**
2483  * Returns the frame position corresponding to the supplied quarter-note beat.
2484  *
2485  * @param quarter_note the quarter-note position.
2486  * @return the frame position of the supplied quarter-note. Ignores meter.
2487  *
2488  *
2489 */
2490 framepos_t
2491 TempoMap::frame_at_quarter_note (const double quarter_note) const
2492 {
2493         double minute;
2494         {
2495                 Glib::Threads::RWLock::ReaderLock lm (lock);
2496
2497                 minute = minute_at_pulse_locked (_metrics, quarter_note / 4.0);
2498         }
2499
2500         return frame_at_minute (minute);
2501 }
2502
2503 /** Returns the quarter-note beats corresponding to the supplied BBT (meter-based) beat.
2504  * @param beat The BBT (meter-based) beat.
2505  * @return The quarter-note position of the supplied BBT (meter-based) beat.
2506  *
2507  * a quarter-note may be compared with and assigned to Evoral::Beats.
2508  *
2509  */
2510 double
2511 TempoMap::quarter_note_at_beat (const double beat) const
2512 {
2513         Glib::Threads::RWLock::ReaderLock lm (lock);
2514
2515         return pulse_at_beat_locked (_metrics, beat) * 4.0;
2516 }
2517
2518 /** Returns the BBT (meter-based) beat position corresponding to the supplied quarter-note beats.
2519  * @param quarter_note The position in quarter-note beats.
2520  * @return the BBT (meter-based) beat position of the supplied quarter-note beats.
2521  *
2522  * a quarter-note is the musical unit of Evoral::Beats.
2523  *
2524  */
2525 double
2526 TempoMap::beat_at_quarter_note (const double quarter_note) const
2527 {
2528         Glib::Threads::RWLock::ReaderLock lm (lock);
2529
2530         return beat_at_pulse_locked (_metrics, quarter_note / 4.0);
2531 }
2532
2533 /** Returns the duration in frames between two supplied quarter-note beat positions.
2534  * @param start the first position in quarter-note beats.
2535  * @param end the end position in quarter-note beats.
2536  * @return the frame distance ober the quarter-note beats duration.
2537  *
2538  * use this rather than e.g.
2539  * frame_at-quarter_note (end_beats) - frame_at_quarter_note (start_beats).
2540  * frames_between_quarter_notes() doesn't round to audio frames as an intermediate step,
2541  *
2542  */
2543 framecnt_t
2544 TempoMap::frames_between_quarter_notes (const double start, const double end) const
2545 {
2546         double minutes;
2547
2548         {
2549                 Glib::Threads::RWLock::ReaderLock lm (lock);
2550                 minutes = minutes_between_quarter_notes_locked (_metrics, start, end);
2551         }
2552
2553         return frame_at_minute (minutes);
2554 }
2555
2556 double
2557 TempoMap::minutes_between_quarter_notes_locked (const Metrics& metrics, const double start, const double end) const
2558 {
2559
2560         return minute_at_pulse_locked (metrics, end / 4.0) - minute_at_pulse_locked (metrics, start / 4.0);
2561 }
2562
2563 double
2564 TempoMap::quarter_notes_between_frames (const framecnt_t start, const framecnt_t end) const
2565 {
2566         Glib::Threads::RWLock::ReaderLock lm (lock);
2567
2568         return quarter_notes_between_frames_locked (_metrics, start, end);
2569 }
2570
2571 double
2572 TempoMap::quarter_notes_between_frames_locked (const Metrics& metrics, const framecnt_t start, const framecnt_t end) const
2573 {
2574         const TempoSection* prev_t = 0;
2575
2576         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2577                 TempoSection* t;
2578
2579                 if ((*i)->is_tempo()) {
2580                         t = static_cast<TempoSection*> (*i);
2581                         if (!t->active()) {
2582                                 continue;
2583                         }
2584                         if (prev_t && t->frame() > start) {
2585                                 break;
2586                         }
2587                         prev_t = t;
2588                 }
2589         }
2590         assert (prev_t);
2591         const double start_qn = prev_t->pulse_at_frame (start);
2592
2593         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2594                 TempoSection* t;
2595
2596                 if ((*i)->is_tempo()) {
2597                         t = static_cast<TempoSection*> (*i);
2598                         if (!t->active()) {
2599                                 continue;
2600                         }
2601                         if (prev_t && t->frame() > end) {
2602                                 break;
2603                         }
2604                         prev_t = t;
2605                 }
2606         }
2607         const double end_qn = prev_t->pulse_at_frame (end);
2608
2609         return (end_qn - start_qn) * 4.0;
2610 }
2611
2612 bool
2613 TempoMap::check_solved (const Metrics& metrics) const
2614 {
2615         TempoSection* prev_t = 0;
2616         MeterSection* prev_m = 0;
2617
2618         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2619                 TempoSection* t;
2620                 MeterSection* m;
2621                 if ((*i)->is_tempo()) {
2622                         t = static_cast<TempoSection*> (*i);
2623                         if (!t->active()) {
2624                                 continue;
2625                         }
2626                         if (prev_t) {
2627                                 /* check ordering */
2628                                 if ((t->minute() <= prev_t->minute()) || (t->pulse() <= prev_t->pulse())) {
2629                                         return false;
2630                                 }
2631
2632                                 /* precision check ensures tempo and frames align.*/
2633                                 if (t->frame() != frame_at_minute (prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()))) {
2634                                         if (!t->locked_to_meter()) {
2635                                                 return false;
2636                                         }
2637                                 }
2638
2639                                 /* gradient limit - who knows what it should be?
2640                                    things are also ok (if a little chaotic) without this
2641                                 */
2642                                 if (fabs (prev_t->c()) > 1000.0) {
2643                                         //std::cout << "c : " << prev_t->c() << std::endl;
2644                                         return false;
2645                                 }
2646                         }
2647                         prev_t = t;
2648                 }
2649
2650                 if (!(*i)->is_tempo()) {
2651                         m = static_cast<MeterSection*> (*i);
2652                         if (prev_m && m->position_lock_style() == AudioTime) {
2653                                 const TempoSection* t = &tempo_section_at_minute_locked (metrics, minute_at_frame (m->frame() - 1));
2654                                 const framepos_t nascent_m_frame = frame_at_minute (t->minute_at_pulse (m->pulse()));
2655                                 /* Here we check that a preceding section of music doesn't overlap a subsequent one.
2656                                 */
2657                                 if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
2658                                         return false;
2659                                 }
2660                         }
2661
2662                         prev_m = m;
2663                 }
2664
2665         }
2666
2667         return true;
2668 }
2669
2670 bool
2671 TempoMap::set_active_tempi (const Metrics& metrics, const framepos_t& frame)
2672 {
2673         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2674                 TempoSection* t;
2675                 if ((*i)->is_tempo()) {
2676                         t = static_cast<TempoSection*> (*i);
2677                         if (t->locked_to_meter()) {
2678                                 t->set_active (true);
2679                         } else if (t->position_lock_style() == AudioTime) {
2680                                 if (t->frame() < frame) {
2681                                         t->set_active (false);
2682                                         t->set_pulse (-1.0);
2683                                 } else if (t->frame() > frame) {
2684                                         t->set_active (true);
2685                                 } else if (t->frame() == frame) {
2686                                         return false;
2687                                 }
2688                         }
2689                 }
2690         }
2691         return true;
2692 }
2693
2694 bool
2695 TempoMap::solve_map_minute (Metrics& imaginary, TempoSection* section, const double& minute)
2696 {
2697         TempoSection* prev_t = 0;
2698         TempoSection* section_prev = 0;
2699         double first_m_minute = 0.0;
2700         const bool sml = section->locked_to_meter();
2701
2702         /* can't move a tempo before the first meter */
2703         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2704                 MeterSection* m;
2705                 if (!(*i)->is_tempo()) {
2706                         m = static_cast<MeterSection*> (*i);
2707                         if (m->initial()) {
2708                                 first_m_minute = m->minute();
2709                                 break;
2710                         }
2711                 }
2712         }
2713         if (!section->initial() && minute <= first_m_minute) {
2714                 return false;
2715         }
2716
2717         section->set_active (true);
2718         section->set_minute (minute);
2719
2720         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2721                 TempoSection* t;
2722                 if ((*i)->is_tempo()) {
2723                         t = static_cast<TempoSection*> (*i);
2724
2725                         if (!t->active()) {
2726                                 continue;
2727                         }
2728
2729                         if (prev_t) {
2730
2731                                 if (t == section) {
2732                                         continue;
2733                                 }
2734
2735                                 if (t->frame() == frame_at_minute (minute)) {
2736                                         return false;
2737                                 }
2738
2739                                 const bool tlm = t->position_lock_style() == MusicTime;
2740
2741                                 if (prev_t && !section_prev && ((sml && tlm && t->pulse() > section->pulse()) || (!tlm && t->minute() > minute))) {
2742                                         section_prev = prev_t;
2743
2744                                         section_prev->set_c (section_prev->compute_c_minute (section_prev->end_note_types_per_minute(), minute));
2745                                         if (!section->locked_to_meter()) {
2746                                                 section->set_pulse (section_prev->pulse_at_ntpm (section_prev->end_note_types_per_minute(), minute));
2747                                         }
2748                                         prev_t = section;
2749                                 }
2750
2751                                 if (t->position_lock_style() == MusicTime) {
2752                                         prev_t->set_c (prev_t->compute_c_pulse (prev_t->end_note_types_per_minute(), t->pulse()));
2753                                         t->set_minute (prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()));
2754                                 } else {
2755                                         prev_t->set_c (prev_t->compute_c_minute (prev_t->end_note_types_per_minute(), t->minute()));
2756                                         if (!t->locked_to_meter()) {
2757                                                 t->set_pulse (prev_t->pulse_at_ntpm (prev_t->end_note_types_per_minute(), t->minute()));
2758                                         }
2759                                 }
2760                         }
2761                         prev_t = t;
2762                 }
2763         }
2764
2765 #if (0)
2766         recompute_tempi (imaginary);
2767
2768         if (check_solved (imaginary)) {
2769                 return true;
2770         } else {
2771                 dunp (imaginary, std::cout);
2772         }
2773 #endif
2774
2775         MetricSectionFrameSorter fcmp;
2776         imaginary.sort (fcmp);
2777
2778         recompute_tempi (imaginary);
2779
2780         if (check_solved (imaginary)) {
2781                 return true;
2782         }
2783
2784         return false;
2785 }
2786
2787 bool
2788 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2789 {
2790         TempoSection* prev_t = 0;
2791         TempoSection* section_prev = 0;
2792
2793         section->set_pulse (pulse);
2794
2795         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2796                 TempoSection* t;
2797                 if ((*i)->is_tempo()) {
2798                         t = static_cast<TempoSection*> (*i);
2799                         if (!t->active()) {
2800                                 continue;
2801                         }
2802                         if (t->initial()) {
2803                                 t->set_pulse (0.0);
2804                                 prev_t = t;
2805                                 continue;
2806                         }
2807                         if (prev_t) {
2808                                 if (t == section) {
2809                                         section_prev = prev_t;
2810                                         continue;
2811                                 }
2812
2813                                 if (t->position_lock_style() == MusicTime) {
2814                                         prev_t->set_c (prev_t->compute_c_pulse (prev_t->end_note_types_per_minute(), t->pulse()));
2815                                         t->set_minute (prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()));
2816                                 } else {
2817                                         prev_t->set_c (prev_t->compute_c_minute (prev_t->end_note_types_per_minute(), t->minute()));
2818                                         if (!t->locked_to_meter()) {
2819                                                 t->set_pulse (prev_t->pulse_at_ntpm (prev_t->end_note_types_per_minute(), t->minute()));
2820                                         }
2821                                 }
2822                         }
2823                         prev_t = t;
2824                 }
2825         }
2826
2827         if (section_prev) {
2828                 section_prev->set_c (section_prev->compute_c_pulse (section_prev->end_note_types_per_minute(), pulse));
2829                 section->set_minute (section_prev->minute_at_ntpm (section_prev->end_note_types_per_minute(), pulse));
2830         }
2831
2832 #if (0)
2833         recompute_tempi (imaginary);
2834
2835         if (check_solved (imaginary)) {
2836                 return true;
2837         } else {
2838                 dunp (imaginary, std::cout);
2839         }
2840 #endif
2841
2842         MetricSectionSorter cmp;
2843         imaginary.sort (cmp);
2844
2845         recompute_tempi (imaginary);
2846         /* Reordering
2847          * XX need a restriction here, but only for this case,
2848          * as audio locked tempos don't interact in the same way.
2849          *
2850          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2851          * e.g.
2852          * |50 bpm                        |250 bpm |60 bpm
2853          *                drag 250 to the pulse after 60->
2854          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2855          */
2856         if (check_solved (imaginary)) {
2857                 return true;
2858         }
2859
2860         return false;
2861 }
2862
2863 bool
2864 TempoMap::solve_map_minute (Metrics& imaginary, MeterSection* section, const double& minute)
2865 {
2866         /* disallow moving first meter past any subsequent one, and any initial meter before the first one */
2867         const MeterSection* other =  &meter_section_at_minute_locked (imaginary, minute);
2868         if ((section->initial() && !other->initial()) || (other->initial() && !section->initial() && other->minute() >= minute)) {
2869                 return false;
2870         }
2871
2872         if (section->initial()) {
2873                 /* lock the first tempo to our first meter */
2874                 if (!set_active_tempi (imaginary, frame_at_minute (minute))) {
2875                         return false;
2876                 }
2877         }
2878
2879         TempoSection* meter_locked_tempo = 0;
2880
2881         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2882                 TempoSection* t;
2883                 if ((*ii)->is_tempo()) {
2884                         t = static_cast<TempoSection*> (*ii);
2885                         if (t->locked_to_meter() && t->frame() == section->frame()) {
2886                                 meter_locked_tempo = t;
2887                                 break;
2888                         }
2889                 }
2890         }
2891
2892         if (!meter_locked_tempo) {
2893                 return false;
2894         }
2895
2896         MeterSection* prev_m = 0;
2897         Metrics future_map;
2898         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2899         bool solved = false;
2900
2901         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2902                 MeterSection* m;
2903                 if (!(*i)->is_tempo()) {
2904                         m = static_cast<MeterSection*> (*i);
2905                         if (m == section){
2906                                 if (prev_m && !section->initial()) {
2907                                         const double beats = (pulse_at_minute_locked (imaginary, minute) - prev_m->pulse()) * prev_m->note_divisor();
2908                                         if (beats + prev_m->beat() < section->beat()) {
2909                                                 /* set the section pulse according to its musical position,
2910                                                  * as an earlier time than this has been requested.
2911                                                 */
2912                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2913                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2914
2915                                                 tempo_copy->set_position_lock_style (MusicTime);
2916                                                 if ((solved = solve_map_pulse (future_map, tempo_copy, new_pulse))) {
2917                                                         meter_locked_tempo->set_position_lock_style (MusicTime);
2918                                                         section->set_position_lock_style (MusicTime);
2919                                                         section->set_pulse (new_pulse);
2920                                                         solve_map_pulse (imaginary, meter_locked_tempo, new_pulse);
2921                                                         meter_locked_tempo->set_position_lock_style (AudioTime);
2922                                                         section->set_position_lock_style (AudioTime);
2923                                                         section->set_minute (meter_locked_tempo->minute());
2924
2925                                                 } else {
2926                                                         solved = false;
2927                                                 }
2928
2929                                                 Metrics::const_iterator d = future_map.begin();
2930                                                 while (d != future_map.end()) {
2931                                                         delete (*d);
2932                                                         ++d;
2933                                                 }
2934
2935                                                 if (!solved) {
2936                                                         return false;
2937                                                 }
2938                                         } else {
2939                                                 /* all is ok. set section's locked tempo if allowed.
2940                                                    possibly disallow if there is an adjacent audio-locked tempo.
2941                                                    XX this check could possibly go. its never actually happened here.
2942                                                 */
2943                                                 MeterSection* meter_copy = const_cast<MeterSection*>
2944                                                         (&meter_section_at_minute_locked (future_map, section->minute()));
2945
2946                                                 meter_copy->set_minute (minute);
2947
2948                                                 if ((solved = solve_map_minute (future_map, tempo_copy, minute))) {
2949                                                         section->set_minute (minute);
2950                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2951                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2952                                                         solve_map_minute (imaginary, meter_locked_tempo, minute);
2953                                                 } else {
2954                                                         solved = false;
2955                                                 }
2956
2957                                                 Metrics::const_iterator d = future_map.begin();
2958                                                 while (d != future_map.end()) {
2959                                                         delete (*d);
2960                                                         ++d;
2961                                                 }
2962
2963                                                 if (!solved) {
2964                                                         return false;
2965                                                 }
2966                                         }
2967                                 } else {
2968                                         /* initial (first meter atm) */
2969
2970                                         tempo_copy->set_minute (minute);
2971                                         tempo_copy->set_pulse (0.0);
2972
2973                                         if ((solved = solve_map_minute (future_map, tempo_copy, minute))) {
2974                                                 section->set_minute (minute);
2975                                                 meter_locked_tempo->set_minute (minute);
2976                                                 meter_locked_tempo->set_pulse (0.0);
2977                                                 solve_map_minute (imaginary, meter_locked_tempo, minute);
2978                                         } else {
2979                                                 solved = false;
2980                                         }
2981
2982                                         Metrics::const_iterator d = future_map.begin();
2983                                         while (d != future_map.end()) {
2984                                                 delete (*d);
2985                                                 ++d;
2986                                         }
2987
2988                                         if (!solved) {
2989                                                 return false;
2990                                         }
2991
2992                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2993                                         section->set_beat (b_bbt);
2994                                         section->set_pulse (0.0);
2995
2996                                 }
2997                                 break;
2998                         }
2999
3000                         prev_m = m;
3001                 }
3002         }
3003
3004         MetricSectionFrameSorter fcmp;
3005         imaginary.sort (fcmp);
3006
3007         recompute_meters (imaginary);
3008
3009         return true;
3010 }
3011
3012 bool
3013 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
3014 {
3015         /* disallow setting section to an existing meter's bbt */
3016         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
3017                 MeterSection* m;
3018                 if (!(*i)->is_tempo()) {
3019                         m = static_cast<MeterSection*> (*i);
3020                         if (m != section && m->bbt().bars == when.bars) {
3021                                 return false;
3022                         }
3023                 }
3024         }
3025
3026         MeterSection* prev_m = 0;
3027         MeterSection* section_prev = 0;
3028
3029         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
3030                 MeterSection* m;
3031                 if (!(*i)->is_tempo()) {
3032                         m = static_cast<MeterSection*> (*i);
3033
3034                         if (m == section) {
3035                                 continue;
3036                         }
3037
3038                         pair<double, BBT_Time> b_bbt;
3039                         double new_pulse = 0.0;
3040
3041                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
3042                                 section_prev = prev_m;
3043
3044                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
3045                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
3046                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
3047
3048                                 section->set_beat (b_bbt);
3049                                 section->set_pulse (pulse);
3050                                 section->set_minute (minute_at_pulse_locked (imaginary, pulse));
3051                                 prev_m = section;
3052                         }
3053
3054                         if (m->position_lock_style() == AudioTime) {
3055                                 TempoSection* meter_locked_tempo = 0;
3056
3057                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
3058                                         TempoSection* t;
3059                                         if ((*ii)->is_tempo()) {
3060                                                 t = static_cast<TempoSection*> (*ii);
3061                                                 if (t->locked_to_meter() && t->frame() == m->frame()) {
3062                                                         meter_locked_tempo = t;
3063                                                         break;
3064                                                 }
3065                                         }
3066                                 }
3067
3068                                 if (!meter_locked_tempo) {
3069                                         return false;
3070                                 }
3071
3072                                 if (prev_m) {
3073                                         double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
3074
3075                                         if (beats + prev_m->beat() != m->beat()) {
3076                                                 /* tempo/ meter change caused a change in beat (bar). */
3077
3078                                                 /* the user has requested that the previous section of music overlaps this one.
3079                                                    we have no choice but to change the bar number here, as being locked to audio means
3080                                                    we must stay where we are on the timeline.
3081                                                 */
3082                                                 beats = m->beat() - prev_m->beat();
3083                                                 b_bbt = make_pair (beats + prev_m->beat()
3084                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
3085                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
3086
3087                                         } else if (!m->initial()) {
3088                                                 b_bbt = make_pair (m->beat(), m->bbt());
3089                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
3090                                         }
3091                                 } else {
3092                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3093                                 }
3094
3095                                 meter_locked_tempo->set_pulse (new_pulse);
3096                                 m->set_beat (b_bbt);
3097                                 m->set_pulse (new_pulse);
3098
3099                         } else {
3100                                 /* MusicTime */
3101                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
3102                                 if (beats + prev_m->beat() != m->beat()) {
3103                                         /* tempo/ meter change caused a change in beat (bar). */
3104                                         b_bbt = make_pair (beats + prev_m->beat()
3105                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
3106                                 } else {
3107                                         b_bbt = make_pair (beats + prev_m->beat()
3108                                                            , m->bbt());
3109                                 }
3110                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
3111                                 m->set_beat (b_bbt);
3112                                 m->set_pulse (new_pulse);
3113                                 m->set_minute (minute_at_pulse_locked (imaginary, new_pulse));
3114                         }
3115
3116                         prev_m = m;
3117                 }
3118         }
3119
3120         if (!section_prev) {
3121
3122                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
3123                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
3124                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
3125
3126                 section->set_beat (b_bbt);
3127                 section->set_pulse (pulse);
3128                 section->set_minute (minute_at_pulse_locked (imaginary, pulse));
3129         }
3130
3131         MetricSectionSorter cmp;
3132         imaginary.sort (cmp);
3133
3134         recompute_meters (imaginary);
3135
3136         return true;
3137 }
3138
3139 /** places a copy of _metrics into copy and returns a pointer
3140  *  to section's equivalent in copy.
3141  */
3142 TempoSection*
3143 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
3144 {
3145         TempoSection* ret = 0;
3146
3147         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3148                 TempoSection* t;
3149                 MeterSection* m;
3150                 if ((*i)->is_tempo()) {
3151                         t = static_cast<TempoSection*> (*i);
3152                         if (t == section) {
3153                                 ret = new TempoSection (*t);
3154                                 copy.push_back (ret);
3155                                 continue;
3156                         }
3157
3158                         TempoSection* cp = new TempoSection (*t);
3159                         copy.push_back (cp);
3160                 }
3161                 if (!(*i)->is_tempo()) {
3162                         m = static_cast<MeterSection *> (*i);
3163                         MeterSection* cp = new MeterSection (*m);
3164                         copy.push_back (cp);
3165                 }
3166         }
3167
3168         return ret;
3169 }
3170
3171 MeterSection*
3172 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
3173 {
3174         MeterSection* ret = 0;
3175
3176         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3177                 TempoSection* t;
3178                 MeterSection* m;
3179                 if ((*i)->is_tempo()) {
3180                         t = static_cast<TempoSection*> (*i);
3181                         TempoSection* cp = new TempoSection (*t);
3182                         copy.push_back (cp);
3183                 }
3184
3185                 if (!(*i)->is_tempo()) {
3186                         m = static_cast<MeterSection *> (*i);
3187                         if (m == section) {
3188                                 ret = new MeterSection (*m);
3189                                 copy.push_back (ret);
3190                                 continue;
3191                         }
3192                         MeterSection* cp = new MeterSection (*m);
3193                         copy.push_back (cp);
3194                 }
3195         }
3196
3197         return ret;
3198 }
3199
3200 /** answers the question "is this a valid beat position for this tempo section?".
3201  *  it returns true if the tempo section can be moved to the requested bbt position,
3202  *  leaving the tempo map in a solved state.
3203  * @param ts the tempo section to be moved
3204  * @param bbt the requested new position for the tempo section
3205  * @return true if the tempo section can be moved to the position, otherwise false.
3206  */
3207 bool
3208 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
3209 {
3210         Metrics copy;
3211         TempoSection* tempo_copy = 0;
3212
3213         {
3214                 Glib::Threads::RWLock::ReaderLock lm (lock);
3215                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
3216                 if (!tempo_copy) {
3217                         return false;
3218                 }
3219         }
3220
3221         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
3222
3223         Metrics::const_iterator d = copy.begin();
3224         while (d != copy.end()) {
3225                 delete (*d);
3226                 ++d;
3227         }
3228
3229         return ret;
3230 }
3231
3232 /**
3233 * 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,
3234 * taking any possible reordering as a consequence of this into account.
3235 * @param section - the section to be altered
3236 * @param bbt - the BBT time  where the altered tempo will fall
3237 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
3238 */
3239 pair<double, framepos_t>
3240 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
3241 {
3242         Metrics future_map;
3243         pair<double, framepos_t> ret = make_pair (0.0, 0);
3244
3245         Glib::Threads::RWLock::ReaderLock lm (lock);
3246
3247         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
3248
3249         const double beat = beat_at_bbt_locked (future_map, bbt);
3250
3251         if (section->position_lock_style() == AudioTime) {
3252                 tempo_copy->set_position_lock_style (MusicTime);
3253         }
3254
3255         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
3256                 ret.first = tempo_copy->pulse();
3257                 ret.second = tempo_copy->frame();
3258         } else {
3259                 ret.first = section->pulse();
3260                 ret.second = section->frame();
3261         }
3262
3263         Metrics::const_iterator d = future_map.begin();
3264         while (d != future_map.end()) {
3265                 delete (*d);
3266                 ++d;
3267         }
3268         return ret;
3269 }
3270
3271 /** moves a TempoSection to a specified position.
3272  * @param ts - the section to be moved
3273  * @param frame - the new position in frames for the tempo
3274  * @param sub_num - the snap division to use if using musical time.
3275  *
3276  * if sub_num is non-zero, the frame position is used to calculate an exact
3277  * musical position.
3278  * sub_num   | effect
3279  * -1        | snap to bars (meter-based)
3280  *  0        | no snap - use audio frame for musical position
3281  *  1        | snap to meter-based (BBT) beat
3282  * >1        | snap to quarter-note subdivision (i.e. 4 will snap to sixteenth notes)
3283  *
3284  * this follows the snap convention in the gui.
3285  * if sub_num is zero, the musical position will be taken from the supplied frame.
3286  */
3287 void
3288 TempoMap::gui_set_tempo_position (TempoSection* ts, const framepos_t& frame, const int& sub_num)
3289 {
3290         Metrics future_map;
3291
3292         if (ts->position_lock_style() == MusicTime) {
3293                 {
3294                         /* if we're snapping to a musical grid, set the pulse exactly instead of via the supplied frame. */
3295                         Glib::Threads::RWLock::WriterLock lm (lock);
3296                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3297
3298                         tempo_copy->set_position_lock_style (AudioTime);
3299
3300                         if (solve_map_minute (future_map, tempo_copy, minute_at_frame (frame))) {
3301                                 const double beat = exact_beat_at_frame_locked (future_map, frame, sub_num);
3302                                 const double pulse = pulse_at_beat_locked (future_map, beat);
3303
3304                                 if (solve_map_pulse (future_map, tempo_copy, pulse)) {
3305                                         solve_map_pulse (_metrics, ts, pulse);
3306                                         recompute_meters (_metrics);
3307                                 }
3308                         }
3309                 }
3310
3311         } else {
3312
3313                 {
3314                         Glib::Threads::RWLock::WriterLock lm (lock);
3315                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3316
3317                         if (solve_map_minute (future_map, tempo_copy, minute_at_frame (frame))) {
3318                                 if (sub_num != 0) {
3319                                         /* We're moving the object that defines the grid while snapping to it...
3320                                          * Placing the ts at the beat corresponding to the requested frame may shift the
3321                                          * grid in such a way that the mouse is left hovering over a completerly different division,
3322                                          * causing jittering when the mouse next moves (esp. large tempo deltas).
3323                                          *
3324                                          * This alters the snap behaviour slightly in that we snap to beat divisions
3325                                          * in the future map rather than the existing one.
3326                                          */
3327                                         const double qn = exact_qn_at_frame_locked (future_map, frame, sub_num);
3328                                         const framepos_t snapped_frame = frame_at_minute (minute_at_pulse_locked (future_map, qn / 4.0));
3329
3330                                         if (solve_map_minute (future_map, tempo_copy, minute_at_frame (snapped_frame))) {
3331                                                 solve_map_minute (_metrics, ts, minute_at_frame (snapped_frame));
3332                                                 ts->set_pulse (qn / 4.0);
3333                                                 recompute_meters (_metrics);
3334                                         }
3335                                 } else {
3336                                         solve_map_minute (_metrics, ts, minute_at_frame (frame));
3337                                         recompute_meters (_metrics);
3338                                 }
3339                         }
3340                 }
3341         }
3342
3343         Metrics::const_iterator d = future_map.begin();
3344         while (d != future_map.end()) {
3345                 delete (*d);
3346                 ++d;
3347         }
3348
3349         MetricPositionChanged (PropertyChange ()); // Emit Signal
3350 }
3351
3352 /** moves a MeterSection to a specified position.
3353  * @param ms - the section to be moved
3354  * @param frame - the new position in frames for the meter
3355  *
3356  * as a meter cannot snap to anything but bars,
3357  * the supplied frame is rounded to the nearest bar, possibly
3358  * leaving the meter position unchanged.
3359  */
3360 void
3361 TempoMap::gui_set_meter_position (MeterSection* ms, const framepos_t& frame)
3362 {
3363         Metrics future_map;
3364
3365         if (ms->position_lock_style() == AudioTime) {
3366
3367                 {
3368                         Glib::Threads::RWLock::WriterLock lm (lock);
3369                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
3370
3371                         if (solve_map_minute (future_map, copy, minute_at_frame (frame))) {
3372                                 solve_map_minute (_metrics, ms, minute_at_frame (frame));
3373                                 recompute_tempi (_metrics);
3374                         }
3375                 }
3376         } else {
3377                 {
3378                         Glib::Threads::RWLock::WriterLock lm (lock);
3379                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
3380
3381                         const double beat = beat_at_minute_locked (_metrics, minute_at_frame (frame));
3382                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
3383
3384                         if (solve_map_bbt (future_map, copy, bbt)) {
3385                                 solve_map_bbt (_metrics, ms, bbt);
3386                                 recompute_tempi (_metrics);
3387                         }
3388                 }
3389         }
3390
3391         Metrics::const_iterator d = future_map.begin();
3392         while (d != future_map.end()) {
3393                 delete (*d);
3394                 ++d;
3395         }
3396
3397         MetricPositionChanged (PropertyChange ()); // Emit Signal
3398 }
3399
3400 bool
3401 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
3402 {
3403         Metrics future_map;
3404         bool can_solve = false;
3405         {
3406                 Glib::Threads::RWLock::WriterLock lm (lock);
3407                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3408
3409                 if (tempo_copy->type() == TempoSection::Constant) {
3410                         tempo_copy->set_end_note_types_per_minute (bpm.note_types_per_minute());
3411                         tempo_copy->set_note_types_per_minute (bpm.note_types_per_minute());
3412                 } else {
3413                         tempo_copy->set_note_types_per_minute (bpm.note_types_per_minute());
3414                         tempo_copy->set_end_note_types_per_minute (bpm.end_note_types_per_minute());
3415                 }
3416
3417                 if (ts->clamped()) {
3418                         TempoSection* prev = 0;
3419                         if ((prev = previous_tempo_section_locked (future_map, tempo_copy)) != 0) {
3420                                 prev->set_end_note_types_per_minute (tempo_copy->note_types_per_minute());
3421                         }
3422                 }
3423
3424                 recompute_tempi (future_map);
3425
3426                 if (check_solved (future_map)) {
3427                         if (ts->type() == TempoSection::Constant) {
3428                                 ts->set_end_note_types_per_minute (bpm.note_types_per_minute());
3429                                 ts->set_note_types_per_minute (bpm.note_types_per_minute());
3430                         } else {
3431                                 ts->set_end_note_types_per_minute (bpm.end_note_types_per_minute());
3432                                 ts->set_note_types_per_minute (bpm.note_types_per_minute());
3433                         }
3434
3435                         if (ts->clamped()) {
3436                                 TempoSection* prev = 0;
3437                                 if ((prev = previous_tempo_section_locked (_metrics, ts)) != 0) {
3438                                         prev->set_end_note_types_per_minute (ts->note_types_per_minute());
3439                                 }
3440                         }
3441
3442                         recompute_map (_metrics);
3443                         can_solve = true;
3444                 }
3445         }
3446
3447         Metrics::const_iterator d = future_map.begin();
3448         while (d != future_map.end()) {
3449                 delete (*d);
3450                 ++d;
3451         }
3452         if (can_solve) {
3453                 MetricPositionChanged (PropertyChange ()); // Emit Signal
3454         }
3455
3456         return can_solve;
3457 }
3458
3459 void
3460 TempoMap::gui_stretch_tempo (TempoSection* ts, const framepos_t frame, const framepos_t end_frame)
3461 {
3462         /*
3463           Ts (future prev_t)   Tnext
3464           |                    |
3465           |     [drag^]        |
3466           |----------|----------
3467                 e_f  qn_beats(frame)
3468         */
3469
3470         Metrics future_map;
3471
3472         {
3473                 Glib::Threads::RWLock::WriterLock lm (lock);
3474
3475                 if (!ts) {
3476                         return;
3477                 }
3478
3479                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
3480
3481                 if (!prev_t) {
3482                         return;
3483                 }
3484
3485                 /* minimum allowed measurement distance in frames */
3486                 framepos_t const min_dframe = 2;
3487
3488                 double new_bpm;
3489                 if (prev_t->clamped()) {
3490                         TempoSection* next_t = next_tempo_section_locked (future_map, prev_t);
3491                         TempoSection* prev_to_prev_t = previous_tempo_section_locked (future_map, prev_t);
3492                         /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
3493                            constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
3494                         */
3495                         double contribution = 0.0;
3496                         if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3497                                 contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
3498                         }
3499                         framepos_t const fr_off = (end_frame - frame);
3500                         const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
3501
3502                         if (frame > prev_to_prev_t->frame() + min_dframe && (frame + prev_t_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
3503                                 new_bpm = prev_t->note_types_per_minute() * ((frame - prev_to_prev_t->frame())
3504                                                                                      / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
3505                         } else {
3506                                 new_bpm = prev_t->note_types_per_minute();
3507                         }
3508                 } else {
3509                         if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
3510
3511                                 new_bpm = prev_t->note_types_per_minute() * ((frame - prev_t->frame())
3512                                                                              / (double) (end_frame - prev_t->frame()));
3513                         } else {
3514                                 new_bpm = prev_t->note_types_per_minute();
3515                         }
3516
3517                         new_bpm = min (new_bpm, (double) 1000.0);
3518                 }
3519                 /* don't clamp and proceed here.
3520                    testing has revealed that this can go negative,
3521                    which is an entirely different thing to just being too low.
3522                 */
3523
3524                 if (new_bpm < 0.5) {
3525                         goto out;
3526                 }
3527
3528                 if (prev_t && prev_t->type() == TempoSection::Ramp) {
3529                         prev_t->set_note_types_per_minute (new_bpm);
3530                 } else {
3531                         prev_t->set_end_note_types_per_minute (new_bpm);
3532                         prev_t->set_note_types_per_minute (new_bpm);
3533                 }
3534
3535                 if (prev_t->clamped()) {
3536                         TempoSection* prev = 0;
3537                         if ((prev = previous_tempo_section_locked (future_map, prev_t)) != 0) {
3538                                 prev->set_end_note_types_per_minute (prev_t->note_types_per_minute());
3539                         }
3540                 }
3541
3542                 recompute_tempi (future_map);
3543                 recompute_meters (future_map);
3544
3545                 if (check_solved (future_map)) {
3546                         if (prev_t && prev_t->type() == TempoSection::Ramp) {
3547                                 ts->set_note_types_per_minute (new_bpm);
3548                         } else {
3549                                 ts->set_end_note_types_per_minute (new_bpm);
3550                                 ts->set_note_types_per_minute (new_bpm);
3551                         }
3552                         if (ts->clamped()) {
3553                                 TempoSection* prev = 0;
3554                                 if ((prev = previous_tempo_section_locked (_metrics, ts)) != 0) {
3555                                         prev->set_end_note_types_per_minute (ts->note_types_per_minute());
3556                                 }
3557                         }
3558                         recompute_tempi (_metrics);
3559                         recompute_meters (_metrics);
3560                 }
3561         }
3562
3563
3564 out:
3565         Metrics::const_iterator d = future_map.begin();
3566         while (d != future_map.end()) {
3567                 delete (*d);
3568                 ++d;
3569         }
3570         MetricPositionChanged (PropertyChange ()); // Emit Signal
3571
3572
3573 }
3574 void
3575 TempoMap::gui_stretch_tempo_end (TempoSection* ts, const framepos_t frame, const framepos_t end_frame)
3576 {
3577         /*
3578           Ts (future prev_t)   Tnext
3579           |                    |
3580           |     [drag^]        |
3581           |----------|----------
3582                 e_f  qn_beats(frame)
3583         */
3584
3585         Metrics future_map;
3586
3587         {
3588                 Glib::Threads::RWLock::WriterLock lm (lock);
3589
3590                 if (!ts) {
3591                         return;
3592                 }
3593
3594                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
3595
3596                 if (!prev_t) {
3597                         return;
3598                 }
3599
3600                 /* minimum allowed measurement distance in frames */
3601                 framepos_t const min_dframe = 2;
3602                 double new_bpm;
3603
3604                 if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
3605                         new_bpm = prev_t->end_note_types_per_minute() * ((prev_t->frame() - frame)
3606                                                                                  / (double) (prev_t->frame() - end_frame));
3607                 } else {
3608                         new_bpm = prev_t->end_note_types_per_minute();
3609                 }
3610
3611                 new_bpm = min (new_bpm, (double) 1000.0);
3612
3613                 if (new_bpm < 0.5) {
3614                         goto out;
3615                 }
3616
3617                 prev_t->set_end_note_types_per_minute (new_bpm);
3618
3619                 TempoSection* next = 0;
3620                 if ((next = next_tempo_section_locked (future_map, prev_t)) != 0) {
3621                         if (next->clamped()) {
3622                                 next->set_note_types_per_minute (prev_t->end_note_types_per_minute());
3623                         }
3624                 }
3625
3626                 recompute_tempi (future_map);
3627                 recompute_meters (future_map);
3628
3629                 if (check_solved (future_map)) {
3630                         ts->set_end_note_types_per_minute (new_bpm);
3631
3632                         TempoSection* true_next = 0;
3633                         if ((true_next = next_tempo_section_locked (_metrics, ts)) != 0) {
3634                                 if (true_next->clamped()) {
3635                                         true_next->set_note_types_per_minute (ts->end_note_types_per_minute());
3636                                 }
3637                         }
3638
3639                         recompute_tempi (_metrics);
3640                         recompute_meters (_metrics);
3641                 }
3642         }
3643
3644
3645 out:
3646         Metrics::const_iterator d = future_map.begin();
3647         while (d != future_map.end()) {
3648                 delete (*d);
3649                 ++d;
3650         }
3651
3652         MetricPositionChanged (PropertyChange ()); // Emit Signal
3653 }
3654
3655 bool
3656 TempoMap::gui_twist_tempi (TempoSection* ts, const Tempo& bpm, const framepos_t frame, const framepos_t end_frame)
3657 {
3658         TempoSection* next_t = 0;
3659         TempoSection* next_to_next_t = 0;
3660         Metrics future_map;
3661         bool can_solve = false;
3662
3663         /* minimum allowed measurement distance in frames */
3664         framepos_t const min_dframe = 2;
3665
3666         {
3667                 Glib::Threads::RWLock::WriterLock lm (lock);
3668                 if (!ts) {
3669                         return false;
3670                 }
3671
3672                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3673                 TempoSection* prev_to_prev_t = 0;
3674                 const frameoffset_t fr_off = end_frame - frame;
3675
3676                 if (!tempo_copy) {
3677                         return false;
3678                 }
3679
3680                 if (tempo_copy->pulse() > 0.0) {
3681                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_minute_locked (future_map, minute_at_frame (tempo_copy->frame() - 1)));
3682                 }
3683
3684                 for (Metrics::const_iterator i = future_map.begin(); i != future_map.end(); ++i) {
3685                         if ((*i)->is_tempo() && (*i)->minute() >  tempo_copy->minute()) {
3686                                 next_t = static_cast<TempoSection*> (*i);
3687                                 break;
3688                         }
3689                 }
3690
3691                 if (!next_t) {
3692                         return false;
3693                 }
3694
3695                 for (Metrics::const_iterator i = future_map.begin(); i != future_map.end(); ++i) {
3696                         if ((*i)->is_tempo() && (*i)->minute() >  next_t->minute()) {
3697                                 next_to_next_t = static_cast<TempoSection*> (*i);
3698                                 break;
3699                         }
3700                 }
3701
3702                 if (!next_to_next_t) {
3703                         return false;
3704                 }
3705
3706                 double prev_contribution = 0.0;
3707
3708                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3709                         prev_contribution = (tempo_copy->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
3710                 }
3711
3712                 const frameoffset_t tempo_copy_frame_contribution = fr_off - (prev_contribution * (double) fr_off);
3713
3714
3715                 framepos_t old_tc_minute = tempo_copy->minute();
3716                 double old_next_minute = next_t->minute();
3717                 double old_next_to_next_minute = next_to_next_t->minute();
3718
3719                 double new_bpm;
3720                 double new_next_bpm;
3721                 double new_copy_end_bpm;
3722
3723                 if (frame > tempo_copy->frame() + min_dframe && (frame + tempo_copy_frame_contribution) > tempo_copy->frame() + min_dframe) {
3724                         new_bpm = tempo_copy->note_types_per_minute() * ((frame - tempo_copy->frame())
3725                                                                                        / (double) (end_frame - tempo_copy->frame()));
3726                 } else {
3727                         new_bpm = tempo_copy->note_types_per_minute();
3728                 }
3729
3730                 /* don't clamp and proceed here.
3731                    testing has revealed that this can go negative,
3732                    which is an entirely different thing to just being too low.
3733                 */
3734                 if (new_bpm < 0.5) {
3735                         return false;
3736                 }
3737
3738                 new_bpm = min (new_bpm, (double) 1000.0);
3739
3740                 tempo_copy->set_note_types_per_minute (new_bpm);
3741                 if (tempo_copy->type() == TempoSection::Constant) {
3742                         tempo_copy->set_end_note_types_per_minute (new_bpm);
3743                 }
3744
3745                 recompute_tempi (future_map);
3746
3747                 if (check_solved (future_map)) {
3748
3749                         if (!next_t) {
3750                                 return false;
3751                         }
3752
3753                         ts->set_note_types_per_minute (new_bpm);
3754                         if (ts->type() == TempoSection::Constant) {
3755                                 ts->set_end_note_types_per_minute (new_bpm);
3756                         }
3757
3758                         recompute_map (_metrics);
3759
3760                         can_solve = true;
3761                 }
3762
3763                 if (next_t->type() == TempoSection::Constant || next_t->c() == 0.0) {
3764                         if (frame > tempo_copy->frame() + min_dframe && end_frame > tempo_copy->frame() + min_dframe) {
3765
3766                                 new_next_bpm = next_t->note_types_per_minute() * ((next_to_next_t->minute() - old_next_minute)
3767                                                                                   / (double) ((old_next_to_next_minute) - old_next_minute));
3768
3769                         } else {
3770                                 new_next_bpm = next_t->note_types_per_minute();
3771                         }
3772
3773                         next_t->set_note_types_per_minute (new_next_bpm);
3774                         recompute_tempi (future_map);
3775
3776                         if (check_solved (future_map)) {
3777                                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3778                                         if ((*i)->is_tempo() && (*i)->minute() >  ts->minute()) {
3779                                                 next_t = static_cast<TempoSection*> (*i);
3780                                                 break;
3781                                         }
3782                                 }
3783
3784                                 if (!next_t) {
3785                                         return false;
3786                                 }
3787                                 next_t->set_note_types_per_minute (new_next_bpm);
3788                                 recompute_map (_metrics);
3789                                 can_solve = true;
3790                         }
3791                 } else {
3792                         double next_frame_ratio = 1.0;
3793                         double copy_frame_ratio = 1.0;
3794
3795                         if (next_to_next_t) {
3796                                 next_frame_ratio = (next_to_next_t->minute() - old_next_minute) / (old_next_to_next_minute -  old_next_minute);
3797
3798                                 copy_frame_ratio = ((old_tc_minute - next_t->minute()) / (double) (old_tc_minute - old_next_minute));
3799                         }
3800
3801                         new_next_bpm = next_t->note_types_per_minute() * next_frame_ratio;
3802                         new_copy_end_bpm = tempo_copy->end_note_types_per_minute() * copy_frame_ratio;
3803
3804                         tempo_copy->set_end_note_types_per_minute (new_copy_end_bpm);
3805
3806                         if (next_t->clamped()) {
3807                                 next_t->set_note_types_per_minute (new_copy_end_bpm);
3808                         } else {
3809                                 next_t->set_note_types_per_minute (new_next_bpm);
3810                         }
3811
3812                         recompute_tempi (future_map);
3813
3814                         if (check_solved (future_map)) {
3815                                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3816                                         if ((*i)->is_tempo() && (*i)->minute() >  ts->minute()) {
3817                                                 next_t = static_cast<TempoSection*> (*i);
3818                                                 break;
3819                                         }
3820                                 }
3821
3822                                 if (!next_t) {
3823                                         return false;
3824                                 }
3825
3826                                 if (next_t->clamped()) {
3827                                         next_t->set_note_types_per_minute (new_copy_end_bpm);
3828                                 } else {
3829                                         next_t->set_note_types_per_minute (new_next_bpm);
3830                                 }
3831
3832                                 ts->set_end_note_types_per_minute (new_copy_end_bpm);
3833                                 recompute_map (_metrics);
3834                                 can_solve = true;
3835                         }
3836                 }
3837         }
3838
3839         Metrics::const_iterator d = future_map.begin();
3840         while (d != future_map.end()) {
3841                 delete (*d);
3842                 ++d;
3843         }
3844
3845         MetricPositionChanged (PropertyChange ()); // Emit Signal
3846
3847         return can_solve;
3848 }
3849 /** Returns the exact bbt-based beat corresponding to the bar, beat or quarter note subdivision nearest to
3850  * the supplied frame, possibly returning a negative value.
3851  *
3852  * @param frame  The session frame position.
3853  * @param sub_num The subdivision to use when rounding the beat.
3854  *                A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3855  *                Positive integers indicate quarter note (non BBT) divisions.
3856  *                0 indicates that the returned beat should not be rounded (equivalent to quarter_note_at_frame()).
3857  * @return The beat position of the supplied frame.
3858  *
3859  * when working to a musical grid, the use of sub_nom indicates that
3860  * the position should be interpreted musically.
3861  *
3862  * it effectively snaps to meter bars, meter beats or quarter note divisions
3863  * (as per current gui convention) and returns a musical position independent of frame rate.
3864  *
3865  * If the supplied frame lies before the first meter, the return will be negative,
3866  * in which case the returned beat uses the first meter (for BBT subdivisions) and
3867  * the continuation of the tempo curve (backwards).
3868  *
3869  * This function is sensitive to tempo and meter.
3870  */
3871 double
3872 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num) const
3873 {
3874         Glib::Threads::RWLock::ReaderLock lm (lock);
3875
3876         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
3877 }
3878
3879 double
3880 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions) const
3881 {
3882         return beat_at_pulse_locked (_metrics, exact_qn_at_frame_locked (metrics, frame, divisions) / 4.0);
3883 }
3884
3885 /** Returns the exact quarter note corresponding to the bar, beat or quarter note subdivision nearest to
3886  * the supplied frame, possibly returning a negative value.
3887  *
3888  * @param frame  The session frame position.
3889  * @param sub_num The subdivision to use when rounding the quarter note.
3890  *                A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3891  *                Positive integers indicate quarter note (non BBT) divisions.
3892  *                0 indicates that the returned quarter note should not be rounded (equivalent to quarter_note_at_frame()).
3893  * @return The quarter note position of the supplied frame.
3894  *
3895  * When working to a musical grid, the use of sub_nom indicates that
3896  * the frame position should be interpreted musically.
3897  *
3898  * it effectively snaps to meter bars, meter beats or quarter note divisions
3899  * (as per current gui convention) and returns a musical position independent of frame rate.
3900  *
3901  * If the supplied frame lies before the first meter, the return will be negative,
3902  * in which case the returned quarter note uses the first meter (for BBT subdivisions) and
3903  * the continuation of the tempo curve (backwards).
3904  *
3905  * This function is tempo-sensitive.
3906  */
3907 double
3908 TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num) const
3909 {
3910         Glib::Threads::RWLock::ReaderLock lm (lock);
3911
3912         return exact_qn_at_frame_locked (_metrics, frame, sub_num);
3913 }
3914
3915 double
3916 TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num) const
3917 {
3918         double qn = pulse_at_minute_locked (metrics, minute_at_frame (frame)) * 4.0;
3919
3920         if (sub_num > 1) {
3921                 qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
3922         } else if (sub_num == 1) {
3923                 /* the gui requested exact musical (BBT) beat */
3924                 qn = pulse_at_beat_locked (metrics, (floor (beat_at_minute_locked (metrics, minute_at_frame (frame)) + 0.5))) * 4.0;
3925         } else if (sub_num == -1) {
3926                 /* snap to  bar */
3927                 Timecode::BBT_Time bbt = bbt_at_pulse_locked (metrics, qn / 4.0);
3928                 bbt.beats = 1;
3929                 bbt.ticks = 0;
3930
3931                 const double prev_b = pulse_at_bbt_locked (metrics, bbt) * 4.0;
3932                 ++bbt.bars;
3933                 const double next_b = pulse_at_bbt_locked (metrics, bbt) * 4.0;
3934
3935                 if ((qn - prev_b) > (next_b - prev_b) / 2.0) {
3936                         qn = next_b;
3937                 } else {
3938                         qn = prev_b;
3939                 }
3940         }
3941
3942         return qn;
3943 }
3944
3945 /** returns the frame duration of the supplied BBT time at a specified frame position in the tempo map.
3946  * @param pos the frame position in the tempo map.
3947  * @param bbt the distance in BBT time from pos to calculate.
3948  * @param dir the rounding direction..
3949  * @return the duration in frames between pos and bbt
3950 */
3951 framecnt_t
3952 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
3953 {
3954         Glib::Threads::RWLock::ReaderLock lm (lock);
3955
3956         BBT_Time pos_bbt = bbt_at_minute_locked (_metrics, minute_at_frame (pos));
3957
3958         const double divisions = meter_section_at_minute_locked (_metrics, minute_at_frame (pos)).divisions_per_bar();
3959
3960         if (dir > 0) {
3961                 pos_bbt.bars += bbt.bars;
3962
3963                 pos_bbt.ticks += bbt.ticks;
3964                 if ((double) pos_bbt.ticks > BBT_Time::ticks_per_beat) {
3965                         pos_bbt.beats += 1;
3966                         pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3967                 }
3968
3969                 pos_bbt.beats += bbt.beats;
3970                 if ((double) pos_bbt.beats > divisions) {
3971                         pos_bbt.bars += 1;
3972                         pos_bbt.beats -= divisions;
3973                 }
3974                 const framecnt_t pos_bbt_frame = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
3975
3976                 return pos_bbt_frame - pos;
3977
3978         } else {
3979
3980                 if (pos_bbt.bars <= bbt.bars) {
3981                         pos_bbt.bars = 1;
3982                 } else {
3983                         pos_bbt.bars -= bbt.bars;
3984                 }
3985
3986                 if (pos_bbt.ticks < bbt.ticks) {
3987                         if (pos_bbt.bars > 1) {
3988                                 if (pos_bbt.beats == 1) {
3989                                         pos_bbt.bars--;
3990                                         pos_bbt.beats = divisions;
3991                                 } else {
3992                                         pos_bbt.beats--;
3993                                 }
3994                                 pos_bbt.ticks = BBT_Time::ticks_per_beat - (bbt.ticks - pos_bbt.ticks);
3995                         } else {
3996                                 pos_bbt.beats = 1;
3997                                 pos_bbt.ticks = 0;
3998                         }
3999                 } else {
4000                         pos_bbt.ticks -= bbt.ticks;
4001                 }
4002
4003                 if (pos_bbt.beats <= bbt.beats) {
4004                         if (pos_bbt.bars > 1) {
4005                                 pos_bbt.bars--;
4006                                 pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
4007                         } else {
4008                                 pos_bbt.beats = 1;
4009                         }
4010                 } else {
4011                         pos_bbt.beats -= bbt.beats;
4012                 }
4013
4014                 return pos - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
4015         }
4016
4017         return 0;
4018 }
4019
4020 MusicFrame
4021 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
4022 {
4023         return round_to_type (fr, dir, Bar);
4024 }
4025
4026 MusicFrame
4027 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
4028 {
4029         return round_to_type (fr, dir, Beat);
4030 }
4031
4032 MusicFrame
4033 TempoMap::round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir)
4034 {
4035         Glib::Threads::RWLock::ReaderLock lm (lock);
4036         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);
4037         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
4038         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
4039
4040         ticks -= beats * BBT_Time::ticks_per_beat;
4041
4042         if (dir > 0) {
4043                 /* round to next (or same iff dir == RoundUpMaybe) */
4044
4045                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
4046
4047                 if (mod == 0 && dir == RoundUpMaybe) {
4048                         /* right on the subdivision, which is fine, so do nothing */
4049
4050                 } else if (mod == 0) {
4051                         /* right on the subdivision, so the difference is just the subdivision ticks */
4052                         ticks += ticks_one_subdivisions_worth;
4053
4054                 } else {
4055                         /* not on subdivision, compute distance to next subdivision */
4056
4057                         ticks += ticks_one_subdivisions_worth - mod;
4058                 }
4059
4060 //NOTE:  this code intentionally limits the rounding so we don't advance to the next beat.
4061 //  For the purposes of "jump-to-next-subdivision", we DO want to advance to the next beat.
4062 //      And since the "prev" direction DOES move beats, I assume this code is unintended.
4063 //  But I'm keeping it around, until we determine there are no terrible consequences.
4064 //              if (ticks >= BBT_Time::ticks_per_beat) {
4065 //                      ticks -= BBT_Time::ticks_per_beat;
4066 //              }
4067
4068         } else if (dir < 0) {
4069
4070                 /* round to previous (or same iff dir == RoundDownMaybe) */
4071
4072                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
4073
4074                 if (difference == 0 && dir == RoundDownAlways) {
4075                         /* right on the subdivision, but force-rounding down,
4076                            so the difference is just the subdivision ticks */
4077                         difference = ticks_one_subdivisions_worth;
4078                 }
4079
4080                 if (ticks < difference) {
4081                         ticks = BBT_Time::ticks_per_beat - ticks;
4082                 } else {
4083                         ticks -= difference;
4084                 }
4085
4086         } else {
4087                 /* round to nearest */
4088                 double rem;
4089
4090                 /* compute the distance to the previous and next subdivision */
4091
4092                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
4093
4094                         /* closer to the next subdivision, so shift forward */
4095
4096                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
4097
4098                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
4099
4100                         if (ticks > BBT_Time::ticks_per_beat) {
4101                                 ++beats;
4102                                 ticks -= BBT_Time::ticks_per_beat;
4103                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
4104                         }
4105
4106                 } else if (rem > 0) {
4107
4108                         /* closer to previous subdivision, so shift backward */
4109
4110                         if (rem > ticks) {
4111                                 if (beats == 0) {
4112                                         /* can't go backwards past zero, so ... */
4113                                         return MusicFrame (0, 0);
4114                                 }
4115                                 /* step back to previous beat */
4116                                 --beats;
4117                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
4118                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
4119                         } else {
4120                                 ticks = lrint (ticks - rem);
4121                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
4122                         }
4123                 } else {
4124                         /* on the subdivision, do nothing */
4125                 }
4126         }
4127
4128         MusicFrame ret (0, 0);
4129         ret.frame = frame_at_minute (minute_at_pulse_locked (_metrics, (beats + (ticks / BBT_Time::ticks_per_beat)) / 4.0));
4130         ret.division = sub_num;
4131
4132         return ret;
4133 }
4134
4135 MusicFrame
4136 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
4137 {
4138         Glib::Threads::RWLock::ReaderLock lm (lock);
4139         const double minute = minute_at_frame (frame);
4140         const double beat_at_framepos = max (0.0, beat_at_minute_locked (_metrics, minute));
4141         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
4142         MusicFrame ret (0, 0);
4143
4144         switch (type) {
4145         case Bar:
4146                 ret.division = -1;
4147
4148                 if (dir < 0) {
4149                         /* find bar previous to 'frame' */
4150                         if (bbt.bars > 0)
4151                                 --bbt.bars;
4152                         bbt.beats = 1;
4153                         bbt.ticks = 0;
4154
4155                         ret.frame = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4156
4157                         return ret;
4158
4159                 } else if (dir > 0) {
4160                         /* find bar following 'frame' */
4161                         ++bbt.bars;
4162                         bbt.beats = 1;
4163                         bbt.ticks = 0;
4164
4165                         ret.frame = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4166
4167                         return ret;
4168                 } else {
4169                         /* true rounding: find nearest bar */
4170                         framepos_t raw_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4171                         bbt.beats = 1;
4172                         bbt.ticks = 0;
4173                         framepos_t prev_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4174                         ++bbt.bars;
4175                         framepos_t next_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4176
4177                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) {
4178                                 ret.frame = next_ft;
4179
4180                                 return ret;
4181                         } else {
4182                                 --bbt.bars;
4183                                 ret.frame = prev_ft;
4184
4185                                 return ret;
4186                         }
4187                 }
4188
4189                 break;
4190
4191         case Beat:
4192                 ret.division = 1;
4193
4194                 if (dir < 0) {
4195                         ret.frame = frame_at_minute (minute_at_beat_locked (_metrics, floor (beat_at_framepos)));
4196
4197                         return ret;
4198                 } else if (dir > 0) {
4199                         ret.frame = frame_at_minute (minute_at_beat_locked (_metrics, ceil (beat_at_framepos)));
4200
4201                         return ret;
4202                 } else {
4203                         ret.frame = frame_at_minute (minute_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5)));
4204
4205                         return ret;
4206                 }
4207                 break;
4208         }
4209
4210         return MusicFrame (0, 0);
4211 }
4212
4213 void
4214 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
4215                     framepos_t lower, framepos_t upper, uint32_t bar_mod)
4216 {
4217         Glib::Threads::RWLock::ReaderLock lm (lock);
4218         int32_t cnt = ceil (beat_at_minute_locked (_metrics, minute_at_frame (lower)));
4219         framecnt_t pos = 0;
4220         /* although the map handles negative beats, bbt doesn't. */
4221         if (cnt < 0.0) {
4222                 cnt = 0.0;
4223         }
4224
4225         if (minute_at_beat_locked (_metrics, cnt) >= minute_at_frame (upper)) {
4226                 return;
4227         }
4228         if (bar_mod == 0) {
4229                 while (pos >= 0 && pos < upper) {
4230                         pos = frame_at_minute (minute_at_beat_locked (_metrics, cnt));
4231                         const TempoSection tempo = tempo_section_at_minute_locked (_metrics, minute_at_frame (pos));
4232                         const MeterSection meter = meter_section_at_minute_locked (_metrics, minute_at_frame (pos));
4233                         const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
4234
4235                         points.push_back (BBTPoint (meter, tempo_at_minute_locked (_metrics, minute_at_frame (pos)), pos, bbt.bars, bbt.beats, tempo.c()));
4236                         ++cnt;
4237                 }
4238         } else {
4239                 BBT_Time bbt = bbt_at_minute_locked (_metrics, minute_at_frame (lower));
4240                 bbt.beats = 1;
4241                 bbt.ticks = 0;
4242
4243                 if (bar_mod != 1) {
4244                         bbt.bars -= bbt.bars % bar_mod;
4245                         ++bbt.bars;
4246                 }
4247
4248                 while (pos >= 0 && pos < upper) {
4249                         pos = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4250                         const TempoSection tempo = tempo_section_at_minute_locked (_metrics, minute_at_frame (pos));
4251                         const MeterSection meter = meter_section_at_minute_locked (_metrics, minute_at_frame (pos));
4252                         points.push_back (BBTPoint (meter, tempo_at_minute_locked (_metrics, minute_at_frame (pos)), pos, bbt.bars, bbt.beats, tempo.c()));
4253                         bbt.bars += bar_mod;
4254                 }
4255         }
4256 }
4257
4258 const TempoSection&
4259 TempoMap::tempo_section_at_frame (framepos_t frame) const
4260 {
4261         Glib::Threads::RWLock::ReaderLock lm (lock);
4262
4263         return tempo_section_at_minute_locked (_metrics, minute_at_frame (frame));
4264 }
4265
4266 TempoSection&
4267 TempoMap::tempo_section_at_frame (framepos_t frame)
4268 {
4269         Glib::Threads::RWLock::ReaderLock lm (lock);
4270
4271         return tempo_section_at_minute_locked (_metrics, minute_at_frame (frame));
4272 }
4273
4274 const TempoSection&
4275 TempoMap::tempo_section_at_minute_locked (const Metrics& metrics, double minute) const
4276 {
4277         TempoSection* prev = 0;
4278
4279         TempoSection* t;
4280
4281         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4282
4283                 if ((*i)->is_tempo()) {
4284                         t = static_cast<TempoSection*> (*i);
4285                         if (!t->active()) {
4286                                 continue;
4287                         }
4288                         if (prev && t->minute() > minute) {
4289                                 break;
4290                         }
4291
4292                         prev = t;
4293                 }
4294         }
4295
4296         if (prev == 0) {
4297                 fatal << endmsg;
4298                 abort(); /*NOTREACHED*/
4299         }
4300
4301         return *prev;
4302 }
4303 TempoSection&
4304 TempoMap::tempo_section_at_minute_locked (const Metrics& metrics, double minute)
4305 {
4306         TempoSection* prev = 0;
4307
4308         TempoSection* t;
4309
4310         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4311
4312                 if ((*i)->is_tempo()) {
4313                         t = static_cast<TempoSection*> (*i);
4314                         if (!t->active()) {
4315                                 continue;
4316                         }
4317                         if (prev && t->minute() > minute) {
4318                                 break;
4319                         }
4320
4321                         prev = t;
4322                 }
4323         }
4324
4325         if (prev == 0) {
4326                 fatal << endmsg;
4327                 abort(); /*NOTREACHED*/
4328         }
4329
4330         return *prev;
4331 }
4332 const TempoSection&
4333 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
4334 {
4335         TempoSection* prev_t = 0;
4336         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
4337
4338         TempoSection* t;
4339
4340         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4341                 if ((*i)->is_tempo()) {
4342                         t = static_cast<TempoSection*> (*i);
4343
4344                         if (!t->active()) {
4345                                 continue;
4346                         }
4347
4348                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
4349                                 break;
4350                         }
4351                         prev_t = t;
4352                 }
4353
4354         }
4355         return *prev_t;
4356 }
4357
4358 TempoSection*
4359 TempoMap::previous_tempo_section (TempoSection* ts) const
4360 {
4361         Glib::Threads::RWLock::ReaderLock lm (lock);
4362
4363         return previous_tempo_section_locked (_metrics, ts);
4364
4365 }
4366
4367 TempoSection*
4368 TempoMap::previous_tempo_section_locked (const Metrics& metrics, TempoSection* ts) const
4369 {
4370         if (!ts) {
4371                 return 0;
4372         }
4373
4374         TempoSection* prev = 0;
4375
4376         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4377
4378                 if ((*i)->is_tempo()) {
4379                         TempoSection* t = static_cast<TempoSection*> (*i);
4380
4381                         if (!t->active()) {
4382                                 continue;
4383                         }
4384
4385                         if (prev && t == ts) {
4386
4387                                 return prev;
4388                         }
4389
4390                         prev = t;
4391                 }
4392         }
4393
4394         if (prev == 0) {
4395                 fatal << endmsg;
4396                 abort(); /*NOTREACHED*/
4397         }
4398
4399         return 0;
4400 }
4401
4402 TempoSection*
4403 TempoMap::next_tempo_section (TempoSection* ts) const
4404 {
4405         Glib::Threads::RWLock::ReaderLock lm (lock);
4406
4407         return next_tempo_section_locked (_metrics, ts);
4408 }
4409
4410 TempoSection*
4411 TempoMap::next_tempo_section_locked (const Metrics& metrics, TempoSection* ts) const
4412 {
4413         if (!ts) {
4414                 return 0;
4415         }
4416
4417         TempoSection* prev = 0;
4418
4419         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4420
4421                 if ((*i)->is_tempo()) {
4422                         TempoSection* t = static_cast<TempoSection*> (*i);
4423
4424                         if (!t->active()) {
4425                                 continue;
4426                         }
4427
4428                         if (prev && prev == ts) {
4429
4430                                 return t;
4431                         }
4432
4433                         prev = t;
4434                 }
4435         }
4436
4437         if (prev == 0) {
4438                 fatal << endmsg;
4439                 abort(); /*NOTREACHED*/
4440         }
4441
4442         return 0;
4443 }
4444 /* don't use this to calculate length (the tempo is only correct for this frame).
4445    do that stuff based on the beat_at_frame and frame_at_beat api
4446 */
4447 double
4448 TempoMap::frames_per_quarter_note_at (const framepos_t& frame, const framecnt_t& sr) const
4449 {
4450         Glib::Threads::RWLock::ReaderLock lm (lock);
4451
4452         const TempoSection* ts_at = 0;
4453         const TempoSection* ts_after = 0;
4454         Metrics::const_iterator i;
4455         TempoSection* t;
4456
4457         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
4458
4459                 if ((*i)->is_tempo()) {
4460                         t = static_cast<TempoSection*> (*i);
4461                         if (!t->active()) {
4462                                 continue;
4463                         }
4464                         if (ts_at && (*i)->frame() > frame) {
4465                                 ts_after = t;
4466                                 break;
4467                         }
4468                         ts_at = t;
4469                 }
4470         }
4471         assert (ts_at);
4472
4473         if (ts_after) {
4474                 return  (60.0 * _frame_rate) / ts_at->tempo_at_minute (minute_at_frame (frame)).quarter_notes_per_minute();
4475         }
4476         /* must be treated as constant tempo */
4477         return ts_at->frames_per_quarter_note (_frame_rate);
4478 }
4479
4480 const MeterSection&
4481 TempoMap::meter_section_at_frame (framepos_t frame) const
4482 {
4483         Glib::Threads::RWLock::ReaderLock lm (lock);
4484         return meter_section_at_minute_locked (_metrics, minute_at_frame (frame));
4485 }
4486
4487 const MeterSection&
4488 TempoMap::meter_section_at_minute_locked (const Metrics& metrics, double minute) const
4489 {
4490         Metrics::const_iterator i;
4491         MeterSection* prev = 0;
4492
4493         MeterSection* m;
4494
4495         for (i = metrics.begin(); i != metrics.end(); ++i) {
4496
4497                 if (!(*i)->is_tempo()) {
4498                         m = static_cast<MeterSection*> (*i);
4499
4500                         if (prev && (*i)->minute() > minute) {
4501                                 break;
4502                         }
4503
4504                         prev = m;
4505                 }
4506         }
4507
4508         if (prev == 0) {
4509                 fatal << endmsg;
4510                 abort(); /*NOTREACHED*/
4511         }
4512
4513         return *prev;
4514 }
4515
4516 const MeterSection&
4517 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
4518 {
4519         MeterSection* prev_m = 0;
4520
4521         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4522                 MeterSection* m;
4523                 if (!(*i)->is_tempo()) {
4524                         m = static_cast<MeterSection*> (*i);
4525                         if (prev_m && m->beat() > beat) {
4526                                 break;
4527                         }
4528                         prev_m = m;
4529                 }
4530
4531         }
4532         return *prev_m;
4533 }
4534
4535 const MeterSection&
4536 TempoMap::meter_section_at_beat (double beat) const
4537 {
4538         Glib::Threads::RWLock::ReaderLock lm (lock);
4539         return meter_section_at_beat_locked (_metrics, beat);
4540 }
4541
4542 const Meter&
4543 TempoMap::meter_at_frame (framepos_t frame) const
4544 {
4545         TempoMetric m (metric_at (frame));
4546         return m.meter();
4547 }
4548
4549 void
4550 TempoMap::fix_legacy_session ()
4551 {
4552         MeterSection* prev_m = 0;
4553         TempoSection* prev_t = 0;
4554         bool have_initial_t = false;
4555
4556         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4557                 MeterSection* m;
4558                 TempoSection* t;
4559
4560                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
4561                         if (m->initial()) {
4562                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
4563                                 m->set_beat (bbt);
4564                                 m->set_pulse (0.0);
4565                                 m->set_minute (0.0);
4566                                 m->set_position_lock_style (AudioTime);
4567                                 prev_m = m;
4568                                 continue;
4569                         }
4570                         if (prev_m) {
4571                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
4572                                                                           + (m->bbt().beats - 1)
4573                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
4574                                                                           , m->bbt());
4575                                 m->set_beat (start);
4576                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
4577                                         + (m->bbt().beats - 1)
4578                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
4579                                 m->set_pulse (start_beat / prev_m->note_divisor());
4580                         }
4581                         prev_m = m;
4582                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
4583
4584                         if (!t->active()) {
4585                                 continue;
4586                         }
4587
4588                         if (t->initial()) {
4589                                 t->set_pulse (0.0);
4590                                 t->set_minute (0.0);
4591                                 t->set_position_lock_style (AudioTime);
4592                                 prev_t = t;
4593                                 have_initial_t = true;
4594                                 continue;
4595                         }
4596
4597                         if (prev_t) {
4598                                 /* some 4.x sessions have no initial (non-movable) tempo. */
4599                                 if (!have_initial_t) {
4600                                         prev_t->set_pulse (0.0);
4601                                         prev_t->set_minute (0.0);
4602                                         prev_t->set_position_lock_style (AudioTime);
4603                                         prev_t->set_initial (true);
4604                                         prev_t->set_locked_to_meter (true);
4605                                         have_initial_t = true;
4606                                 }
4607
4608                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
4609                                         + (t->legacy_bbt().beats - 1)
4610                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
4611                                 if (prev_m) {
4612                                         t->set_pulse (beat / prev_m->note_divisor());
4613                                 } else {
4614                                         /* really shouldn't happen but.. */
4615                                         t->set_pulse (beat / 4.0);
4616                                 }
4617                         }
4618                         prev_t = t;
4619                 }
4620         }
4621 }
4622 void
4623 TempoMap::fix_legacy_end_session ()
4624 {
4625         TempoSection* prev_t = 0;
4626
4627         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4628                 TempoSection* t;
4629
4630                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
4631
4632                         if (!t->active()) {
4633                                 continue;
4634                         }
4635
4636                         if (prev_t) {
4637                                 if (prev_t->type() != TempoSection::Constant) {
4638                                         prev_t->set_end_note_types_per_minute (t->note_types_per_minute());
4639                                 }
4640                         }
4641
4642                         prev_t = t;
4643                 }
4644         }
4645 }
4646
4647 XMLNode&
4648 TempoMap::get_state ()
4649 {
4650         Metrics::const_iterator i;
4651         XMLNode *root = new XMLNode ("TempoMap");
4652
4653         {
4654                 Glib::Threads::RWLock::ReaderLock lm (lock);
4655                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
4656                         root->add_child_nocopy ((*i)->get_state());
4657                 }
4658         }
4659
4660         return *root;
4661 }
4662
4663 int
4664 TempoMap::set_state (const XMLNode& node, int /*version*/)
4665 {
4666         {
4667                 Glib::Threads::RWLock::WriterLock lm (lock);
4668
4669                 XMLNodeList nlist;
4670                 XMLNodeConstIterator niter;
4671                 Metrics old_metrics (_metrics);
4672                 _metrics.clear();
4673
4674                 nlist = node.children();
4675
4676                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
4677                         XMLNode* child = *niter;
4678
4679                         if (child->name() == TempoSection::xml_state_node_name) {
4680
4681                                 try {
4682                                         TempoSection* ts = new TempoSection (*child, _frame_rate);
4683                                         _metrics.push_back (ts);
4684                                 }
4685
4686                                 catch (failed_constructor& err){
4687                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
4688                                         _metrics = old_metrics;
4689                                         old_metrics.clear();
4690                                         break;
4691                                 }
4692
4693                         } else if (child->name() == MeterSection::xml_state_node_name) {
4694
4695                                 try {
4696                                         MeterSection* ms = new MeterSection (*child, _frame_rate);
4697                                         _metrics.push_back (ms);
4698                                 }
4699
4700                                 catch (failed_constructor& err) {
4701                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
4702                                         _metrics = old_metrics;
4703                                         old_metrics.clear();
4704                                         break;
4705                                 }
4706                         }
4707                 }
4708
4709                 if (niter == nlist.end()) {
4710                         MetricSectionSorter cmp;
4711                         _metrics.sort (cmp);
4712                 }
4713
4714                 /* check for legacy sessions where bbt was the base musical unit for tempo */
4715                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4716                         TempoSection* t;
4717                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
4718                                 if (t->legacy_bbt().bars != 0) {
4719                                         fix_legacy_session();
4720                                         break;
4721                                 }
4722
4723                                 if (t->legacy_end()) {
4724                                         fix_legacy_end_session();
4725                                         break;
4726                                 }
4727
4728                                 break;
4729                         }
4730                 }
4731
4732                 /* check for multiple tempo/meters at the same location, which
4733                    ardour2 somehow allowed.
4734                 */
4735
4736                 Metrics::iterator prev = _metrics.end();
4737                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4738                         if (prev != _metrics.end()) {
4739                                 MeterSection* ms;
4740                                 MeterSection* prev_m;
4741                                 TempoSection* ts;
4742                                 TempoSection* prev_t;
4743                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
4744                                         if (prev_m->pulse() == ms->pulse()) {
4745                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
4746                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
4747                                                 return -1;
4748                                         }
4749                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
4750                                         if (prev_t->pulse() == ts->pulse()) {
4751                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
4752                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
4753                                                 return -1;
4754                                         }
4755                                 }
4756                         }
4757                         prev = i;
4758                 }
4759
4760                 recompute_map (_metrics);
4761
4762                 Metrics::const_iterator d = old_metrics.begin();
4763                 while (d != old_metrics.end()) {
4764                         delete (*d);
4765                         ++d;
4766                 }
4767                 old_metrics.clear ();
4768         }
4769
4770         PropertyChanged (PropertyChange ());
4771
4772         return 0;
4773 }
4774
4775 void
4776 TempoMap::dump (std::ostream& o) const
4777 {
4778         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
4779         const MeterSection* m;
4780         const TempoSection* t;
4781         const TempoSection* prev_t = 0;
4782
4783         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4784
4785                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
4786                         o << "Tempo @ " << *i << " start : " << t->note_types_per_minute() << " end : " << t->end_note_types_per_minute() << " BPM (pulse = 1/" << t->note_type()
4787                           << " type= " << enum_2_string (t->type()) << ") "  << " at pulse= " << t->pulse()
4788                           << " minute= " << t->minute() << " frame= " << t->frame() << " (initial? " << t->initial() << ')'
4789                           << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
4790                         if (prev_t) {
4791                                 o <<  "  current start  : " << t->note_types_per_minute()
4792                                   <<  "  current end  : " << t->end_note_types_per_minute()
4793                                   << " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl;
4794                                 o << "  previous     : " << prev_t->note_types_per_minute()
4795                                   << " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl;
4796                                 o << "  calculated   : " << prev_t->tempo_at_pulse (t->pulse())
4797                                   << " | " << prev_t->pulse_at_ntpm (prev_t->end_note_types_per_minute(), t->minute())
4798                                   << " | " << frame_at_minute (prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()))
4799                                   << " | " << prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()) << std::endl;
4800                         }
4801                         prev_t = t;
4802                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
4803                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt()
4804                           << " frame= " << m->frame() << " pulse: " << m->pulse() <<  " beat : " << m->beat()
4805                           << " pos lock: " << enum_2_string (m->position_lock_style()) << " (initial? " << m->initial() << ')' << endl;
4806                 }
4807         }
4808         o << "------" << std::endl;
4809 }
4810
4811 int
4812 TempoMap::n_tempos() const
4813 {
4814         Glib::Threads::RWLock::ReaderLock lm (lock);
4815         int cnt = 0;
4816
4817         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4818                 if ((*i)->is_tempo()) {
4819                         cnt++;
4820                 }
4821         }
4822
4823         return cnt;
4824 }
4825
4826 int
4827 TempoMap::n_meters() const
4828 {
4829         Glib::Threads::RWLock::ReaderLock lm (lock);
4830         int cnt = 0;
4831
4832         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4833                 if (!(*i)->is_tempo()) {
4834                         cnt++;
4835                 }
4836         }
4837
4838         return cnt;
4839 }
4840
4841 void
4842 TempoMap::insert_time (framepos_t where, framecnt_t amount)
4843 {
4844         for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
4845                 if ((*i)->frame() >= where && !(*i)->initial ()) {
4846                         MeterSection* ms;
4847                         TempoSection* ts;
4848
4849                         if ((ms = dynamic_cast <MeterSection*>(*i)) != 0) {
4850                                 gui_set_meter_position (ms, (*i)->frame() + amount);
4851                         }
4852
4853                         if ((ts = dynamic_cast <TempoSection*>(*i)) != 0) {
4854                                 gui_set_tempo_position (ts, (*i)->frame() + amount, 0);
4855                         }
4856                 }
4857         }
4858
4859         PropertyChanged (PropertyChange ());
4860 }
4861
4862 bool
4863 TempoMap::remove_time (framepos_t where, framecnt_t amount)
4864 {
4865         bool moved = false;
4866
4867         std::list<MetricSection*> metric_kill_list;
4868
4869         TempoSection* last_tempo = NULL;
4870         MeterSection* last_meter = NULL;
4871         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
4872         bool meter_after = false; // is there a meter marker likewise?
4873         {
4874                 Glib::Threads::RWLock::WriterLock lm (lock);
4875                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4876                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
4877                                 metric_kill_list.push_back(*i);
4878                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
4879                                 if (lt)
4880                                         last_tempo = lt;
4881                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
4882                                 if (lm)
4883                                         last_meter = lm;
4884                         }
4885                         else if ((*i)->frame() >= where) {
4886                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
4887                                 (*i)->set_minute ((*i)->minute() - minute_at_frame (amount));
4888                                 if ((*i)->frame() == where) {
4889                                         // marker was immediately after end of range
4890                                         tempo_after = dynamic_cast<TempoSection*> (*i);
4891                                         meter_after = dynamic_cast<MeterSection*> (*i);
4892                                 }
4893                                 moved = true;
4894                         }
4895                 }
4896
4897                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
4898                 if (last_tempo && !tempo_after) {
4899                         metric_kill_list.remove(last_tempo);
4900                         last_tempo->set_minute (minute_at_frame (where));
4901                         moved = true;
4902                 }
4903                 if (last_meter && !meter_after) {
4904                         metric_kill_list.remove(last_meter);
4905                         last_meter->set_minute (minute_at_frame (where));
4906                         moved = true;
4907                 }
4908
4909                 //remove all the remaining metrics
4910                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
4911                         _metrics.remove(*i);
4912                         moved = true;
4913                 }
4914
4915                 if (moved) {
4916                         recompute_map (_metrics);
4917                 }
4918         }
4919         PropertyChanged (PropertyChange ());
4920         return moved;
4921 }
4922
4923 /** Add some (fractional) Beats to a session frame position, and return the result in frames.
4924  *  pos can be -ve, if required.
4925  */
4926 framepos_t
4927 TempoMap::framepos_plus_qn (framepos_t frame, Evoral::Beats beats) const
4928 {
4929         Glib::Threads::RWLock::ReaderLock lm (lock);
4930         const double frame_qn = pulse_at_minute_locked (_metrics, minute_at_frame (frame)) * 4.0;
4931
4932         return frame_at_minute (minute_at_pulse_locked (_metrics, (frame_qn + beats.to_double()) / 4.0));
4933 }
4934
4935 framepos_t
4936 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
4937 {
4938         Glib::Threads::RWLock::ReaderLock lm (lock);
4939
4940         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_minute_locked (_metrics, minute_at_frame (pos)));
4941         pos_bbt.ticks += op.ticks;
4942         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
4943                 ++pos_bbt.beats;
4944                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
4945         }
4946         pos_bbt.beats += op.beats;
4947         /* the meter in effect will start on the bar */
4948         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();
4949         while (pos_bbt.beats >= divisions_per_bar + 1) {
4950                 ++pos_bbt.bars;
4951                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
4952                 pos_bbt.beats -= divisions_per_bar;
4953         }
4954         pos_bbt.bars += op.bars;
4955
4956         return frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
4957 }
4958
4959 /** Count the number of beats that are equivalent to distance when going forward,
4960     starting at pos.
4961 */
4962 Evoral::Beats
4963 TempoMap::framewalk_to_qn (framepos_t pos, framecnt_t distance) const
4964 {
4965         Glib::Threads::RWLock::ReaderLock lm (lock);
4966
4967         return Evoral::Beats (quarter_notes_between_frames_locked (_metrics, pos, pos + distance));
4968 }
4969
4970 struct bbtcmp {
4971     bool operator() (const BBT_Time& a, const BBT_Time& b) {
4972             return a < b;
4973     }
4974 };
4975
4976 std::ostream&
4977 operator<< (std::ostream& o, const Meter& m) {
4978         return o << m.divisions_per_bar() << '/' << m.note_divisor();
4979 }
4980
4981 std::ostream&
4982 operator<< (std::ostream& o, const Tempo& t) {
4983         return o << t.note_types_per_minute() << " 1/" << t.note_type() << "'s per minute";
4984 }
4985
4986 std::ostream&
4987 operator<< (std::ostream& o, const MetricSection& section) {
4988
4989         o << "MetricSection @ " << section.frame() << ' ';
4990
4991         const TempoSection* ts;
4992         const MeterSection* ms;
4993
4994         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
4995                 o << *((const Tempo*) ts);
4996         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
4997                 o << *((const Meter*) ms);
4998         }
4999
5000         return o;
5001 }