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