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