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