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