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