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