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