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