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