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