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