make new (ramped) tempi indidstiguishable from constant to the novice user.
[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                 /* this should be everywhere. no _type because type() is constant if note_types_per_minute() == end_types_per_minute()
3487                    but what to do with legact sessions?
3488                 */
3489                 if (prev_t && prev_t->note_types_per_minute() != prev_t->end_note_types_per_minute()) {
3490                         prev_t->set_note_types_per_minute (new_bpm);
3491                 } else {
3492                         prev_t->set_end_note_types_per_minute (new_bpm);
3493                         prev_t->set_note_types_per_minute (new_bpm);
3494                 }
3495
3496                 recompute_tempi (future_map);
3497                 recompute_meters (future_map);
3498
3499                 if (check_solved (future_map)) {
3500                         if (prev_t && prev_t->note_types_per_minute() != prev_t->end_note_types_per_minute()) {
3501                                 ts->set_note_types_per_minute (new_bpm);
3502                         } else {
3503                                 ts->set_end_note_types_per_minute (new_bpm);
3504                                 ts->set_note_types_per_minute (new_bpm);
3505                         }
3506                         recompute_tempi (_metrics);
3507                         recompute_meters (_metrics);
3508                 }
3509         }
3510
3511         MetricPositionChanged (PropertyChange ()); // Emit Signal
3512
3513 out:
3514         Metrics::const_iterator d = future_map.begin();
3515         while (d != future_map.end()) {
3516                 delete (*d);
3517                 ++d;
3518         }
3519
3520 }
3521 void
3522 TempoMap::gui_stretch_tempo_end (TempoSection* ts, const framepos_t frame, const framepos_t end_frame)
3523 {
3524         /*
3525           Ts (future prev_t)   Tnext
3526           |                    |
3527           |     [drag^]        |
3528           |----------|----------
3529                 e_f  qn_beats(frame)
3530         */
3531
3532         Metrics future_map;
3533
3534         {
3535                 Glib::Threads::RWLock::WriterLock lm (lock);
3536
3537                 if (!ts) {
3538                         return;
3539                 }
3540
3541                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
3542
3543 /*
3544                 TempoSection* next_t = 0;
3545                 for (Metrics::const_iterator i = future_map.begin(); i != future_map.end(); ++i) {
3546                         if ((*i)->is_tempo() && (*i)->minute() >  prev_t->minute()) {
3547                                 next_t = static_cast<TempoSection*> (*i);
3548                                 break;
3549                         }
3550                 }
3551
3552                 if (!next_t) {
3553                         return;
3554                 }
3555 */
3556                 if (!prev_t) {
3557                         return;
3558                 }
3559
3560
3561                 /* minimum allowed measurement distance in frames */
3562                 framepos_t const min_dframe = 2;
3563                 double new_bpm;
3564
3565                 if (frame > prev_t->frame() + min_dframe && end_frame > prev_t->frame() + min_dframe) {
3566                         new_bpm = prev_t->end_note_types_per_minute() * ((frame - prev_t->frame())
3567                                                                                  / (double) (end_frame - prev_t->frame()));
3568                 } else {
3569                         new_bpm = prev_t->end_note_types_per_minute();
3570                 }
3571
3572                 new_bpm = min (new_bpm, (double) 1000.0);
3573
3574                 if (new_bpm < 0.5) {
3575                         goto out;
3576                 }
3577
3578                 if (prev_t && prev_t->type() == TempoSection::Ramp) {
3579                         prev_t->set_end_note_types_per_minute (new_bpm);
3580                 } else {
3581                         if (prev_t) {
3582                                 prev_t->set_note_types_per_minute (new_bpm);
3583                                 prev_t->set_end_note_types_per_minute (prev_t->note_types_per_minute());
3584                         }
3585                 }
3586
3587                 recompute_tempi (future_map);
3588                 recompute_meters (future_map);
3589
3590                 if (check_solved (future_map)) {
3591                         if (prev_t && prev_t->type() == TempoSection::Ramp) {
3592                                 ts->set_end_note_types_per_minute (new_bpm);
3593                         } else {
3594                                 if (prev_t) {
3595                                         ts->set_end_note_types_per_minute (prev_t->note_types_per_minute());
3596                                         ts->set_note_types_per_minute (prev_t->note_types_per_minute());
3597                                 }
3598                         }
3599                         recompute_tempi (_metrics);
3600                         recompute_meters (_metrics);
3601                 }
3602         }
3603
3604         MetricPositionChanged (PropertyChange ()); // Emit Signal
3605
3606 out:
3607         Metrics::const_iterator d = future_map.begin();
3608         while (d != future_map.end()) {
3609                 delete (*d);
3610                 ++d;
3611         }
3612
3613 }
3614 bool
3615 TempoMap::gui_twist_tempi (TempoSection* ts, const Tempo& bpm, const framepos_t frame, const framepos_t end_frame)
3616 {
3617         TempoSection* next_t = 0;
3618         TempoSection* next_to_next_t = 0;
3619         Metrics future_map;
3620         bool can_solve = false;
3621
3622         /* minimum allowed measurement distance in frames */
3623         framepos_t const min_dframe = 2;
3624
3625         {
3626                 Glib::Threads::RWLock::WriterLock lm (lock);
3627                 if (!ts) {
3628                         return false;
3629                 }
3630
3631                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
3632                 TempoSection* prev_to_prev_t = 0;
3633                 const frameoffset_t fr_off = end_frame - frame;
3634
3635                 if (!tempo_copy) {
3636                         return false;
3637                 }
3638
3639                 if (tempo_copy->pulse() > 0.0) {
3640                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_minute_locked (future_map, minute_at_frame (tempo_copy->frame() - 1)));
3641                 }
3642
3643                 for (Metrics::const_iterator i = future_map.begin(); i != future_map.end(); ++i) {
3644                         if ((*i)->is_tempo() && (*i)->minute() >  tempo_copy->minute()) {
3645                                 next_t = static_cast<TempoSection*> (*i);
3646                                 break;
3647                         }
3648                 }
3649
3650                 if (!next_t) {
3651                         return false;
3652                 }
3653
3654                 for (Metrics::const_iterator i = future_map.begin(); i != future_map.end(); ++i) {
3655                         if ((*i)->is_tempo() && (*i)->minute() >  next_t->minute()) {
3656                                 next_to_next_t = static_cast<TempoSection*> (*i);
3657                                 break;
3658                         }
3659                 }
3660
3661                 if (!next_to_next_t) {
3662                         std::cout << "no next to next t" << std::endl;
3663                         return false;
3664                 }
3665
3666                 double prev_contribution = 0.0;
3667
3668                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
3669                         prev_contribution = (tempo_copy->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
3670                 }
3671
3672                 const frameoffset_t tempo_copy_frame_contribution = fr_off - (prev_contribution * (double) fr_off);
3673
3674
3675                 framepos_t old_tc_pos = tempo_copy->frame();
3676                 framepos_t old_next_pos = next_t->frame();
3677                 double old_next_minute = next_t->minute();
3678                 framepos_t old_next_to_next_pos = next_to_next_t->frame();
3679                 double old_next_to_next_minute = next_to_next_t->minute();
3680
3681                 double new_bpm;
3682                 double new_next_bpm;
3683                 double new_copy_end_bpm;
3684
3685                 if (frame > prev_to_prev_t->frame() + min_dframe && (frame + tempo_copy_frame_contribution) > prev_to_prev_t->frame() + min_dframe) {
3686                         new_bpm = tempo_copy->note_types_per_minute() * ((frame - tempo_copy->frame())
3687                                                                                        / (double) (end_frame - tempo_copy->frame()));
3688                 } else {
3689                         new_bpm = tempo_copy->note_types_per_minute();
3690                 }
3691
3692                 /* don't clamp and proceed here.
3693                    testing has revealed that this can go negative,
3694                    which is an entirely different thing to just being too low.
3695                 */
3696                 if (new_bpm < 0.5) {
3697                         return false;
3698                 }
3699
3700                 new_bpm = min (new_bpm, (double) 1000.0);
3701
3702                 tempo_copy->set_note_types_per_minute (new_bpm);
3703                 if (tempo_copy->type() == TempoSection::Constant) {
3704                         tempo_copy->set_end_note_types_per_minute (new_bpm);
3705                 }
3706                 recompute_tempi (future_map);
3707
3708                 if (check_solved (future_map)) {
3709
3710                         if (!next_t) {
3711                                 return false;
3712                         }
3713                         ts->set_note_types_per_minute (new_bpm);
3714                         if (ts->type() == TempoSection::Constant) {
3715                                 ts->set_end_note_types_per_minute (new_bpm);
3716                         }
3717                         recompute_map (_metrics);
3718                         can_solve = true;
3719                 }
3720
3721                 if (next_t->type() == TempoSection::Constant || next_t->c() == 0.0) {
3722                         if (frame > prev_to_prev_t->frame() + min_dframe && end_frame > prev_to_prev_t->frame() + min_dframe) {
3723
3724                                 new_next_bpm = next_t->note_types_per_minute() * ((next_to_next_t->minute() - old_next_minute)
3725                                                                                         / (double) ((old_next_to_next_minute) - old_next_minute));
3726
3727                         } else {
3728                                 new_next_bpm = next_t->note_types_per_minute();
3729                         }
3730
3731                         next_t->set_note_types_per_minute (new_next_bpm);
3732                         recompute_tempi (future_map);
3733
3734                         if (check_solved (future_map)) {
3735                                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3736                                         if ((*i)->is_tempo() && (*i)->minute() >  ts->minute()) {
3737                                                 next_t = static_cast<TempoSection*> (*i);
3738                                                 break;
3739                                         }
3740                                 }
3741
3742                                 if (!next_t) {
3743                                         return false;
3744                                 }
3745                                 next_t->set_note_types_per_minute (new_next_bpm);
3746                                 recompute_map (_metrics);
3747                                 can_solve = true;
3748                         }
3749                 } else {
3750                         double next_frame_ratio = 1.0;
3751                         double copy_frame_ratio = 1.0;
3752
3753                         if (next_to_next_t) {
3754                                 next_frame_ratio =  (next_to_next_t->frame() - old_next_pos) / (double) (old_next_to_next_pos -  old_next_pos);
3755
3756                                 copy_frame_ratio =   ((old_tc_pos - next_t->frame()) / (double) (old_tc_pos - old_next_pos));
3757
3758                         } else {
3759                                 //next_frame_ratio = (((next_to_next_pos - fr_off) - next_t->frame()) / (double) ((next_to_next_pos) - next_t->frame()));
3760                                 //next_pulse_ratio = (start_pulse / end_pulse);
3761                         }
3762
3763                         new_next_bpm = next_t->note_types_per_minute() * next_frame_ratio;
3764                         new_copy_end_bpm =  tempo_copy->end_note_types_per_minute() * copy_frame_ratio;
3765
3766                         next_t->set_note_types_per_minute (new_next_bpm);
3767                         tempo_copy->set_end_note_types_per_minute (new_copy_end_bpm);
3768                         recompute_tempi (future_map);
3769
3770                         if (check_solved (future_map)) {
3771                                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3772                                         if ((*i)->is_tempo() && (*i)->minute() >  ts->minute()) {
3773                                                 next_t = static_cast<TempoSection*> (*i);
3774                                                 break;
3775                                         }
3776                                 }
3777
3778                                 if (!next_t) {
3779                                         return false;
3780                                 }
3781                                 next_t->set_note_types_per_minute (new_next_bpm);
3782                                 ts->set_end_note_types_per_minute (new_copy_end_bpm);
3783                                 recompute_map (_metrics);
3784                                 can_solve = true;
3785                         }
3786                 }
3787         }
3788
3789         Metrics::const_iterator d = future_map.begin();
3790         while (d != future_map.end()) {
3791                 delete (*d);
3792                 ++d;
3793         }
3794         if (can_solve) {
3795                 MetricPositionChanged (PropertyChange ()); // Emit Signal
3796         }
3797
3798         return can_solve;
3799 }
3800 /** Returns the exact bbt-based beat corresponding to the bar, beat or quarter note subdivision nearest to
3801  * the supplied frame, possibly returning a negative value.
3802  *
3803  * @param frame  The session frame position.
3804  * @param sub_num The subdivision to use when rounding the beat.
3805  *                A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3806  *                Positive integers indicate quarter note (non BBT) divisions.
3807  *                0 indicates that the returned beat should not be rounded (equivalent to quarter_note_at_frame()).
3808  * @return The beat position of the supplied frame.
3809  *
3810  * when working to a musical grid, the use of sub_nom indicates that
3811  * the position should be interpreted musically.
3812  *
3813  * it effectively snaps to meter bars, meter beats or quarter note divisions
3814  * (as per current gui convention) and returns a musical position independent of frame rate.
3815  *
3816  * If the supplied frame lies before the first meter, the return will be negative,
3817  * in which case the returned beat uses the first meter (for BBT subdivisions) and
3818  * the continuation of the tempo curve (backwards).
3819  *
3820  * This function is sensitive to tempo and meter.
3821  */
3822 double
3823 TempoMap::exact_beat_at_frame (const framepos_t& frame, const int32_t sub_num) const
3824 {
3825         Glib::Threads::RWLock::ReaderLock lm (lock);
3826
3827         return exact_beat_at_frame_locked (_metrics, frame, sub_num);
3828 }
3829
3830 double
3831 TempoMap::exact_beat_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t divisions) const
3832 {
3833         return beat_at_pulse_locked (_metrics, exact_qn_at_frame_locked (metrics, frame, divisions) / 4.0);
3834 }
3835
3836 /** Returns the exact quarter note corresponding to the bar, beat or quarter note subdivision nearest to
3837  * the supplied frame, possibly returning a negative value.
3838  *
3839  * @param frame  The session frame position.
3840  * @param sub_num The subdivision to use when rounding the quarter note.
3841  *                A value of -1 indicates rounding to BBT bar. 1 indicates rounding to BBT beats.
3842  *                Positive integers indicate quarter note (non BBT) divisions.
3843  *                0 indicates that the returned quarter note should not be rounded (equivalent to quarter_note_at_frame()).
3844  * @return The quarter note position of the supplied frame.
3845  *
3846  * When working to a musical grid, the use of sub_nom indicates that
3847  * the frame position should be interpreted musically.
3848  *
3849  * it effectively snaps to meter bars, meter beats or quarter note divisions
3850  * (as per current gui convention) and returns a musical position independent of frame rate.
3851  *
3852  * If the supplied frame lies before the first meter, the return will be negative,
3853  * in which case the returned quarter note uses the first meter (for BBT subdivisions) and
3854  * the continuation of the tempo curve (backwards).
3855  *
3856  * This function is tempo-sensitive.
3857  */
3858 double
3859 TempoMap::exact_qn_at_frame (const framepos_t& frame, const int32_t sub_num) const
3860 {
3861         Glib::Threads::RWLock::ReaderLock lm (lock);
3862
3863         return exact_qn_at_frame_locked (_metrics, frame, sub_num);
3864 }
3865
3866 double
3867 TempoMap::exact_qn_at_frame_locked (const Metrics& metrics, const framepos_t& frame, const int32_t sub_num) const
3868 {
3869         double qn = pulse_at_minute_locked (metrics, minute_at_frame (frame)) * 4.0;
3870
3871         if (sub_num > 1) {
3872                 qn = floor (qn) + (floor (((qn - floor (qn)) * (double) sub_num) + 0.5) / sub_num);
3873         } else if (sub_num == 1) {
3874                 /* the gui requested exact musical (BBT) beat */
3875                 qn = pulse_at_beat_locked (metrics, (floor (beat_at_minute_locked (metrics, minute_at_frame (frame)) + 0.5))) * 4.0;
3876         } else if (sub_num == -1) {
3877                 /* snap to  bar */
3878                 Timecode::BBT_Time bbt = bbt_at_pulse_locked (metrics, qn / 4.0);
3879                 bbt.beats = 1;
3880                 bbt.ticks = 0;
3881
3882                 const double prev_b = pulse_at_bbt_locked (metrics, bbt) * 4.0;
3883                 ++bbt.bars;
3884                 const double next_b = pulse_at_bbt_locked (metrics, bbt) * 4.0;
3885
3886                 if ((qn - prev_b) > (next_b - prev_b) / 2.0) {
3887                         qn = next_b;
3888                 } else {
3889                         qn = prev_b;
3890                 }
3891         }
3892
3893         return qn;
3894 }
3895
3896 /** returns the frame duration of the supplied BBT time at a specified frame position in the tempo map.
3897  * @param pos the frame position in the tempo map.
3898  * @param bbt the distance in BBT time from pos to calculate.
3899  * @param dir the rounding direction..
3900  * @return the duration in frames between pos and bbt
3901 */
3902 framecnt_t
3903 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
3904 {
3905         Glib::Threads::RWLock::ReaderLock lm (lock);
3906
3907         BBT_Time pos_bbt = bbt_at_minute_locked (_metrics, minute_at_frame (pos));
3908
3909         const double divisions = meter_section_at_minute_locked (_metrics, minute_at_frame (pos)).divisions_per_bar();
3910
3911         if (dir > 0) {
3912                 pos_bbt.bars += bbt.bars;
3913
3914                 pos_bbt.ticks += bbt.ticks;
3915                 if ((double) pos_bbt.ticks > BBT_Time::ticks_per_beat) {
3916                         pos_bbt.beats += 1;
3917                         pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3918                 }
3919
3920                 pos_bbt.beats += bbt.beats;
3921                 if ((double) pos_bbt.beats > divisions) {
3922                         pos_bbt.bars += 1;
3923                         pos_bbt.beats -= divisions;
3924                 }
3925                 const framecnt_t pos_bbt_frame = frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
3926
3927                 return pos_bbt_frame - pos;
3928
3929         } else {
3930
3931                 if (pos_bbt.bars <= bbt.bars) {
3932                         pos_bbt.bars = 1;
3933                 } else {
3934                         pos_bbt.bars -= bbt.bars;
3935                 }
3936
3937                 if (pos_bbt.ticks < bbt.ticks) {
3938                         if (pos_bbt.bars > 1) {
3939                                 if (pos_bbt.beats == 1) {
3940                                         pos_bbt.bars--;
3941                                         pos_bbt.beats = divisions;
3942                                 } else {
3943                                         pos_bbt.beats--;
3944                                 }
3945                                 pos_bbt.ticks = BBT_Time::ticks_per_beat - (bbt.ticks - pos_bbt.ticks);
3946                         } else {
3947                                 pos_bbt.beats = 1;
3948                                 pos_bbt.ticks = 0;
3949                         }
3950                 } else {
3951                         pos_bbt.ticks -= bbt.ticks;
3952                 }
3953
3954                 if (pos_bbt.beats <= bbt.beats) {
3955                         if (pos_bbt.bars > 1) {
3956                                 pos_bbt.bars--;
3957                                 pos_bbt.beats = divisions - (bbt.beats - pos_bbt.beats);
3958                         } else {
3959                                 pos_bbt.beats = 1;
3960                         }
3961                 } else {
3962                         pos_bbt.beats -= bbt.beats;
3963                 }
3964
3965                 return pos - frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
3966         }
3967
3968         return 0;
3969 }
3970
3971 MusicFrame
3972 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
3973 {
3974         return round_to_type (fr, dir, Bar);
3975 }
3976
3977 MusicFrame
3978 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
3979 {
3980         return round_to_type (fr, dir, Beat);
3981 }
3982
3983 MusicFrame
3984 TempoMap::round_to_quarter_note_subdivision (framepos_t fr, int sub_num, RoundMode dir)
3985 {
3986         Glib::Threads::RWLock::ReaderLock lm (lock);
3987         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);
3988         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
3989         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
3990
3991         ticks -= beats * BBT_Time::ticks_per_beat;
3992
3993         if (dir > 0) {
3994                 /* round to next (or same iff dir == RoundUpMaybe) */
3995
3996                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
3997
3998                 if (mod == 0 && dir == RoundUpMaybe) {
3999                         /* right on the subdivision, which is fine, so do nothing */
4000
4001                 } else if (mod == 0) {
4002                         /* right on the subdivision, so the difference is just the subdivision ticks */
4003                         ticks += ticks_one_subdivisions_worth;
4004
4005                 } else {
4006                         /* not on subdivision, compute distance to next subdivision */
4007
4008                         ticks += ticks_one_subdivisions_worth - mod;
4009                 }
4010
4011 //NOTE:  this code intentionally limits the rounding so we don't advance to the next beat.
4012 //  For the purposes of "jump-to-next-subdivision", we DO want to advance to the next beat.
4013 //      And since the "prev" direction DOES move beats, I assume this code is unintended.
4014 //  But I'm keeping it around, until we determine there are no terrible consequences.
4015 //              if (ticks >= BBT_Time::ticks_per_beat) {
4016 //                      ticks -= BBT_Time::ticks_per_beat;
4017 //              }
4018
4019         } else if (dir < 0) {
4020
4021                 /* round to previous (or same iff dir == RoundDownMaybe) */
4022
4023                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
4024
4025                 if (difference == 0 && dir == RoundDownAlways) {
4026                         /* right on the subdivision, but force-rounding down,
4027                            so the difference is just the subdivision ticks */
4028                         difference = ticks_one_subdivisions_worth;
4029                 }
4030
4031                 if (ticks < difference) {
4032                         ticks = BBT_Time::ticks_per_beat - ticks;
4033                 } else {
4034                         ticks -= difference;
4035                 }
4036
4037         } else {
4038                 /* round to nearest */
4039                 double rem;
4040
4041                 /* compute the distance to the previous and next subdivision */
4042
4043                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
4044
4045                         /* closer to the next subdivision, so shift forward */
4046
4047                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
4048
4049                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
4050
4051                         if (ticks > BBT_Time::ticks_per_beat) {
4052                                 ++beats;
4053                                 ticks -= BBT_Time::ticks_per_beat;
4054                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
4055                         }
4056
4057                 } else if (rem > 0) {
4058
4059                         /* closer to previous subdivision, so shift backward */
4060
4061                         if (rem > ticks) {
4062                                 if (beats == 0) {
4063                                         /* can't go backwards past zero, so ... */
4064                                         return MusicFrame (0, 0);
4065                                 }
4066                                 /* step back to previous beat */
4067                                 --beats;
4068                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
4069                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
4070                         } else {
4071                                 ticks = lrint (ticks - rem);
4072                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
4073                         }
4074                 } else {
4075                         /* on the subdivision, do nothing */
4076                 }
4077         }
4078
4079         MusicFrame ret (0, 0);
4080         ret.frame = frame_at_minute (minute_at_pulse_locked (_metrics, (beats + (ticks / BBT_Time::ticks_per_beat)) / 4.0));
4081         ret.division = sub_num;
4082
4083         return ret;
4084 }
4085
4086 MusicFrame
4087 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
4088 {
4089         Glib::Threads::RWLock::ReaderLock lm (lock);
4090         const double minute = minute_at_frame (frame);
4091         const double beat_at_framepos = max (0.0, beat_at_minute_locked (_metrics, minute));
4092         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
4093         MusicFrame ret (0, 0);
4094
4095         switch (type) {
4096         case Bar:
4097                 ret.division = -1;
4098
4099                 if (dir < 0) {
4100                         /* find bar previous to 'frame' */
4101                         if (bbt.bars > 0)
4102                                 --bbt.bars;
4103                         bbt.beats = 1;
4104                         bbt.ticks = 0;
4105
4106                         ret.frame = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4107
4108                         return ret;
4109
4110                 } else if (dir > 0) {
4111                         /* find bar following 'frame' */
4112                         ++bbt.bars;
4113                         bbt.beats = 1;
4114                         bbt.ticks = 0;
4115
4116                         ret.frame = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4117
4118                         return ret;
4119                 } else {
4120                         /* true rounding: find nearest bar */
4121                         framepos_t raw_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4122                         bbt.beats = 1;
4123                         bbt.ticks = 0;
4124                         framepos_t prev_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4125                         ++bbt.bars;
4126                         framepos_t next_ft = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4127
4128                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) {
4129                                 ret.frame = next_ft;
4130
4131                                 return ret;
4132                         } else {
4133                                 --bbt.bars;
4134                                 ret.frame = prev_ft;
4135
4136                                 return ret;
4137                         }
4138                 }
4139
4140                 break;
4141
4142         case Beat:
4143                 ret.division = 1;
4144
4145                 if (dir < 0) {
4146                         ret.frame = frame_at_minute (minute_at_beat_locked (_metrics, floor (beat_at_framepos)));
4147
4148                         return ret;
4149                 } else if (dir > 0) {
4150                         ret.frame = frame_at_minute (minute_at_beat_locked (_metrics, ceil (beat_at_framepos)));
4151
4152                         return ret;
4153                 } else {
4154                         ret.frame = frame_at_minute (minute_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5)));
4155
4156                         return ret;
4157                 }
4158                 break;
4159         }
4160
4161         return MusicFrame (0, 0);
4162 }
4163
4164 void
4165 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
4166                     framepos_t lower, framepos_t upper, uint32_t bar_mod)
4167 {
4168         Glib::Threads::RWLock::ReaderLock lm (lock);
4169         int32_t cnt = ceil (beat_at_minute_locked (_metrics, minute_at_frame (lower)));
4170         framecnt_t pos = 0;
4171         /* although the map handles negative beats, bbt doesn't. */
4172         if (cnt < 0.0) {
4173                 cnt = 0.0;
4174         }
4175
4176         if (minute_at_beat_locked (_metrics, cnt) >= minute_at_frame (upper)) {
4177                 return;
4178         }
4179         if (bar_mod == 0) {
4180                 while (pos >= 0 && pos < upper) {
4181                         pos = frame_at_minute (minute_at_beat_locked (_metrics, cnt));
4182                         const TempoSection tempo = tempo_section_at_minute_locked (_metrics, minute_at_frame (pos));
4183                         const MeterSection meter = meter_section_at_minute_locked (_metrics, minute_at_frame (pos));
4184                         const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
4185
4186                         points.push_back (BBTPoint (meter, tempo_at_minute_locked (_metrics, minute_at_frame (pos)), pos, bbt.bars, bbt.beats, tempo.c()));
4187                         ++cnt;
4188                 }
4189         } else {
4190                 BBT_Time bbt = bbt_at_minute_locked (_metrics, minute_at_frame (lower));
4191                 bbt.beats = 1;
4192                 bbt.ticks = 0;
4193
4194                 if (bar_mod != 1) {
4195                         bbt.bars -= bbt.bars % bar_mod;
4196                         ++bbt.bars;
4197                 }
4198
4199                 while (pos >= 0 && pos < upper) {
4200                         pos = frame_at_minute (minute_at_bbt_locked (_metrics, bbt));
4201                         const TempoSection tempo = tempo_section_at_minute_locked (_metrics, minute_at_frame (pos));
4202                         const MeterSection meter = meter_section_at_minute_locked (_metrics, minute_at_frame (pos));
4203                         points.push_back (BBTPoint (meter, tempo_at_minute_locked (_metrics, minute_at_frame (pos)), pos, bbt.bars, bbt.beats, tempo.c()));
4204                         bbt.bars += bar_mod;
4205                 }
4206         }
4207 }
4208
4209 const TempoSection&
4210 TempoMap::tempo_section_at_frame (framepos_t frame) const
4211 {
4212         Glib::Threads::RWLock::ReaderLock lm (lock);
4213
4214         return tempo_section_at_minute_locked (_metrics, minute_at_frame (frame));
4215 }
4216
4217 TempoSection&
4218 TempoMap::tempo_section_at_frame (framepos_t frame)
4219 {
4220         Glib::Threads::RWLock::ReaderLock lm (lock);
4221
4222         return tempo_section_at_minute_locked (_metrics, minute_at_frame (frame));
4223 }
4224
4225 const TempoSection&
4226 TempoMap::tempo_section_at_minute_locked (const Metrics& metrics, double minute) const
4227 {
4228         TempoSection* prev = 0;
4229
4230         TempoSection* t;
4231
4232         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4233
4234                 if ((*i)->is_tempo()) {
4235                         t = static_cast<TempoSection*> (*i);
4236                         if (!t->active()) {
4237                                 continue;
4238                         }
4239                         if (prev && t->minute() > minute) {
4240                                 break;
4241                         }
4242
4243                         prev = t;
4244                 }
4245         }
4246
4247         if (prev == 0) {
4248                 fatal << endmsg;
4249                 abort(); /*NOTREACHED*/
4250         }
4251
4252         return *prev;
4253 }
4254 TempoSection&
4255 TempoMap::tempo_section_at_minute_locked (const Metrics& metrics, double minute)
4256 {
4257         TempoSection* prev = 0;
4258
4259         TempoSection* t;
4260
4261         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4262
4263                 if ((*i)->is_tempo()) {
4264                         t = static_cast<TempoSection*> (*i);
4265                         if (!t->active()) {
4266                                 continue;
4267                         }
4268                         if (prev && t->minute() > minute) {
4269                                 break;
4270                         }
4271
4272                         prev = t;
4273                 }
4274         }
4275
4276         if (prev == 0) {
4277                 fatal << endmsg;
4278                 abort(); /*NOTREACHED*/
4279         }
4280
4281         return *prev;
4282 }
4283 const TempoSection&
4284 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
4285 {
4286         TempoSection* prev_t = 0;
4287         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
4288
4289         TempoSection* t;
4290
4291         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4292                 if ((*i)->is_tempo()) {
4293                         t = static_cast<TempoSection*> (*i);
4294
4295                         if (!t->active()) {
4296                                 continue;
4297                         }
4298
4299                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
4300                                 break;
4301                         }
4302                         prev_t = t;
4303                 }
4304
4305         }
4306         return *prev_t;
4307 }
4308
4309 /* don't use this to calculate length (the tempo is only correct for this frame).
4310    do that stuff based on the beat_at_frame and frame_at_beat api
4311 */
4312 double
4313 TempoMap::frames_per_quarter_note_at (const framepos_t& frame, const framecnt_t& sr) const
4314 {
4315         Glib::Threads::RWLock::ReaderLock lm (lock);
4316
4317         const TempoSection* ts_at = 0;
4318         const TempoSection* ts_after = 0;
4319         Metrics::const_iterator i;
4320         TempoSection* t;
4321
4322         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
4323
4324                 if ((*i)->is_tempo()) {
4325                         t = static_cast<TempoSection*> (*i);
4326                         if (!t->active()) {
4327                                 continue;
4328                         }
4329                         if (ts_at && (*i)->frame() > frame) {
4330                                 ts_after = t;
4331                                 break;
4332                         }
4333                         ts_at = t;
4334                 }
4335         }
4336         assert (ts_at);
4337
4338         if (ts_after) {
4339                 return  (60.0 * _frame_rate) / ts_at->tempo_at_minute (minute_at_frame (frame)).quarter_notes_per_minute();
4340         }
4341         /* must be treated as constant tempo */
4342         return ts_at->frames_per_quarter_note (_frame_rate);
4343 }
4344
4345 const MeterSection&
4346 TempoMap::meter_section_at_frame (framepos_t frame) const
4347 {
4348         Glib::Threads::RWLock::ReaderLock lm (lock);
4349         return meter_section_at_minute_locked (_metrics, minute_at_frame (frame));
4350 }
4351
4352 const MeterSection&
4353 TempoMap::meter_section_at_minute_locked (const Metrics& metrics, double minute) const
4354 {
4355         Metrics::const_iterator i;
4356         MeterSection* prev = 0;
4357
4358         MeterSection* m;
4359
4360         for (i = metrics.begin(); i != metrics.end(); ++i) {
4361
4362                 if (!(*i)->is_tempo()) {
4363                         m = static_cast<MeterSection*> (*i);
4364
4365                         if (prev && (*i)->minute() > minute) {
4366                                 break;
4367                         }
4368
4369                         prev = m;
4370                 }
4371         }
4372
4373         if (prev == 0) {
4374                 fatal << endmsg;
4375                 abort(); /*NOTREACHED*/
4376         }
4377
4378         return *prev;
4379 }
4380
4381 const MeterSection&
4382 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
4383 {
4384         MeterSection* prev_m = 0;
4385
4386         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
4387                 MeterSection* m;
4388                 if (!(*i)->is_tempo()) {
4389                         m = static_cast<MeterSection*> (*i);
4390                         if (prev_m && m->beat() > beat) {
4391                                 break;
4392                         }
4393                         prev_m = m;
4394                 }
4395
4396         }
4397         return *prev_m;
4398 }
4399
4400 const MeterSection&
4401 TempoMap::meter_section_at_beat (double beat) const
4402 {
4403         Glib::Threads::RWLock::ReaderLock lm (lock);
4404         return meter_section_at_beat_locked (_metrics, beat);
4405 }
4406
4407 const Meter&
4408 TempoMap::meter_at_frame (framepos_t frame) const
4409 {
4410         TempoMetric m (metric_at (frame));
4411         return m.meter();
4412 }
4413
4414 void
4415 TempoMap::fix_legacy_session ()
4416 {
4417         MeterSection* prev_m = 0;
4418         TempoSection* prev_t = 0;
4419         bool have_initial_t = false;
4420
4421         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4422                 MeterSection* m;
4423                 TempoSection* t;
4424
4425                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
4426                         if (m->initial()) {
4427                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
4428                                 m->set_beat (bbt);
4429                                 m->set_pulse (0.0);
4430                                 m->set_minute (0.0);
4431                                 m->set_position_lock_style (AudioTime);
4432                                 prev_m = m;
4433                                 continue;
4434                         }
4435                         if (prev_m) {
4436                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
4437                                                                           + (m->bbt().beats - 1)
4438                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
4439                                                                           , m->bbt());
4440                                 m->set_beat (start);
4441                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
4442                                         + (m->bbt().beats - 1)
4443                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
4444                                 m->set_pulse (start_beat / prev_m->note_divisor());
4445                         }
4446                         prev_m = m;
4447                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
4448
4449                         if (!t->active()) {
4450                                 continue;
4451                         }
4452
4453                         if (t->initial()) {
4454                                 t->set_pulse (0.0);
4455                                 t->set_minute (0.0);
4456                                 t->set_position_lock_style (AudioTime);
4457                                 prev_t = t;
4458                                 have_initial_t = true;
4459                                 continue;
4460                         }
4461
4462                         if (prev_t) {
4463                                 /* some 4.x sessions have no initial (non-movable) tempo. */
4464                                 if (!have_initial_t) {
4465                                         prev_t->set_pulse (0.0);
4466                                         prev_t->set_minute (0.0);
4467                                         prev_t->set_position_lock_style (AudioTime);
4468                                         prev_t->set_initial (true);
4469                                         prev_t->set_locked_to_meter (true);
4470                                         have_initial_t = true;
4471                                 }
4472
4473                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
4474                                         + (t->legacy_bbt().beats - 1)
4475                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
4476                                 if (prev_m) {
4477                                         t->set_pulse (beat / prev_m->note_divisor());
4478                                 } else {
4479                                         /* really shouldn't happen but.. */
4480                                         t->set_pulse (beat / 4.0);
4481                                 }
4482                         }
4483                         prev_t = t;
4484                 }
4485         }
4486 }
4487 void
4488 TempoMap::fix_legacy_end_session ()
4489 {
4490         TempoSection* prev_t = 0;
4491
4492         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4493                 TempoSection* t;
4494
4495                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
4496
4497                         if (!t->active()) {
4498                                 continue;
4499                         }
4500
4501                         if (prev_t) {
4502                                 if (prev_t->type() == TempoSection::Ramp) {
4503                                         prev_t->set_end_note_types_per_minute (t->note_types_per_minute());
4504                                 } else {
4505                                         prev_t->set_end_note_types_per_minute (prev_t->note_types_per_minute());
4506                                 }
4507                         }
4508
4509                         prev_t = t;
4510                 }
4511         }
4512 }
4513
4514 XMLNode&
4515 TempoMap::get_state ()
4516 {
4517         Metrics::const_iterator i;
4518         XMLNode *root = new XMLNode ("TempoMap");
4519
4520         {
4521                 Glib::Threads::RWLock::ReaderLock lm (lock);
4522                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
4523                         root->add_child_nocopy ((*i)->get_state());
4524                 }
4525         }
4526
4527         return *root;
4528 }
4529
4530 int
4531 TempoMap::set_state (const XMLNode& node, int /*version*/)
4532 {
4533         {
4534                 Glib::Threads::RWLock::WriterLock lm (lock);
4535
4536                 XMLNodeList nlist;
4537                 XMLNodeConstIterator niter;
4538                 Metrics old_metrics (_metrics);
4539                 _metrics.clear();
4540
4541                 nlist = node.children();
4542
4543                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
4544                         XMLNode* child = *niter;
4545
4546                         if (child->name() == TempoSection::xml_state_node_name) {
4547
4548                                 try {
4549                                         TempoSection* ts = new TempoSection (*child, _frame_rate);
4550                                         _metrics.push_back (ts);
4551                                 }
4552
4553                                 catch (failed_constructor& err){
4554                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
4555                                         _metrics = old_metrics;
4556                                         old_metrics.clear();
4557                                         break;
4558                                 }
4559
4560                         } else if (child->name() == MeterSection::xml_state_node_name) {
4561
4562                                 try {
4563                                         MeterSection* ms = new MeterSection (*child, _frame_rate);
4564                                         _metrics.push_back (ms);
4565                                 }
4566
4567                                 catch (failed_constructor& err) {
4568                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
4569                                         _metrics = old_metrics;
4570                                         old_metrics.clear();
4571                                         break;
4572                                 }
4573                         }
4574                 }
4575
4576                 if (niter == nlist.end()) {
4577                         MetricSectionSorter cmp;
4578                         _metrics.sort (cmp);
4579                 }
4580
4581                 /* check for legacy sessions where bbt was the base musical unit for tempo */
4582                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4583                         TempoSection* t;
4584                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
4585                                 if (t->legacy_bbt().bars != 0) {
4586                                         fix_legacy_session();
4587                                         break;
4588                                 }
4589
4590                                 if (t->legacy_end()) {
4591                                         fix_legacy_end_session();
4592                                         break;
4593                                 }
4594
4595                                 break;
4596                         }
4597                 }
4598
4599                 /* check for multiple tempo/meters at the same location, which
4600                    ardour2 somehow allowed.
4601                 */
4602
4603                 Metrics::iterator prev = _metrics.end();
4604                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4605                         if (prev != _metrics.end()) {
4606                                 MeterSection* ms;
4607                                 MeterSection* prev_m;
4608                                 TempoSection* ts;
4609                                 TempoSection* prev_t;
4610                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
4611                                         if (prev_m->pulse() == ms->pulse()) {
4612                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
4613                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
4614                                                 return -1;
4615                                         }
4616                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
4617                                         if (prev_t->pulse() == ts->pulse()) {
4618                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
4619                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
4620                                                 return -1;
4621                                         }
4622                                 }
4623                         }
4624                         prev = i;
4625                 }
4626
4627                 recompute_map (_metrics);
4628
4629                 Metrics::const_iterator d = old_metrics.begin();
4630                 while (d != old_metrics.end()) {
4631                         delete (*d);
4632                         ++d;
4633                 }
4634                 old_metrics.clear ();
4635         }
4636
4637         PropertyChanged (PropertyChange ());
4638
4639         return 0;
4640 }
4641
4642 void
4643 TempoMap::dump (std::ostream& o) const
4644 {
4645         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
4646         const MeterSection* m;
4647         const TempoSection* t;
4648         const TempoSection* prev_t = 0;
4649
4650         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4651
4652                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
4653                         o << "Tempo @ " << *i << " start : " << t->note_types_per_minute() << " end : " << t->end_note_types_per_minute() << " BPM (pulse = 1/" << t->note_type()
4654                           << " type= " << enum_2_string (t->type()) << ") "  << " at pulse= " << t->pulse()
4655                           << " minute= " << t->minute() << " frame= " << t->frame() << " (initial? " << t->initial() << ')'
4656                           << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
4657                         if (prev_t) {
4658                                 o <<  "  current start  : " << t->note_types_per_minute()
4659                                   <<  "  current end  : " << t->end_note_types_per_minute()
4660                                   << " | " << t->pulse() << " | " << t->frame() << " | " << t->minute() << std::endl;
4661                                 o << "  previous     : " << prev_t->note_types_per_minute()
4662                                   << " | " << prev_t->pulse() << " | " << prev_t->frame() << " | " << prev_t->minute() << std::endl;
4663                                 o << "  calculated   : " << prev_t->tempo_at_pulse (t->pulse())
4664                                   << " | " << prev_t->pulse_at_ntpm (prev_t->end_note_types_per_minute(), t->minute())
4665                                   << " | " << frame_at_minute (prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()))
4666                                   << " | " << prev_t->minute_at_ntpm (prev_t->end_note_types_per_minute(), t->pulse()) << std::endl;
4667                         }
4668                         prev_t = t;
4669                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
4670                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt()
4671                           << " frame= " << m->frame() << " pulse: " << m->pulse() <<  " beat : " << m->beat()
4672                           << " pos lock: " << enum_2_string (m->position_lock_style()) << " (initial? " << m->initial() << ')' << endl;
4673                 }
4674         }
4675         o << "------" << std::endl;
4676 }
4677
4678 int
4679 TempoMap::n_tempos() const
4680 {
4681         Glib::Threads::RWLock::ReaderLock lm (lock);
4682         int cnt = 0;
4683
4684         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4685                 if ((*i)->is_tempo()) {
4686                         cnt++;
4687                 }
4688         }
4689
4690         return cnt;
4691 }
4692
4693 int
4694 TempoMap::n_meters() const
4695 {
4696         Glib::Threads::RWLock::ReaderLock lm (lock);
4697         int cnt = 0;
4698
4699         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4700                 if (!(*i)->is_tempo()) {
4701                         cnt++;
4702                 }
4703         }
4704
4705         return cnt;
4706 }
4707
4708 void
4709 TempoMap::insert_time (framepos_t where, framecnt_t amount)
4710 {
4711         for (Metrics::reverse_iterator i = _metrics.rbegin(); i != _metrics.rend(); ++i) {
4712                 if ((*i)->frame() >= where && !(*i)->initial ()) {
4713                         MeterSection* ms;
4714                         TempoSection* ts;
4715
4716                         if ((ms = dynamic_cast <MeterSection*>(*i)) != 0) {
4717                                 gui_set_meter_position (ms, (*i)->frame() + amount);
4718                         }
4719
4720                         if ((ts = dynamic_cast <TempoSection*>(*i)) != 0) {
4721                                 gui_set_tempo_position (ts, (*i)->frame() + amount, 0);
4722                         }
4723                 }
4724         }
4725
4726         PropertyChanged (PropertyChange ());
4727 }
4728
4729 bool
4730 TempoMap::remove_time (framepos_t where, framecnt_t amount)
4731 {
4732         bool moved = false;
4733
4734         std::list<MetricSection*> metric_kill_list;
4735
4736         TempoSection* last_tempo = NULL;
4737         MeterSection* last_meter = NULL;
4738         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
4739         bool meter_after = false; // is there a meter marker likewise?
4740         {
4741                 Glib::Threads::RWLock::WriterLock lm (lock);
4742                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
4743                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
4744                                 metric_kill_list.push_back(*i);
4745                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
4746                                 if (lt)
4747                                         last_tempo = lt;
4748                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
4749                                 if (lm)
4750                                         last_meter = lm;
4751                         }
4752                         else if ((*i)->frame() >= where) {
4753                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
4754                                 (*i)->set_minute ((*i)->minute() - minute_at_frame (amount));
4755                                 if ((*i)->frame() == where) {
4756                                         // marker was immediately after end of range
4757                                         tempo_after = dynamic_cast<TempoSection*> (*i);
4758                                         meter_after = dynamic_cast<MeterSection*> (*i);
4759                                 }
4760                                 moved = true;
4761                         }
4762                 }
4763
4764                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
4765                 if (last_tempo && !tempo_after) {
4766                         metric_kill_list.remove(last_tempo);
4767                         last_tempo->set_minute (minute_at_frame (where));
4768                         moved = true;
4769                 }
4770                 if (last_meter && !meter_after) {
4771                         metric_kill_list.remove(last_meter);
4772                         last_meter->set_minute (minute_at_frame (where));
4773                         moved = true;
4774                 }
4775
4776                 //remove all the remaining metrics
4777                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
4778                         _metrics.remove(*i);
4779                         moved = true;
4780                 }
4781
4782                 if (moved) {
4783                         recompute_map (_metrics);
4784                 }
4785         }
4786         PropertyChanged (PropertyChange ());
4787         return moved;
4788 }
4789
4790 /** Add some (fractional) Beats to a session frame position, and return the result in frames.
4791  *  pos can be -ve, if required.
4792  */
4793 framepos_t
4794 TempoMap::framepos_plus_qn (framepos_t frame, Evoral::Beats beats) const
4795 {
4796         Glib::Threads::RWLock::ReaderLock lm (lock);
4797         const double frame_qn = pulse_at_minute_locked (_metrics, minute_at_frame (frame)) * 4.0;
4798
4799         return frame_at_minute (minute_at_pulse_locked (_metrics, (frame_qn + beats.to_double()) / 4.0));
4800 }
4801
4802 framepos_t
4803 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
4804 {
4805         Glib::Threads::RWLock::ReaderLock lm (lock);
4806
4807         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_minute_locked (_metrics, minute_at_frame (pos)));
4808         pos_bbt.ticks += op.ticks;
4809         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
4810                 ++pos_bbt.beats;
4811                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
4812         }
4813         pos_bbt.beats += op.beats;
4814         /* the meter in effect will start on the bar */
4815         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();
4816         while (pos_bbt.beats >= divisions_per_bar + 1) {
4817                 ++pos_bbt.bars;
4818                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
4819                 pos_bbt.beats -= divisions_per_bar;
4820         }
4821         pos_bbt.bars += op.bars;
4822
4823         return frame_at_minute (minute_at_bbt_locked (_metrics, pos_bbt));
4824 }
4825
4826 /** Count the number of beats that are equivalent to distance when going forward,
4827     starting at pos.
4828 */
4829 Evoral::Beats
4830 TempoMap::framewalk_to_qn (framepos_t pos, framecnt_t distance) const
4831 {
4832         Glib::Threads::RWLock::ReaderLock lm (lock);
4833
4834         return Evoral::Beats (quarter_notes_between_frames_locked (_metrics, pos, pos + distance));
4835 }
4836
4837 struct bbtcmp {
4838     bool operator() (const BBT_Time& a, const BBT_Time& b) {
4839             return a < b;
4840     }
4841 };
4842
4843 std::ostream&
4844 operator<< (std::ostream& o, const Meter& m) {
4845         return o << m.divisions_per_bar() << '/' << m.note_divisor();
4846 }
4847
4848 std::ostream&
4849 operator<< (std::ostream& o, const Tempo& t) {
4850         return o << t.note_types_per_minute() << " 1/" << t.note_type() << "'s per minute";
4851 }
4852
4853 std::ostream&
4854 operator<< (std::ostream& o, const MetricSection& section) {
4855
4856         o << "MetricSection @ " << section.frame() << ' ';
4857
4858         const TempoSection* ts;
4859         const MeterSection* ms;
4860
4861         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
4862                 o << *((const Tempo*) ts);
4863         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
4864                 o << *((const Meter*) ms);
4865         }
4866
4867         return o;
4868 }