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