ca21d32e4874e1ffb4785c39886383f28204cf76
[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)
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    beat b 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& b, const framecnt_t& frame_rate) const
227 {
228         if (_type == Constant || _c_func == 0.0) {
229                 return ((b - 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), 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   Tempo is the rate of the musical pulse.
590   Meters divide the pulses into measures and beats.
591
592   Note that Tempo::beats_per_minute() has nothing to do with musical beats.
593   It should rather be thought of as tempo note divisions per minute.
594
595   TempoSections, which are nice to think of in whole pulses per minute,
596   and MeterSecions which divide tempo pulses into measures (via divisions_per_bar)
597   and beats (via note_divisor) are used to form a tempo map.
598   TempoSections and MeterSections may be locked to either audio or music (position lock style).
599   We construct the tempo map by first using the frame or pulse position (depending on position lock style) of each tempo.
600   We then use this pulse/frame layout to find the beat & pulse or frame position of each meter (again depending on lock style).
601
602   Having done this, we can now find any one of tempo, beat, frame or pulse if a beat, frame, pulse or tempo is known.
603
604   With tepo sections potentially being ramped, meters provide a way of mapping beats to whole pulses without
605   referring to the tempo function(s) involved as the distance in whole pulses between a meter and a subsequent beat is
606   sb->beat() - meter->beat() / meter->note_divisor().
607   Because every meter falls on a known pulse, (derived from its bar), the rest is easy as the duration in pulses between
608   two meters is of course
609   (meater_b->bar - meter_a->bar) * meter_a->divisions_per_bar / meter_a->note_divisor.
610
611   Below, beat calculations are based on meter sections and all pulse and tempo calculations are based on tempo sections.
612   Beat to frame conversion of course requires the use of meter and tempo.
613
614   Remembering that ramped tempo sections interact, it is important to avoid referring to any other tempos when moving tempo sections,
615   Here, beats (meters) are used to determine the new pulse (see predict_tempo_position())
616
617   The first tempo and first meter are special. they must move together, and must be locked to audio.
618   Audio locked tempos which lie before the first meter are made inactive.
619   They will be re-activated if the first meter is again placed before them.
620
621   Both tempos and meters have a pulse position and a frame position.
622   Meters also have a beat position, which is always 0.0 for the first meter.
623
624   A tempo locked to music is locked to musical pulses.
625   A meter locked to music is locked to beats.
626
627   Recomputing the tempo map is the process where the 'missing' position
628   (tempo pulse or meter pulse & beat in the case of AudioTime, frame for MusicTime) is calculated.
629
630   It is important to keep the _metrics in an order that makes sense.
631   Because ramped MusicTime and AudioTime tempos can interact with each other,
632   reordering is frequent. Care must be taken to keep _metrics in a solved state.
633   Solved means ordered by frame or pulse with frame-accurate precision (see check_solved()).
634 */
635 struct MetricSectionSorter {
636     bool operator() (const MetricSection* a, const MetricSection* b) {
637             return a->pulse() < b->pulse();
638     }
639 };
640
641 struct MetricSectionFrameSorter {
642     bool operator() (const MetricSection* a, const MetricSection* b) {
643             return a->frame() < b->frame();
644     }
645 };
646
647 TempoMap::TempoMap (framecnt_t fr)
648 {
649         _frame_rate = fr;
650         BBT_Time start (1, 1, 0);
651
652         TempoSection *t = new TempoSection (0.0, 0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Ramp, AudioTime);
653         MeterSection *m = new MeterSection (0.0, 0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor(), AudioTime);
654
655         t->set_movable (false);
656         m->set_movable (false);
657
658         /* note: frame time is correct (zero) for both of these */
659
660         _metrics.push_back (t);
661         _metrics.push_back (m);
662
663 }
664
665 TempoMap::~TempoMap ()
666 {
667         Metrics::const_iterator d = _metrics.begin();
668         while (d != _metrics.end()) {
669                 delete (*d);
670                 ++d;
671         }
672         _metrics.clear();
673 }
674
675 void
676 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
677 {
678         bool removed = false;
679
680         {
681                 Glib::Threads::RWLock::WriterLock lm (lock);
682                 if ((removed = remove_tempo_locked (tempo))) {
683                         if (complete_operation) {
684                                 recompute_map (_metrics);
685                         }
686                 }
687         }
688
689         if (removed && complete_operation) {
690                 PropertyChanged (PropertyChange ());
691         }
692 }
693
694 bool
695 TempoMap::remove_tempo_locked (const TempoSection& tempo)
696 {
697         Metrics::iterator i;
698
699         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
700                 if (dynamic_cast<TempoSection*> (*i) != 0) {
701                         if (tempo.frame() == (*i)->frame()) {
702                                 if ((*i)->movable()) {
703                                         delete (*i);
704                                         _metrics.erase (i);
705                                         return true;
706                                 }
707                         }
708                 }
709         }
710
711         return false;
712 }
713
714 void
715 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
716 {
717         bool removed = false;
718
719         {
720                 Glib::Threads::RWLock::WriterLock lm (lock);
721                 if ((removed = remove_meter_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_meter_locked (const MeterSection& meter)
735 {
736         Metrics::iterator i;
737
738         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
739                 TempoSection* t = 0;
740                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
741                         if (meter.frame() == (*i)->frame()) {
742                                 if (t->locked_to_meter()) {
743                                         delete (*i);
744                                         _metrics.erase (i);
745                                         break;
746                                 }
747                         }
748                 }
749         }
750
751         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
752                 if (dynamic_cast<MeterSection*> (*i) != 0) {
753                         if (meter.frame() == (*i)->frame()) {
754                                 if ((*i)->movable()) {
755                                         delete (*i);
756                                         _metrics.erase (i);
757                                         return true;
758                                 }
759                         }
760                 }
761         }
762
763         return false;
764 }
765
766 void
767 TempoMap::do_insert (MetricSection* section)
768 {
769         bool need_add = true;
770         /* we only allow new meters to be inserted on beat 1 of an existing
771          * measure.
772          */
773         MeterSection* m = 0;
774         if ((m = dynamic_cast<MeterSection*>(section)) != 0) {
775
776                 if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
777
778                         pair<double, BBT_Time> corrected = make_pair (m->beat(), m->bbt());
779                         corrected.second.beats = 1;
780                         corrected.second.ticks = 0;
781                         corrected.first = beat_at_bbt_locked (_metrics, corrected.second);
782                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
783                                                    m->bbt(), corrected.second) << endmsg;
784                         //m->set_pulse (corrected);
785                 }
786         }
787
788         /* Look for any existing MetricSection that is of the same type and
789            in the same bar as the new one, and remove it before adding
790            the new one. Note that this means that if we find a matching,
791            existing section, we can break out of the loop since we're
792            guaranteed that there is only one such match.
793         */
794
795         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
796
797                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
798                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
799                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
800                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
801
802                 if (tempo && insert_tempo) {
803
804                         /* Tempo sections */
805                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
806                         if ((ipm && tempo->pulse() == insert_tempo->pulse()) || (!ipm && tempo->frame() == insert_tempo->frame())) {
807
808                                 if (!tempo->movable()) {
809
810                                         /* can't (re)move this section, so overwrite
811                                          * its data content (but not its properties as
812                                          * a section).
813                                          */
814
815                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo));
816                                         (*i)->set_position_lock_style (AudioTime);
817                                         TempoSection* t;
818                                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
819                                                 t->set_type (insert_tempo->type());
820                                         }
821                                         need_add = false;
822                                 } else {
823                                         delete (*i);
824                                         _metrics.erase (i);
825                                 }
826                                 break;
827                         }
828
829                 } else if (meter && insert_meter) {
830
831                         /* Meter Sections */
832
833                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
834
835                         if ((ipm && meter->beat() == insert_meter->beat()) || (!ipm && meter->frame() == insert_meter->frame())) {
836
837                                 if (!meter->movable()) {
838
839                                         /* can't (re)move this section, so overwrite
840                                          * its data content (but not its properties as
841                                          * a section
842                                          */
843
844                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
845                                         (*i)->set_position_lock_style (AudioTime);
846                                         need_add = false;
847                                 } else {
848                                         delete (*i);
849                                         _metrics.erase (i);
850                                 }
851
852                                 break;
853                         }
854                 } else {
855                         /* non-matching types, so we don't care */
856                 }
857         }
858
859         /* Add the given MetricSection, if we didn't just reset an existing
860          * one above
861          */
862
863         if (need_add) {
864                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
865                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
866                 Metrics::iterator i;
867                 if (insert_meter) {
868                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
869                                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
870
871                                 if (meter) {
872                                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
873                                         if ((ipm && meter->beat() > insert_meter->beat()) || (!ipm && meter->frame() > insert_meter->frame())) {
874                                                 break;
875                                         }
876                                 }
877                         }
878                 } else if (insert_tempo) {
879                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
880                                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
881
882                                 if (tempo) {
883                                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
884                                         if ((ipm && tempo->pulse() > insert_tempo->pulse()) || (!ipm && tempo->frame() > insert_tempo->frame())) {
885                                                 break;
886                                         }
887                                 }
888                         }
889                 }
890
891                 _metrics.insert (i, section);
892                 //dump (_metrics, std::cout);
893         }
894 }
895
896 TempoSection*
897 TempoMap::add_tempo (const Tempo& tempo, const double& pulse, const framepos_t& frame, ARDOUR::TempoSection::Type type, PositionLockStyle pls)
898 {
899         TempoSection* ts = 0;
900         {
901                 Glib::Threads::RWLock::WriterLock lm (lock);
902                 ts = add_tempo_locked (tempo, pulse, frame, type, pls, true);
903         }
904
905
906         PropertyChanged (PropertyChange ());
907
908         return ts;
909 }
910
911 void
912 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, const framepos_t& frame, TempoSection::Type type, PositionLockStyle pls)
913 {
914         const bool locked_to_meter = ts.locked_to_meter();
915
916         {
917                 Glib::Threads::RWLock::WriterLock lm (lock);
918                 TempoSection& first (first_tempo());
919                 if (ts.frame() != first.frame()) {
920                         remove_tempo_locked (ts);
921                         add_tempo_locked (tempo, pulse, frame, type, pls, true, locked_to_meter);
922                 } else {
923                         first.set_type (type);
924                         first.set_pulse (0.0);
925                         first.set_frame (frame);
926                         first.set_position_lock_style (AudioTime);
927                         {
928                                 /* cannot move the first tempo section */
929                                 *static_cast<Tempo*>(&first) = tempo;
930                                 recompute_map (_metrics);
931                         }
932                 }
933         }
934
935         PropertyChanged (PropertyChange ());
936 }
937
938 TempoSection*
939 TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, framepos_t frame
940                             , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter)
941 {
942         TempoSection* t = new TempoSection (pulse, frame, tempo.beats_per_minute(), tempo.note_type(), type, pls);
943         t->set_locked_to_meter (locked_to_meter);
944
945         do_insert (t);
946
947         if (recompute) {
948                 if (pls == AudioTime) {
949                         solve_map_frame (_metrics, t, t->frame());
950                 } else {
951                         solve_map_pulse (_metrics, t, t->pulse());
952                 }
953                 recompute_meters (_metrics);
954         }
955
956         return t;
957 }
958
959 MeterSection*
960 TempoMap::add_meter (const Meter& meter, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
961 {
962         MeterSection* m = 0;
963         {
964                 Glib::Threads::RWLock::WriterLock lm (lock);
965                 m = add_meter_locked (meter, beat, where, frame, pls, true);
966         }
967
968
969 #ifndef NDEBUG
970         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
971                 dump (_metrics, std::cerr);
972         }
973 #endif
974
975         PropertyChanged (PropertyChange ());
976         return m;
977 }
978
979 void
980 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where, const framepos_t& frame, PositionLockStyle pls)
981 {
982         {
983                 Glib::Threads::RWLock::WriterLock lm (lock);
984                 const double beat = beat_at_bbt_locked (_metrics, where);
985
986                 if (ms.movable()) {
987                         remove_meter_locked (ms);
988                         add_meter_locked (meter, beat, where, frame, pls, true);
989                 } else {
990                         MeterSection& first (first_meter());
991                         TempoSection& first_t (first_tempo());
992                         /* cannot move the first meter section */
993                         *static_cast<Meter*>(&first) = meter;
994                         first.set_position_lock_style (AudioTime);
995                         first.set_pulse (0.0);
996                         first.set_frame (frame);
997                         pair<double, BBT_Time> beat = make_pair (0.0, BBT_Time (1, 1, 0));
998                         first.set_beat (beat);
999                         first_t.set_frame (first.frame());
1000                         first_t.set_pulse (0.0);
1001                         first_t.set_position_lock_style (AudioTime);
1002                         recompute_map (_metrics);
1003                 }
1004         }
1005
1006         PropertyChanged (PropertyChange ());
1007 }
1008
1009 MeterSection*
1010 TempoMap::add_meter_locked (const Meter& meter, double beat, const Timecode::BBT_Time& where, framepos_t frame, PositionLockStyle pls, bool recompute)
1011 {
1012         const MeterSection& prev_m = meter_section_at_locked  (_metrics, frame - 1);
1013         const double pulse = ((where.bars - prev_m.bbt().bars) * (prev_m.divisions_per_bar() / prev_m.note_divisor())) + prev_m.pulse();
1014
1015         if (pls == AudioTime) {
1016                 /* add meter-locked tempo */
1017                 add_tempo_locked (tempo_at_locked (_metrics, frame), pulse,  frame, TempoSection::Ramp, AudioTime, true, true);
1018         }
1019
1020         MeterSection* new_meter = new MeterSection (pulse, frame, beat, where, meter.divisions_per_bar(), meter.note_divisor(), pls);
1021
1022         do_insert (new_meter);
1023
1024         if (recompute) {
1025
1026                 if (pls == AudioTime) {
1027                         solve_map_frame (_metrics, new_meter, frame);
1028                 } else {
1029                         solve_map_bbt (_metrics, new_meter, where);
1030                 }
1031         }
1032
1033         return new_meter;
1034 }
1035
1036 void
1037 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
1038 {
1039         Tempo newtempo (beats_per_minute, note_type);
1040         TempoSection* t;
1041
1042         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1043                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1044                         if (!t->active()) {
1045                                 continue;
1046                         }
1047                         {
1048                                 Glib::Threads::RWLock::WriterLock lm (lock);
1049                                 *((Tempo*) t) = newtempo;
1050                                 recompute_map (_metrics);
1051                         }
1052                         PropertyChanged (PropertyChange ());
1053                         break;
1054                 }
1055         }
1056 }
1057
1058 void
1059 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
1060 {
1061         Tempo newtempo (beats_per_minute, note_type);
1062
1063         TempoSection* prev;
1064         TempoSection* first;
1065         Metrics::iterator i;
1066
1067         /* find the TempoSection immediately preceding "where"
1068          */
1069
1070         for (first = 0, i = _metrics.begin(), prev = 0; i != _metrics.end(); ++i) {
1071
1072                 if ((*i)->frame() > where) {
1073                         break;
1074                 }
1075
1076                 TempoSection* t;
1077
1078                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1079                         if (!t->active()) {
1080                                 continue;
1081                         }
1082                         if (!first) {
1083                                 first = t;
1084                         }
1085                         prev = t;
1086                 }
1087         }
1088
1089         if (!prev) {
1090                 if (!first) {
1091                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
1092                         return;
1093                 }
1094
1095                 prev = first;
1096         }
1097
1098         /* reset */
1099
1100         {
1101                 Glib::Threads::RWLock::WriterLock lm (lock);
1102                 /* cannot move the first tempo section */
1103                 *((Tempo*)prev) = newtempo;
1104                 recompute_map (_metrics);
1105         }
1106
1107         PropertyChanged (PropertyChange ());
1108 }
1109
1110 const MeterSection&
1111 TempoMap::first_meter () const
1112 {
1113         const MeterSection *m = 0;
1114
1115         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1116                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
1117                         return *m;
1118                 }
1119         }
1120
1121         fatal << _("programming error: no meter section in tempo map!") << endmsg;
1122         abort(); /*NOTREACHED*/
1123         return *m;
1124 }
1125
1126 MeterSection&
1127 TempoMap::first_meter ()
1128 {
1129         MeterSection *m = 0;
1130
1131         /* CALLER MUST HOLD LOCK */
1132
1133         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1134                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1135                         return *m;
1136                 }
1137         }
1138
1139         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1140         abort(); /*NOTREACHED*/
1141         return *m;
1142 }
1143
1144 const TempoSection&
1145 TempoMap::first_tempo () const
1146 {
1147         const TempoSection *t = 0;
1148
1149         /* CALLER MUST HOLD LOCK */
1150
1151         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1152                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1153                         if (!t->active()) {
1154                                 continue;
1155                         }
1156                         if (!t->movable()) {
1157                                 return *t;
1158                         }
1159                 }
1160         }
1161
1162         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1163         abort(); /*NOTREACHED*/
1164         return *t;
1165 }
1166
1167 TempoSection&
1168 TempoMap::first_tempo ()
1169 {
1170         TempoSection *t = 0;
1171
1172         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1173                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1174                         if (!t->active()) {
1175                                 continue;
1176                         }
1177                         if (!t->movable()) {
1178                                 return *t;
1179                         }
1180                 }
1181         }
1182
1183         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1184         abort(); /*NOTREACHED*/
1185         return *t;
1186 }
1187 void
1188 TempoMap::recompute_tempos (Metrics& metrics)
1189 {
1190         TempoSection* prev_t = 0;
1191
1192         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1193                 TempoSection* t;
1194
1195                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1196                         if (!t->active()) {
1197                                 continue;
1198                         }
1199                         if (!t->movable()) {
1200                                 if (!prev_t) {
1201                                         t->set_pulse (0.0);
1202                                         prev_t = t;
1203                                         continue;
1204                                 }
1205                         }
1206                         if (prev_t) {
1207                                 if (t->position_lock_style() == AudioTime) {
1208                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1209                                         if (!t->locked_to_meter()) {
1210                                                 t->set_pulse (prev_t->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate));
1211                                         }
1212
1213                                 } else {
1214                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1215                                         t->set_frame (prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate));
1216
1217                                 }
1218                         }
1219                         prev_t = t;
1220                 }
1221         }
1222         prev_t->set_c_func (0.0);
1223 }
1224
1225 /* tempos must be positioned correctly.
1226    the current approach is to use a meter's bbt time as its base position unit.
1227    an audio-locked meter requires a recomputation of pulse and beat (but not bbt),
1228    while a music-locked meter requires recomputations of frame pulse and beat (but not bbt)
1229 */
1230 void
1231 TempoMap::recompute_meters (Metrics& metrics)
1232 {
1233         MeterSection* meter = 0;
1234         MeterSection* prev_m = 0;
1235
1236         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1237                 if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
1238                         if (meter->position_lock_style() == AudioTime) {
1239                                 double pulse = 0.0;
1240                                 pair<double, BBT_Time> b_bbt;
1241                                 TempoSection* meter_locked_tempo = 0;
1242                                 for (Metrics::const_iterator ii = metrics.begin(); ii != metrics.end(); ++ii) {
1243                                         TempoSection* t;
1244                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
1245                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == meter->frame()) {
1246                                                         meter_locked_tempo = t;
1247                                                         break;
1248                                                 }
1249                                         }
1250                                 }
1251
1252                                 if (prev_m) {
1253                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1254                                         if (beats + prev_m->beat() != meter->beat()) {
1255                                                 /* reordering caused a bbt change */
1256                                                 b_bbt = make_pair (beats + prev_m->beat()
1257                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1258                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1259
1260                                         } else if (meter->movable()) {
1261                                                 b_bbt = make_pair (meter->beat(), meter->bbt());
1262                                                 pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
1263                                         }
1264                                 } else {
1265                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
1266                                 }
1267                                 if (meter_locked_tempo) {
1268                                         meter_locked_tempo->set_pulse (pulse);
1269                                 }
1270                                 meter->set_beat (b_bbt);
1271                                 meter->set_pulse (pulse);
1272
1273                         } else {
1274                                 /* MusicTime */
1275                                 double pulse = 0.0;
1276                                 pair<double, BBT_Time> b_bbt;
1277                                 if (prev_m) {
1278                                         const double beats = (meter->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
1279                                         if (beats + prev_m->beat() != meter->beat()) {
1280                                                 /* reordering caused a bbt change */
1281                                                 b_bbt = make_pair (beats + prev_m->beat()
1282                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
1283                                         } else {
1284                                                 b_bbt = make_pair (beats + prev_m->beat(), meter->bbt());
1285                                         }
1286                                         pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
1287                                 } else {
1288                                         /* shouldn't happen - the first is audio-locked */
1289                                         pulse = pulse_at_beat_locked (metrics, meter->beat());
1290                                         b_bbt = make_pair (meter->beat(), meter->bbt());
1291                                 }
1292
1293                                 meter->set_beat (b_bbt);
1294                                 meter->set_pulse (pulse);
1295                                 meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1296                         }
1297
1298                         prev_m = meter;
1299                 }
1300         }
1301 }
1302
1303 void
1304 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1305 {
1306         /* CALLER MUST HOLD WRITE LOCK */
1307
1308         if (end < 0) {
1309
1310                 /* we will actually stop once we hit
1311                    the last metric.
1312                 */
1313                 end = max_framepos;
1314
1315         }
1316
1317         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1318
1319         if (end == 0) {
1320                 /* silly call from Session::process() during startup
1321                  */
1322                 return;
1323         }
1324
1325         recompute_tempos (metrics);
1326         recompute_meters (metrics);
1327 }
1328
1329 TempoMetric
1330 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1331 {
1332         Glib::Threads::RWLock::ReaderLock lm (lock);
1333         TempoMetric m (first_meter(), first_tempo());
1334
1335         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1336            at something, because we insert the default tempo and meter during
1337            TempoMap construction.
1338
1339            now see if we can find better candidates.
1340         */
1341
1342         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1343
1344                 if ((*i)->frame() > frame) {
1345                         break;
1346                 }
1347
1348                 m.set_metric(*i);
1349
1350                 if (last) {
1351                         *last = i;
1352                 }
1353         }
1354
1355         return m;
1356 }
1357
1358 /* XX meters only */
1359 TempoMetric
1360 TempoMap::metric_at (BBT_Time bbt) const
1361 {
1362         Glib::Threads::RWLock::ReaderLock lm (lock);
1363         TempoMetric m (first_meter(), first_tempo());
1364
1365         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1366            at something, because we insert the default tempo and meter during
1367            TempoMap construction.
1368
1369            now see if we can find better candidates.
1370         */
1371
1372         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1373                 MeterSection* mw;
1374                 if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
1375                         BBT_Time section_start (mw->bbt());
1376
1377                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1378                                 break;
1379                         }
1380
1381                         m.set_metric (*i);
1382                 }
1383         }
1384
1385         return m;
1386 }
1387
1388 double
1389 TempoMap::pulse_at_beat (const double& beat) const
1390 {
1391         Glib::Threads::RWLock::ReaderLock lm (lock);
1392         return pulse_at_beat_locked (_metrics, beat);
1393 }
1394
1395 double
1396 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1397 {
1398         MeterSection* prev_m = 0;
1399
1400         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1401                 MeterSection* m;
1402                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1403                         if (prev_m && m->beat() > beat) {
1404                                 break;
1405                         }
1406                         prev_m = m;
1407                 }
1408
1409         }
1410         double const ret = prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1411         return ret;
1412 }
1413
1414 double
1415 TempoMap::beat_at_pulse (const double& pulse) const
1416 {
1417         Glib::Threads::RWLock::ReaderLock lm (lock);
1418         return beat_at_pulse_locked (_metrics, pulse);
1419 }
1420
1421 double
1422 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1423 {
1424         MeterSection* prev_m = 0;
1425
1426         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1427                 MeterSection* m;
1428                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1429                         if (prev_m && m->pulse() > pulse) {
1430                                 if (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > m->beat()) {
1431                                         break;
1432                                 }
1433                         }
1434                         prev_m = m;
1435                 }
1436         }
1437
1438         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1439         return ret;
1440 }
1441
1442 double
1443 TempoMap::pulse_at_frame (const framecnt_t& frame) const
1444 {
1445         Glib::Threads::RWLock::ReaderLock lm (lock);
1446         return pulse_at_frame_locked (_metrics, frame);
1447 }
1448
1449 /* tempo section based */
1450 double
1451 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1452 {
1453         /* HOLD (at least) THE READER LOCK */
1454         TempoSection* prev_t = 0;
1455
1456         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1457                 TempoSection* t;
1458                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1459                         if (!t->active()) {
1460                                 continue;
1461                         }
1462                         if (prev_t && t->frame() > frame) {
1463                                 /*the previous ts is the one containing the frame */
1464                                 const double ret = prev_t->pulse_at_frame (frame, _frame_rate);
1465                                 return ret;
1466                         }
1467                         prev_t = t;
1468                 }
1469         }
1470
1471         /* treated as constant for this ts */
1472         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1473
1474         return pulses_in_section + prev_t->pulse();
1475 }
1476
1477 framecnt_t
1478 TempoMap::frame_at_pulse (const double& pulse) const
1479 {
1480         Glib::Threads::RWLock::ReaderLock lm (lock);
1481         return frame_at_pulse_locked (_metrics, pulse);
1482 }
1483
1484 /* tempo section based */
1485 framecnt_t
1486 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1487 {
1488         /* HOLD THE READER LOCK */
1489
1490         const TempoSection* prev_t = 0;
1491
1492         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1493                 TempoSection* t;
1494
1495                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1496                         if (!t->active()) {
1497                                 continue;
1498                         }
1499                         if (prev_t && t->pulse() > pulse) {
1500                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1501                         }
1502
1503                         prev_t = t;
1504                 }
1505         }
1506         /* must be treated as constant, irrespective of _type */
1507         double const pulses_in_section = pulse - prev_t->pulse();
1508         double const dtime = pulses_in_section * prev_t->frames_per_pulse (_frame_rate);
1509
1510         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_t->frame();
1511
1512         return ret;
1513 }
1514
1515 double
1516 TempoMap::beat_at_frame (const framecnt_t& frame) const
1517 {
1518         Glib::Threads::RWLock::ReaderLock lm (lock);
1519         return beat_at_frame_locked (_metrics, frame);
1520 }
1521
1522 /* meter / tempo section based */
1523 double
1524 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1525 {
1526         const TempoSection& ts = tempo_section_at_locked (metrics, frame);
1527         MeterSection* prev_m = 0;
1528         MeterSection* next_m = 0;
1529
1530         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1531                 MeterSection* m;
1532                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1533                         if (prev_m && m->frame() > frame) {
1534                                 next_m = m;
1535                                 break;
1536                         }
1537                         prev_m = m;
1538                 }
1539         }
1540         if (frame < prev_m->frame()) {
1541                 return 0.0;
1542         }
1543         const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
1544
1545         if (next_m && next_m->beat() < beat) {
1546                 return next_m->beat();
1547         }
1548
1549         return beat;
1550 }
1551
1552 framecnt_t
1553 TempoMap::frame_at_beat (const double& beat) const
1554 {
1555         Glib::Threads::RWLock::ReaderLock lm (lock);
1556         return frame_at_beat_locked (_metrics, beat);
1557 }
1558
1559 /* meter section based */
1560 framecnt_t
1561 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1562 {
1563         const TempoSection& prev_t = tempo_section_at_beat_locked (metrics, beat);
1564         MeterSection* prev_m = 0;
1565
1566         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1567                 MeterSection* m;
1568                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1569                         if (prev_m && m->beat() > beat) {
1570                                 break;
1571                         }
1572                         prev_m = m;
1573                 }
1574         }
1575
1576         return prev_t.frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
1577 }
1578
1579 double
1580 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1581 {
1582         Glib::Threads::RWLock::ReaderLock lm (lock);
1583         return beat_at_bbt_locked (_metrics, bbt);
1584 }
1585
1586
1587 double
1588 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1589 {
1590         /* CALLER HOLDS READ LOCK */
1591
1592         MeterSection* prev_m = 0;
1593
1594         /* because audio-locked meters have 'fake' integral beats,
1595            there is no pulse offset here.
1596         */
1597         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1598                 MeterSection* m;
1599                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1600                         if (prev_m) {
1601                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1602                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1603                                         break;
1604                                 }
1605                         }
1606                         prev_m = m;
1607                 }
1608         }
1609
1610         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1611         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1612         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1613
1614         return ret;
1615 }
1616
1617 Timecode::BBT_Time
1618 TempoMap::bbt_at_beat (const double& beats)
1619 {
1620         Glib::Threads::RWLock::ReaderLock lm (lock);
1621         return bbt_at_beat_locked (_metrics, beats);
1622 }
1623
1624 Timecode::BBT_Time
1625 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1626 {
1627         /* CALLER HOLDS READ LOCK */
1628         MeterSection* prev_m = 0;
1629         const double beats = max (0.0, b);
1630
1631         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1632                 MeterSection* m = 0;
1633
1634                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1635                         if (prev_m) {
1636                                 if (m->beat() > beats) {
1637                                         /* this is the meter after the one our beat is on*/
1638                                         break;
1639                                 }
1640                         }
1641
1642                         prev_m = m;
1643                 }
1644         }
1645
1646         const double beats_in_ms = beats - prev_m->beat();
1647         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1648         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1649         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1650         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1651
1652         BBT_Time ret;
1653
1654         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1655         ret.beats = (uint32_t) floor (remaining_beats);
1656         ret.bars = total_bars;
1657
1658         /* 0 0 0 to 1 1 0 - based mapping*/
1659         ++ret.bars;
1660         ++ret.beats;
1661
1662         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1663                 ++ret.beats;
1664                 ret.ticks -= BBT_Time::ticks_per_beat;
1665         }
1666
1667         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1668                 ++ret.bars;
1669                 ret.beats = 1;
1670         }
1671
1672         return ret;
1673 }
1674
1675 double
1676 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1677 {
1678         Glib::Threads::RWLock::ReaderLock lm (lock);
1679
1680         return pulse_at_bbt_locked (_metrics, bbt);
1681 }
1682
1683 double
1684 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1685 {
1686         /* CALLER HOLDS READ LOCK */
1687
1688         MeterSection* prev_m = 0;
1689
1690         /* because audio-locked meters have 'fake' integral beats,
1691            there is no pulse offset here.
1692         */
1693         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1694                 MeterSection* m;
1695                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1696                         if (prev_m) {
1697                                 if (m->bbt().bars > bbt.bars) {
1698                                         break;
1699                                 }
1700                         }
1701                         prev_m = m;
1702                 }
1703         }
1704
1705         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1706         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1707         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1708
1709         return ret;
1710 }
1711
1712 Timecode::BBT_Time
1713 TempoMap::bbt_at_pulse (const double& pulse)
1714 {
1715         Glib::Threads::RWLock::ReaderLock lm (lock);
1716
1717         return bbt_at_pulse_locked (_metrics, pulse);
1718 }
1719
1720 Timecode::BBT_Time
1721 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1722 {
1723         MeterSection* prev_m = 0;
1724
1725         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1726                 MeterSection* m = 0;
1727
1728                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1729
1730                         if (prev_m) {
1731                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1732                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1733                                         /* this is the meter after the one our beat is on*/
1734                                         break;
1735                                 }
1736                         }
1737
1738                         prev_m = m;
1739                 }
1740         }
1741
1742         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1743         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1744         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1745         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1746         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1747
1748         BBT_Time ret;
1749
1750         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1751         ret.beats = (uint32_t) floor (remaining_beats);
1752         ret.bars = total_bars;
1753
1754         /* 0 0 0 to 1 1 0 mapping*/
1755         ++ret.bars;
1756         ++ret.beats;
1757
1758         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1759                 ++ret.beats;
1760                 ret.ticks -= BBT_Time::ticks_per_beat;
1761         }
1762
1763         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1764                 ++ret.bars;
1765                 ret.beats = 1;
1766         }
1767
1768         return ret;
1769 }
1770
1771 void
1772 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1773 {
1774
1775         if (frame < 0) {
1776                 bbt.bars = 1;
1777                 bbt.beats = 1;
1778                 bbt.ticks = 0;
1779                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1780                 return;
1781         }
1782         Glib::Threads::RWLock::ReaderLock lm (lock);
1783         const double beat = beat_at_frame_locked (_metrics, frame);
1784
1785         bbt = bbt_at_beat_locked (_metrics, beat);
1786 }
1787
1788 framepos_t
1789 TempoMap::frame_time (const BBT_Time& bbt)
1790 {
1791         if (bbt.bars < 1) {
1792                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1793                 return 0;
1794         }
1795
1796         if (bbt.beats < 1) {
1797                 throw std::logic_error ("beats are counted from one");
1798         }
1799         Glib::Threads::RWLock::ReaderLock lm (lock);
1800
1801         return frame_time_locked (_metrics, bbt);
1802 }
1803
1804 /* meter section based */
1805 framepos_t
1806 TempoMap::frame_time_locked (const Metrics& metrics, const BBT_Time& bbt) const
1807 {
1808         /* HOLD THE READER LOCK */
1809
1810         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
1811         return ret;
1812 }
1813
1814 bool
1815 TempoMap::check_solved (const Metrics& metrics) const
1816 {
1817         TempoSection* prev_t = 0;
1818         MeterSection* prev_m = 0;
1819
1820         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1821                 TempoSection* t;
1822                 MeterSection* m;
1823                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1824                         if (!t->active()) {
1825                                 continue;
1826                         }
1827                         if (prev_t) {
1828                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
1829                                         return false;
1830                                 }
1831
1832                                 /* precision check ensures tempo and frames align.*/
1833                                 if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
1834                                         if (!t->locked_to_meter()) {
1835                                                 return false;
1836                                         }
1837                                 }
1838                         }
1839                         prev_t = t;
1840                 }
1841
1842                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1843                         if (prev_m && m->position_lock_style() == AudioTime) {
1844                                 TempoSection* t = const_cast<TempoSection*>(&tempo_section_at_locked (metrics, m->frame() - 1));
1845                                 const double nascent_m_pulse = ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
1846                                 const framepos_t nascent_m_frame = t->frame_at_pulse (nascent_m_pulse, _frame_rate);
1847
1848                                 if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
1849                                         return false;
1850                                 }
1851                         }
1852
1853                         prev_m = m;
1854                 }
1855
1856         }
1857
1858         return true;
1859 }
1860
1861 bool
1862 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
1863 {
1864         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1865                 TempoSection* t;
1866                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1867                         if (!t->movable()) {
1868                                 t->set_active (true);
1869                                 continue;
1870                         }
1871                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
1872                                 t->set_active (false);
1873                                 t->set_pulse (0.0);
1874                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
1875                                 t->set_active (true);
1876                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
1877                                 return false;
1878                         }
1879                 }
1880         }
1881         return true;
1882 }
1883
1884 bool
1885 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
1886 {
1887         TempoSection* prev_t = 0;
1888         TempoSection* section_prev = 0;
1889         framepos_t first_m_frame = 0;
1890
1891         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1892                 MeterSection* m;
1893                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1894                         if (!m->movable()) {
1895                                 first_m_frame = m->frame();
1896                                 break;
1897                         }
1898                 }
1899         }
1900         if (section->movable() && frame <= first_m_frame) {
1901                 return false;
1902         }
1903
1904         section->set_active (true);
1905         section->set_frame (frame);
1906
1907         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1908                 TempoSection* t;
1909                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1910
1911                         if (!t->active()) {
1912                                 continue;
1913                         }
1914                         if (prev_t) {
1915                                 if (t == section) {
1916                                         section_prev = prev_t;
1917                                         continue;
1918                                 }
1919                                 if (t->position_lock_style() == MusicTime) {
1920                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1921                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
1922                                 } else {
1923                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1924                                         if (!t->locked_to_meter()) {
1925                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
1926                                         }
1927                                 }
1928                         }
1929                         prev_t = t;
1930                 }
1931         }
1932
1933         if (section_prev) {
1934                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
1935                 if (!section->locked_to_meter()) {
1936                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
1937                 }
1938         }
1939
1940         recompute_tempos (imaginary);
1941
1942         if (check_solved (imaginary)) {
1943                 return true;
1944         }
1945
1946         MetricSectionFrameSorter fcmp;
1947         imaginary.sort (fcmp);
1948
1949         recompute_tempos (imaginary);
1950
1951         if (check_solved (imaginary)) {
1952                 return true;
1953         }
1954
1955         return false;
1956 }
1957
1958 bool
1959 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
1960 {
1961         TempoSection* prev_t = 0;
1962         TempoSection* section_prev = 0;
1963
1964         section->set_pulse (pulse);
1965
1966         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1967                 TempoSection* t;
1968                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1969                         if (!t->active()) {
1970                                 continue;
1971                         }
1972                         if (!t->movable()) {
1973                                 t->set_pulse (0.0);
1974                                 prev_t = t;
1975                                 continue;
1976                         }
1977                         if (prev_t) {
1978                                 if (t == section) {
1979                                         section_prev = prev_t;
1980                                         continue;
1981                                 }
1982                                 if (t->position_lock_style() == MusicTime) {
1983                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1984                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
1985                                 } else {
1986                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1987                                         if (!t->locked_to_meter()) {
1988                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
1989                                         }
1990                                 }
1991                         }
1992                         prev_t = t;
1993                 }
1994         }
1995
1996         if (section_prev) {
1997                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
1998                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
1999         }
2000
2001         recompute_tempos (imaginary);
2002
2003         if (check_solved (imaginary)) {
2004                 return true;
2005         }
2006
2007         MetricSectionSorter cmp;
2008         imaginary.sort (cmp);
2009
2010         recompute_tempos (imaginary);
2011         /* Reordering
2012          * XX need a restriction here, but only for this case,
2013          * as audio locked tempos don't interact in the same way.
2014          *
2015          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2016          * e.g.
2017          * |50 bpm                        |250 bpm |60 bpm
2018          *                drag 250 to the pulse after 60->
2019          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2020          */
2021         if (check_solved (imaginary)) {
2022                 return true;
2023         }
2024
2025         return false;
2026 }
2027
2028 bool
2029 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2030 {
2031         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2032         const MeterSection* other =  &meter_section_at_locked (imaginary, frame);
2033         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2034                 return false;
2035         }
2036
2037         if (!section->movable()) {
2038                 /* lock the first tempo to our first meter */
2039                 if (!set_active_tempos (imaginary, frame)) {
2040                         return false;
2041                 }
2042         }
2043
2044         /* it would make sense to bail out if there is no audio-locked meter,
2045            however it may be desirable to move a music-locked meter by frame at some point.
2046         */
2047         TempoSection* meter_locked_tempo = 0;
2048         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2049                 TempoSection* t;
2050                 if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2051                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2052                                 meter_locked_tempo = t;
2053                                 break;
2054                         }
2055                 }
2056         }
2057
2058         if (!meter_locked_tempo) {
2059                 return false;
2060         }
2061
2062         MeterSection* prev_m = 0;
2063         Metrics future_map;
2064         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2065         bool solved = false;
2066
2067         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2068                 MeterSection* m;
2069                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2070                         if (m == section){
2071                                 if (prev_m && section->movable()) {
2072                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2073                                         if (beats + prev_m->beat() < section->beat()) {
2074                                                 /* set the frame/pulse corresponding to its musical position,
2075                                                  * as an earlier time than this has been requested.
2076                                                 */
2077                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2078                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2079
2080                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2081
2082                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2083                                                         meter_locked_tempo->set_pulse (new_pulse);
2084                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2085                                                         section->set_frame (smallest_frame);
2086                                                         section->set_pulse (new_pulse);
2087                                                 } else {
2088                                                         solved = false;
2089                                                 }
2090
2091                                                 Metrics::const_iterator d = future_map.begin();
2092                                                 while (d != future_map.end()) {
2093                                                         delete (*d);
2094                                                         ++d;
2095                                                 }
2096
2097                                                 if (!solved) {
2098                                                         return false;
2099                                                 }
2100                                         } else {
2101                                                 /* all is ok. set section's tempo */
2102                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_locked (future_map, section->frame()));
2103                                                 meter_copy->set_frame (frame);
2104
2105                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2106                                                         section->set_frame (frame);
2107                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2108                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2109                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2110                                                 } else {
2111                                                         solved = false;
2112                                                 }
2113
2114                                                 Metrics::const_iterator d = future_map.begin();
2115                                                 while (d != future_map.end()) {
2116                                                         delete (*d);
2117                                                         ++d;
2118                                                 }
2119
2120                                                 if (!solved) {
2121                                                         return false;
2122                                                 }
2123                                         }
2124                                 } else {
2125                                         /* not movable (first meter atm) */
2126
2127                                         tempo_copy->set_frame (frame);
2128                                         tempo_copy->set_pulse (0.0);
2129
2130                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2131                                                 section->set_frame (frame);
2132                                                 meter_locked_tempo->set_frame (frame);
2133                                                 meter_locked_tempo->set_pulse (0.0);
2134                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2135                                         } else {
2136                                                 solved = false;
2137                                         }
2138
2139                                         Metrics::const_iterator d = future_map.begin();
2140                                         while (d != future_map.end()) {
2141                                                 delete (*d);
2142                                                 ++d;
2143                                         }
2144
2145                                         if (!solved) {
2146                                                 return false;
2147                                         }
2148
2149                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2150                                         section->set_beat (b_bbt);
2151                                         section->set_pulse (0.0);
2152
2153                                 }
2154                                 break;
2155                         }
2156
2157                         prev_m = m;
2158                 }
2159         }
2160
2161         MetricSectionFrameSorter fcmp;
2162         imaginary.sort (fcmp);
2163
2164         recompute_meters (imaginary);
2165
2166         return true;
2167 }
2168
2169 bool
2170 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2171 {
2172         /* disallow setting section to an existing meter's bbt */
2173         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2174                 MeterSection* m;
2175                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2176                         if (m != section && m->bbt().bars == when.bars) {
2177                                 return false;
2178                         }
2179                 }
2180         }
2181
2182         MeterSection* prev_m = 0;
2183         MeterSection* section_prev = 0;
2184
2185         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2186                 MeterSection* m;
2187                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2188                         pair<double, BBT_Time> b_bbt;
2189                         double new_pulse = 0.0;
2190
2191                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2192                                 section_prev = prev_m;
2193                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2194                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2195                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2196
2197                                 section->set_beat (b_bbt);
2198                                 section->set_pulse (pulse);
2199                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2200                                 prev_m = section;
2201                                 continue;
2202                         }
2203
2204                         if (m->position_lock_style() == AudioTime) {
2205                                 TempoSection* meter_locked_tempo = 0;
2206
2207                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2208                                         TempoSection* t;
2209                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2210                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2211                                                         meter_locked_tempo = t;
2212                                                         break;
2213                                                 }
2214                                         }
2215                                 }
2216
2217                                 if (!meter_locked_tempo) {
2218                                         return false;
2219                                 }
2220
2221                                 if (prev_m) {
2222                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2223
2224                                         if (beats + prev_m->beat() != m->beat()) {
2225                                                 /* tempo/ meter change caused a change in beat (bar). */
2226                                                 b_bbt = make_pair (beats + prev_m->beat()
2227                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2228                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2229                                         } else if (m->movable()) {
2230                                                 b_bbt = make_pair (m->beat(), m->bbt());
2231                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2232                                         }
2233                                 } else {
2234                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2235                                 }
2236
2237                                 meter_locked_tempo->set_pulse (new_pulse);
2238                                 m->set_beat (b_bbt);
2239                                 m->set_pulse (new_pulse);
2240
2241                         } else {
2242                                 /* MusicTime */
2243                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2244                                 if (beats + prev_m->beat() != m->beat()) {
2245                                         /* tempo/ meter change caused a change in beat (bar). */
2246                                         b_bbt = make_pair (beats + prev_m->beat()
2247                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2248                                 } else {
2249                                         b_bbt = make_pair (beats + prev_m->beat()
2250                                                            , m->bbt());
2251                                 }
2252                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2253                                 m->set_beat (b_bbt);
2254                                 m->set_pulse (new_pulse);
2255                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2256                         }
2257
2258                         prev_m = m;
2259                 }
2260         }
2261
2262         if (!section_prev) {
2263
2264                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2265                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2266                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2267
2268                 section->set_beat (b_bbt);
2269                 section->set_pulse (pulse);
2270                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2271         }
2272
2273         MetricSectionSorter cmp;
2274         imaginary.sort (cmp);
2275
2276         recompute_meters (imaginary);
2277
2278         return true;
2279 }
2280
2281 /** places a copy of _metrics into copy and returns a pointer
2282  *  to section's equivalent in copy.
2283  */
2284 TempoSection*
2285 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2286 {
2287         TempoSection* ret = 0;
2288
2289         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2290                 TempoSection* t;
2291                 MeterSection* m;
2292                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2293                         if (t == section) {
2294                                 ret = new TempoSection (*t);
2295                                 copy.push_back (ret);
2296                                 continue;
2297                         }
2298
2299                         TempoSection* cp = new TempoSection (*t);
2300                         copy.push_back (cp);
2301                 }
2302                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2303                         MeterSection* cp = new MeterSection (*m);
2304                         copy.push_back (cp);
2305                 }
2306         }
2307
2308         return ret;
2309 }
2310
2311 MeterSection*
2312 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2313 {
2314         MeterSection* ret = 0;
2315
2316         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2317                 TempoSection* t;
2318                 MeterSection* m;
2319                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2320                         TempoSection* cp = new TempoSection (*t);
2321                         copy.push_back (cp);
2322                 }
2323
2324                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2325                         if (m == section) {
2326                                 ret = new MeterSection (*m);
2327                                 copy.push_back (ret);
2328                                 continue;
2329                         }
2330                         MeterSection* cp = new MeterSection (*m);
2331                         copy.push_back (cp);
2332                 }
2333         }
2334
2335         return ret;
2336 }
2337
2338 bool
2339 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2340 {
2341         Metrics copy;
2342         TempoSection* tempo_copy = 0;
2343
2344         {
2345                 Glib::Threads::RWLock::ReaderLock lm (lock);
2346                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2347                 if (!tempo_copy) {
2348                         return false;
2349                 }
2350         }
2351
2352         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2353
2354         Metrics::const_iterator d = copy.begin();
2355         while (d != copy.end()) {
2356                 delete (*d);
2357                 ++d;
2358         }
2359
2360         return ret;
2361 }
2362
2363 /**
2364 * 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,
2365 * taking any possible reordering as a consequence of this into account.
2366 * @param section - the section to be altered
2367 * @param bbt - the bbt where the altered tempo will fall
2368 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2369 */
2370 pair<double, framepos_t>
2371 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2372 {
2373         Metrics future_map;
2374         pair<double, framepos_t> ret = make_pair (0.0, 0);
2375
2376         Glib::Threads::RWLock::ReaderLock lm (lock);
2377
2378         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2379
2380         const double beat = beat_at_bbt_locked (future_map, bbt);
2381
2382         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2383                 ret.first = tempo_copy->pulse();
2384                 ret.second = tempo_copy->frame();
2385         } else {
2386                 ret.first = section->pulse();
2387                 ret.second = section->frame();
2388         }
2389
2390         Metrics::const_iterator d = future_map.begin();
2391         while (d != future_map.end()) {
2392                 delete (*d);
2393                 ++d;
2394         }
2395         return ret;
2396 }
2397
2398 void
2399 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame)
2400 {
2401         Metrics future_map;
2402
2403         if (ts->position_lock_style() == MusicTime) {
2404                 {
2405                         Glib::Threads::RWLock::WriterLock lm (lock);
2406                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2407                         const double pulse = pulse_at_frame_locked (future_map, frame);
2408                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2409                                 solve_map_pulse (_metrics, ts, pulse);
2410                                 recompute_meters (_metrics);
2411                         }
2412                 }
2413
2414         } else {
2415
2416                 {
2417                         Glib::Threads::RWLock::WriterLock lm (lock);
2418                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2419                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2420                                 solve_map_frame (_metrics, ts, frame);
2421                                 recompute_meters (_metrics);
2422                         }
2423                 }
2424         }
2425
2426         Metrics::const_iterator d = future_map.begin();
2427         while (d != future_map.end()) {
2428                 delete (*d);
2429                 ++d;
2430         }
2431
2432         MetricPositionChanged (); // Emit Signal
2433 }
2434
2435 void
2436 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2437 {
2438         Metrics future_map;
2439
2440         if (ms->position_lock_style() == AudioTime) {
2441
2442                 {
2443                         Glib::Threads::RWLock::WriterLock lm (lock);
2444                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2445
2446                         if (solve_map_frame (future_map, copy, frame)) {
2447                                 solve_map_frame (_metrics, ms, frame);
2448                                 recompute_tempos (_metrics);
2449                         }
2450                 }
2451         } else {
2452                 {
2453                         Glib::Threads::RWLock::WriterLock lm (lock);
2454                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2455
2456                         const double beat = beat_at_frame_locked (_metrics, frame);
2457                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2458
2459                         if (solve_map_bbt (future_map, copy, bbt)) {
2460                                 solve_map_bbt (_metrics, ms, bbt);
2461                                 recompute_tempos (_metrics);
2462                         }
2463                 }
2464         }
2465
2466         Metrics::const_iterator d = future_map.begin();
2467         while (d != future_map.end()) {
2468                 delete (*d);
2469                 ++d;
2470         }
2471
2472         MetricPositionChanged (); // Emit Signal
2473 }
2474
2475 bool
2476 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2477 {
2478         Metrics future_map;
2479         bool can_solve = false;
2480         {
2481                 Glib::Threads::RWLock::WriterLock lm (lock);
2482                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2483                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2484                 recompute_tempos (future_map);
2485
2486                 if (check_solved (future_map)) {
2487                         ts->set_beats_per_minute (bpm.beats_per_minute());
2488                         recompute_map (_metrics);
2489                         can_solve = true;
2490                 }
2491         }
2492
2493         Metrics::const_iterator d = future_map.begin();
2494         while (d != future_map.end()) {
2495                 delete (*d);
2496                 ++d;
2497         }
2498         if (can_solve) {
2499                 MetricPositionChanged (); // Emit Signal
2500         }
2501         return can_solve;
2502 }
2503
2504 void
2505 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2506 {
2507         /*
2508           Ts (future prev_t)   Tnext
2509           |                    |
2510           |     [drag^]        |
2511           |----------|----------
2512                 e_f  pulse(frame)
2513         */
2514
2515         Metrics future_map;
2516
2517         {
2518                 Glib::Threads::RWLock::WriterLock lm (lock);
2519
2520                 if (!ts) {
2521                         return;
2522                 }
2523
2524                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2525                 TempoSection* prev_to_prev_t = 0;
2526                 const frameoffset_t fr_off = end_frame - frame;
2527
2528                 if (prev_t && prev_t->pulse() > 0.0) {
2529                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
2530                 }
2531
2532                 TempoSection* next_t = 0;
2533                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2534                         TempoSection* t = 0;
2535                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2536                                 if (t->frame() > ts->frame()) {
2537                                         next_t = t;
2538                                         break;
2539                                 }
2540                         }
2541                 }
2542
2543                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2544                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2545                 */
2546                 double contribution = 0.0;
2547                 double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2548
2549                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2550                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2551                 }
2552
2553                 frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2554                 double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2555                 double new_bpm;
2556
2557                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2558
2559                         if (prev_t->position_lock_style() == MusicTime) {
2560                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2561
2562                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2563                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2564
2565                                 } else {
2566                                         /* prev to prev is irrelevant */
2567
2568                                         if (start_pulse != prev_t->pulse()) {
2569                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2570                                         } else {
2571                                                 new_bpm = prev_t->beats_per_minute();
2572                                         }
2573                                 }
2574                         } else {
2575                                 /* AudioTime */
2576                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2577                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
2578                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
2579                                 } else {
2580                                         /* prev_to_prev_t is irrelevant */
2581
2582                                         if (end_frame != prev_t->frame()) {
2583                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2584                                         } else {
2585                                                 new_bpm = prev_t->beats_per_minute();
2586                                         }
2587                                 }
2588                         }
2589                 } else {
2590
2591                         double frame_ratio;
2592                         double pulse_ratio;
2593                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2594
2595                         if (prev_to_prev_t) {
2596
2597                                 frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2598                                 pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2599                         } else {
2600
2601                                 frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2602                                 pulse_ratio = (start_pulse / end_pulse);
2603                         }
2604                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2605                 }
2606
2607                 prev_t->set_beats_per_minute (new_bpm);
2608                 recompute_tempos (future_map);
2609                 recompute_meters (future_map);
2610
2611                 if (check_solved (future_map)) {
2612                         ts->set_beats_per_minute (new_bpm);
2613                         recompute_tempos (_metrics);
2614                         recompute_meters (_metrics);
2615                 }
2616         }
2617
2618         Metrics::const_iterator d = future_map.begin();
2619         while (d != future_map.end()) {
2620                 delete (*d);
2621                 ++d;
2622         }
2623
2624         MetricPositionChanged (); // Emit Signal
2625 }
2626
2627 framecnt_t
2628 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2629 {
2630         Glib::Threads::RWLock::ReaderLock lm (lock);
2631
2632         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2633         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2634         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2635
2636         return frame_at_beat_locked (_metrics, total_beats);
2637 }
2638
2639 framepos_t
2640 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2641 {
2642         return round_to_type (fr, dir, Bar);
2643 }
2644
2645 framepos_t
2646 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2647 {
2648         return round_to_type (fr, dir, Beat);
2649 }
2650
2651 framepos_t
2652 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2653 {
2654         Glib::Threads::RWLock::ReaderLock lm (lock);
2655         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2656         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2657         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2658
2659         ticks -= beats * BBT_Time::ticks_per_beat;
2660
2661         if (dir > 0) {
2662                 /* round to next (or same iff dir == RoundUpMaybe) */
2663
2664                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2665
2666                 if (mod == 0 && dir == RoundUpMaybe) {
2667                         /* right on the subdivision, which is fine, so do nothing */
2668
2669                 } else if (mod == 0) {
2670                         /* right on the subdivision, so the difference is just the subdivision ticks */
2671                         ticks += ticks_one_subdivisions_worth;
2672
2673                 } else {
2674                         /* not on subdivision, compute distance to next subdivision */
2675
2676                         ticks += ticks_one_subdivisions_worth - mod;
2677                 }
2678
2679                 if (ticks >= BBT_Time::ticks_per_beat) {
2680                         ticks -= BBT_Time::ticks_per_beat;
2681                 }
2682         } else if (dir < 0) {
2683
2684                 /* round to previous (or same iff dir == RoundDownMaybe) */
2685
2686                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2687
2688                 if (difference == 0 && dir == RoundDownAlways) {
2689                         /* right on the subdivision, but force-rounding down,
2690                            so the difference is just the subdivision ticks */
2691                         difference = ticks_one_subdivisions_worth;
2692                 }
2693
2694                 if (ticks < difference) {
2695                         ticks = BBT_Time::ticks_per_beat - ticks;
2696                 } else {
2697                         ticks -= difference;
2698                 }
2699
2700         } else {
2701                 /* round to nearest */
2702                 double rem;
2703
2704                 /* compute the distance to the previous and next subdivision */
2705
2706                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2707
2708                         /* closer to the next subdivision, so shift forward */
2709
2710                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2711
2712                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2713
2714                         if (ticks > BBT_Time::ticks_per_beat) {
2715                                 ++beats;
2716                                 ticks -= BBT_Time::ticks_per_beat;
2717                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2718                         }
2719
2720                 } else if (rem > 0) {
2721
2722                         /* closer to previous subdivision, so shift backward */
2723
2724                         if (rem > ticks) {
2725                                 if (beats == 0) {
2726                                         /* can't go backwards past zero, so ... */
2727                                         return 0;
2728                                 }
2729                                 /* step back to previous beat */
2730                                 --beats;
2731                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2732                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2733                         } else {
2734                                 ticks = lrint (ticks - rem);
2735                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2736                         }
2737                 } else {
2738                         /* on the subdivision, do nothing */
2739                 }
2740         }
2741
2742         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2743
2744         return ret_frame;
2745 }
2746
2747 framepos_t
2748 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2749 {
2750         Glib::Threads::RWLock::ReaderLock lm (lock);
2751
2752         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2753         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
2754
2755         switch (type) {
2756         case Bar:
2757                 if (dir < 0) {
2758                         /* find bar previous to 'frame' */
2759                         bbt.beats = 1;
2760                         bbt.ticks = 0;
2761                         return frame_time_locked (_metrics, bbt);
2762
2763                 } else if (dir > 0) {
2764                         /* find bar following 'frame' */
2765                         ++bbt.bars;
2766                         bbt.beats = 1;
2767                         bbt.ticks = 0;
2768                         return frame_time_locked (_metrics, bbt);
2769                 } else {
2770                         /* true rounding: find nearest bar */
2771                         framepos_t raw_ft = frame_time_locked (_metrics, bbt);
2772                         bbt.beats = 1;
2773                         bbt.ticks = 0;
2774                         framepos_t prev_ft = frame_time_locked (_metrics, bbt);
2775                         ++bbt.bars;
2776                         framepos_t next_ft = frame_time_locked (_metrics, bbt);
2777
2778                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2779                                 return next_ft;
2780                         } else {
2781                                 return prev_ft;
2782                         }
2783                 }
2784
2785                 break;
2786
2787         case Beat:
2788                 if (dir < 0) {
2789                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2790                 } else if (dir > 0) {
2791                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2792                 } else {
2793                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2794                 }
2795                 break;
2796         }
2797
2798         return 0;
2799 }
2800
2801 void
2802 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2803                     framepos_t lower, framepos_t upper)
2804 {
2805         Glib::Threads::RWLock::ReaderLock lm (lock);
2806         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
2807         framecnt_t pos = 0;
2808         /* although the map handles negative beats, bbt doesn't. */
2809         if (cnt < 0.0) {
2810                 cnt = 0.0;
2811         }
2812         while (pos < upper) {
2813                 pos = frame_at_beat_locked (_metrics, cnt);
2814                 const TempoSection tempo = tempo_section_at_locked (_metrics, pos);
2815                 const MeterSection meter = meter_section_at_locked (_metrics, pos);
2816                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
2817                 points.push_back (BBTPoint (meter, tempo_at_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
2818                 ++cnt;
2819         }
2820 }
2821
2822 const TempoSection&
2823 TempoMap::tempo_section_at (framepos_t frame) const
2824 {
2825         Glib::Threads::RWLock::ReaderLock lm (lock);
2826         return tempo_section_at_locked (_metrics, frame);
2827 }
2828
2829 const TempoSection&
2830 TempoMap::tempo_section_at_locked (const Metrics& metrics, framepos_t frame) const
2831 {
2832         Metrics::const_iterator i;
2833         TempoSection* prev = 0;
2834
2835         for (i = metrics.begin(); i != metrics.end(); ++i) {
2836                 TempoSection* t;
2837
2838                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2839                         if (!t->active()) {
2840                                 continue;
2841                         }
2842                         if (prev && t->frame() > frame) {
2843                                 break;
2844                         }
2845
2846                         prev = t;
2847                 }
2848         }
2849
2850         if (prev == 0) {
2851                 fatal << endmsg;
2852                 abort(); /*NOTREACHED*/
2853         }
2854
2855         return *prev;
2856 }
2857
2858 const TempoSection&
2859 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
2860 {
2861         TempoSection* prev_t = 0;
2862         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
2863
2864         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2865                 TempoSection* t;
2866                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2867                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
2868                                 break;
2869                         }
2870                         prev_t = t;
2871                 }
2872
2873         }
2874         return *prev_t;
2875 }
2876
2877 const TempoSection&
2878 TempoMap::tempo_section_at_pulse_locked (const Metrics& metrics, const double& pulse) const
2879 {
2880         TempoSection* prev_t = 0;
2881
2882         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2883                 TempoSection* t;
2884                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2885                         if (prev_t && t->pulse() > pulse) {
2886                                 break;
2887                         }
2888                         prev_t = t;
2889                 }
2890
2891         }
2892         return *prev_t;
2893 }
2894
2895 /* don't use this to calculate length (the tempo is only correct for this frame).
2896    do that stuff based on the beat_at_frame and frame_at_beat api
2897 */
2898 double
2899 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
2900 {
2901         Glib::Threads::RWLock::ReaderLock lm (lock);
2902
2903         const TempoSection* ts_at = &tempo_section_at_locked (_metrics, frame);
2904         const TempoSection* ts_after = 0;
2905         Metrics::const_iterator i;
2906
2907         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2908                 TempoSection* t;
2909
2910                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2911                         if (!t->active()) {
2912                                 continue;
2913                         }
2914                         if ((*i)->frame() > frame) {
2915                                 ts_after = t;
2916                                 break;
2917                         }
2918                 }
2919         }
2920
2921         if (ts_after) {
2922                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
2923         }
2924         /* must be treated as constant tempo */
2925         return ts_at->frames_per_beat (_frame_rate);
2926 }
2927
2928 const Tempo
2929 TempoMap::tempo_at_locked (const Metrics& metrics, const framepos_t& frame) const
2930 {
2931         TempoSection* prev_t = 0;
2932
2933         Metrics::const_iterator i;
2934
2935         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2936                 TempoSection* t;
2937                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2938                         if (!t->active()) {
2939                                 continue;
2940                         }
2941                         if ((prev_t) && t->frame() > frame) {
2942                                 /* t is the section past frame */
2943                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
2944                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
2945                                 return ret_tempo;
2946                         }
2947                         prev_t = t;
2948                 }
2949         }
2950
2951         const double ret = prev_t->beats_per_minute();
2952         const Tempo ret_tempo (ret, prev_t->note_type ());
2953
2954         return ret_tempo;
2955 }
2956
2957 const Tempo
2958 TempoMap::tempo_at (const framepos_t& frame) const
2959 {
2960         Glib::Threads::RWLock::ReaderLock lm (lock);
2961         return tempo_at_locked (_metrics, frame);
2962 }
2963
2964 const MeterSection&
2965 TempoMap::meter_section_at_locked (const Metrics& metrics, framepos_t frame) const
2966 {
2967         Metrics::const_iterator i;
2968         MeterSection* prev = 0;
2969
2970         for (i = metrics.begin(); i != metrics.end(); ++i) {
2971                 MeterSection* m;
2972
2973                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2974
2975                         if (prev && (*i)->frame() > frame) {
2976                                 break;
2977                         }
2978
2979                         prev = m;
2980                 }
2981         }
2982
2983         if (prev == 0) {
2984                 fatal << endmsg;
2985                 abort(); /*NOTREACHED*/
2986         }
2987
2988         return *prev;
2989 }
2990
2991
2992 const MeterSection&
2993 TempoMap::meter_section_at (framepos_t frame) const
2994 {
2995         Glib::Threads::RWLock::ReaderLock lm (lock);
2996         return meter_section_at_locked (_metrics, frame);
2997 }
2998
2999 const MeterSection&
3000 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3001 {
3002         MeterSection* prev_m = 0;
3003
3004         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3005                 MeterSection* m;
3006                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3007                         if (prev_m && m->beat() > beat) {
3008                                 break;
3009                         }
3010                         prev_m = m;
3011                 }
3012
3013         }
3014         return *prev_m;
3015 }
3016
3017 const MeterSection&
3018 TempoMap::meter_section_at_beat (double beat) const
3019 {
3020         Glib::Threads::RWLock::ReaderLock lm (lock);
3021         return meter_section_at_beat_locked (_metrics, beat);
3022 }
3023
3024 const Meter&
3025 TempoMap::meter_at (framepos_t frame) const
3026 {
3027         TempoMetric m (metric_at (frame));
3028         return m.meter();
3029 }
3030
3031 void
3032 TempoMap::fix_legacy_session ()
3033 {
3034         MeterSection* prev_m = 0;
3035         TempoSection* prev_t = 0;
3036
3037         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3038                 MeterSection* m;
3039                 TempoSection* t;
3040
3041                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3042                         if (!m->movable()) {
3043                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3044                                 m->set_beat (bbt);
3045                                 m->set_pulse (0.0);
3046                                 m->set_frame (0);
3047                                 m->set_position_lock_style (AudioTime);
3048                                 prev_m = m;
3049                                 continue;
3050                         }
3051                         if (prev_m) {
3052                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3053                                                                           + (m->bbt().beats - 1)
3054                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3055                                                                           , m->bbt());
3056                                 m->set_beat (start);
3057                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3058                                         + (m->bbt().beats - 1)
3059                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3060                                 m->set_pulse (start_beat / prev_m->note_divisor());
3061                         }
3062                         prev_m = m;
3063                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3064
3065                         if (!t->active()) {
3066                                 continue;
3067                         }
3068
3069                         if (!t->movable()) {
3070                                 t->set_pulse (0.0);
3071                                 t->set_frame (0);
3072                                 t->set_position_lock_style (AudioTime);
3073                                 prev_t = t;
3074                                 continue;
3075                         }
3076
3077                         if (prev_t) {
3078                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3079                                         + (t->legacy_bbt().beats - 1)
3080                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3081                                 if (prev_m) {
3082                                         t->set_pulse (beat / prev_m->note_divisor());
3083                                 } else {
3084                                         /* really shouldn't happen but.. */
3085                                         t->set_pulse (beat / 4.0);
3086                                 }
3087                         }
3088                         prev_t = t;
3089                 }
3090         }
3091 }
3092
3093 XMLNode&
3094 TempoMap::get_state ()
3095 {
3096         Metrics::const_iterator i;
3097         XMLNode *root = new XMLNode ("TempoMap");
3098
3099         {
3100                 Glib::Threads::RWLock::ReaderLock lm (lock);
3101                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3102                         root->add_child_nocopy ((*i)->get_state());
3103                 }
3104         }
3105
3106         return *root;
3107 }
3108
3109 int
3110 TempoMap::set_state (const XMLNode& node, int /*version*/)
3111 {
3112         {
3113                 Glib::Threads::RWLock::WriterLock lm (lock);
3114
3115                 XMLNodeList nlist;
3116                 XMLNodeConstIterator niter;
3117                 Metrics old_metrics (_metrics);
3118                 _metrics.clear();
3119
3120                 nlist = node.children();
3121
3122                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3123                         XMLNode* child = *niter;
3124
3125                         if (child->name() == TempoSection::xml_state_node_name) {
3126
3127                                 try {
3128                                         TempoSection* ts = new TempoSection (*child);
3129                                         _metrics.push_back (ts);
3130                                 }
3131
3132                                 catch (failed_constructor& err){
3133                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3134                                         _metrics = old_metrics;
3135                                         break;
3136                                 }
3137
3138                         } else if (child->name() == MeterSection::xml_state_node_name) {
3139
3140                                 try {
3141                                         MeterSection* ms = new MeterSection (*child);
3142                                         _metrics.push_back (ms);
3143                                 }
3144
3145                                 catch (failed_constructor& err) {
3146                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3147                                         _metrics = old_metrics;
3148                                         break;
3149                                 }
3150                         }
3151                 }
3152
3153                 if (niter == nlist.end()) {
3154                         MetricSectionSorter cmp;
3155                         _metrics.sort (cmp);
3156                 }
3157
3158                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3159                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3160                         TempoSection* t;
3161                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3162                                 if (t->legacy_bbt().bars != 0) {
3163                                         fix_legacy_session();
3164                                         break;
3165                                 }
3166                                 break;
3167                         }
3168                 }
3169
3170                 /* check for multiple tempo/meters at the same location, which
3171                    ardour2 somehow allowed.
3172                 */
3173
3174                 Metrics::iterator prev = _metrics.end();
3175                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3176                         if (prev != _metrics.end()) {
3177                                 MeterSection* ms;
3178                                 MeterSection* prev_m;
3179                                 TempoSection* ts;
3180                                 TempoSection* prev_t;
3181                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3182                                         if (prev_m->pulse() == ms->pulse()) {
3183                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3184                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3185                                                 return -1;
3186                                         }
3187                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3188                                         if (prev_t->pulse() == ts->pulse()) {
3189                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3190                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3191                                                 return -1;
3192                                         }
3193                                 }
3194                         }
3195                         prev = i;
3196                 }
3197
3198                 recompute_map (_metrics);
3199         }
3200
3201         PropertyChanged (PropertyChange ());
3202
3203         return 0;
3204 }
3205
3206 void
3207 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3208 {
3209         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3210         const MeterSection* m;
3211         const TempoSection* t;
3212         const TempoSection* prev_t = 0;
3213
3214         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3215
3216                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3217                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3218                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3219                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3220                         if (prev_t) {
3221                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3222                                 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;
3223                         }
3224                         prev_t = t;
3225                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3226                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3227                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3228                 }
3229         }
3230         o << "------" << std::endl;
3231 }
3232
3233 int
3234 TempoMap::n_tempos() const
3235 {
3236         Glib::Threads::RWLock::ReaderLock lm (lock);
3237         int cnt = 0;
3238
3239         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3240                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3241                         cnt++;
3242                 }
3243         }
3244
3245         return cnt;
3246 }
3247
3248 int
3249 TempoMap::n_meters() const
3250 {
3251         Glib::Threads::RWLock::ReaderLock lm (lock);
3252         int cnt = 0;
3253
3254         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3255                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3256                         cnt++;
3257                 }
3258         }
3259
3260         return cnt;
3261 }
3262
3263 void
3264 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3265 {
3266         {
3267                 Glib::Threads::RWLock::WriterLock lm (lock);
3268                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3269                         if ((*i)->frame() >= where && (*i)->movable ()) {
3270                                 (*i)->set_frame ((*i)->frame() + amount);
3271                         }
3272                 }
3273
3274                 /* now reset the BBT time of all metrics, based on their new
3275                  * audio time. This is the only place where we do this reverse
3276                  * timestamp.
3277                  */
3278
3279                 Metrics::iterator i;
3280                 const MeterSection* meter;
3281                 const TempoSection* tempo;
3282                 MeterSection *m;
3283                 TempoSection *t;
3284
3285                 meter = &first_meter ();
3286                 tempo = &first_tempo ();
3287
3288                 BBT_Time start;
3289                 BBT_Time end;
3290
3291                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3292
3293                 bool first = true;
3294                 MetricSection* prev = 0;
3295
3296                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3297
3298                         BBT_Time bbt;
3299                         //TempoMetric metric (*meter, *tempo);
3300                         MeterSection* ms = const_cast<MeterSection*>(meter);
3301                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3302                         if (prev) {
3303                                 if (ts){
3304                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3305                                                 if (!t->active()) {
3306                                                         continue;
3307                                                 }
3308                                                 ts->set_pulse (t->pulse());
3309                                         }
3310                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3311                                                 ts->set_pulse (m->pulse());
3312                                         }
3313                                         ts->set_frame (prev->frame());
3314
3315                                 }
3316                                 if (ms) {
3317                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3318                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3319                                                 ms->set_beat (start);
3320                                                 ms->set_pulse (m->pulse());
3321                                         }
3322                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3323                                                 if (!t->active()) {
3324                                                         continue;
3325                                                 }
3326                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3327                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3328                                                 ms->set_beat (start);
3329                                                 ms->set_pulse (t->pulse());
3330                                         }
3331                                         ms->set_frame (prev->frame());
3332                                 }
3333
3334                         } else {
3335                                 // metric will be at frames=0 bbt=1|1|0 by default
3336                                 // which is correct for our purpose
3337                         }
3338
3339                         // cerr << bbt << endl;
3340
3341                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3342                                 if (!t->active()) {
3343                                         continue;
3344                                 }
3345                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3346                                 tempo = t;
3347                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3348                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3349                                 bbt_time (m->frame(), bbt);
3350
3351                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3352
3353                                 if (first) {
3354                                         first = false;
3355                                 } else {
3356
3357                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3358                                                 /* round up to next beat */
3359                                                 bbt.beats += 1;
3360                                         }
3361
3362                                         bbt.ticks = 0;
3363
3364                                         if (bbt.beats != 1) {
3365                                                 /* round up to next bar */
3366                                                 bbt.bars += 1;
3367                                                 bbt.beats = 1;
3368                                         }
3369                                 }
3370                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3371                                 m->set_beat (start);
3372                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3373                                 meter = m;
3374                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3375                         } else {
3376                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3377                                 abort(); /*NOTREACHED*/
3378                         }
3379
3380                         prev = (*i);
3381                 }
3382
3383                 recompute_map (_metrics);
3384         }
3385
3386
3387         PropertyChanged (PropertyChange ());
3388 }
3389 bool
3390 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3391 {
3392         bool moved = false;
3393
3394         std::list<MetricSection*> metric_kill_list;
3395
3396         TempoSection* last_tempo = NULL;
3397         MeterSection* last_meter = NULL;
3398         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3399         bool meter_after = false; // is there a meter marker likewise?
3400         {
3401                 Glib::Threads::RWLock::WriterLock lm (lock);
3402                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3403                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3404                                 metric_kill_list.push_back(*i);
3405                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3406                                 if (lt)
3407                                         last_tempo = lt;
3408                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3409                                 if (lm)
3410                                         last_meter = lm;
3411                         }
3412                         else if ((*i)->frame() >= where) {
3413                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3414                                 (*i)->set_frame ((*i)->frame() - amount);
3415                                 if ((*i)->frame() == where) {
3416                                         // marker was immediately after end of range
3417                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3418                                         meter_after = dynamic_cast<MeterSection*> (*i);
3419                                 }
3420                                 moved = true;
3421                         }
3422                 }
3423
3424                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3425                 if (last_tempo && !tempo_after) {
3426                         metric_kill_list.remove(last_tempo);
3427                         last_tempo->set_frame(where);
3428                         moved = true;
3429                 }
3430                 if (last_meter && !meter_after) {
3431                         metric_kill_list.remove(last_meter);
3432                         last_meter->set_frame(where);
3433                         moved = true;
3434                 }
3435
3436                 //remove all the remaining metrics
3437                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3438                         _metrics.remove(*i);
3439                         moved = true;
3440                 }
3441
3442                 if (moved) {
3443                         recompute_map (_metrics);
3444                 }
3445         }
3446         PropertyChanged (PropertyChange ());
3447         return moved;
3448 }
3449
3450 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3451  *  pos can be -ve, if required.
3452  */
3453 framepos_t
3454 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3455 {
3456         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
3457 }
3458
3459 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3460 framepos_t
3461 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3462 {
3463         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
3464 }
3465
3466 /** Add the BBT interval op to pos and return the result */
3467 framepos_t
3468 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3469 {
3470         Glib::Threads::RWLock::ReaderLock lm (lock);
3471
3472         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3473         pos_bbt.ticks += op.ticks;
3474         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3475                 ++pos_bbt.beats;
3476                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3477         }
3478         pos_bbt.beats += op.beats;
3479         /* the meter in effect will start on the bar */
3480         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();
3481         while (pos_bbt.beats >= divisions_per_bar + 1) {
3482                 ++pos_bbt.bars;
3483                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3484                 pos_bbt.beats -= divisions_per_bar;
3485         }
3486         pos_bbt.bars += op.bars;
3487
3488         return frame_time_locked (_metrics, pos_bbt);
3489 }
3490
3491 /** Count the number of beats that are equivalent to distance when going forward,
3492     starting at pos.
3493 */
3494 Evoral::Beats
3495 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3496 {
3497         return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
3498 }
3499
3500 struct bbtcmp {
3501     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3502             return a < b;
3503     }
3504 };
3505
3506 std::ostream&
3507 operator<< (std::ostream& o, const Meter& m) {
3508         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3509 }
3510
3511 std::ostream&
3512 operator<< (std::ostream& o, const Tempo& t) {
3513         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3514 }
3515
3516 std::ostream&
3517 operator<< (std::ostream& o, const MetricSection& section) {
3518
3519         o << "MetricSection @ " << section.frame() << ' ';
3520
3521         const TempoSection* ts;
3522         const MeterSection* ms;
3523
3524         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3525                 o << *((const Tempo*) ts);
3526         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3527                 o << *((const Meter*) ms);
3528         }
3529
3530         return o;
3531 }