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