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