Tempo ramps - implement TempoMap::tempo_at_beat().
[ardour.git] / libs / ardour / tempo.cc
1 /*
2     Copyright (C) 2000-2002 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <algorithm>
21 #include <stdexcept>
22 #include <cmath>
23
24 #include <unistd.h>
25
26 #include <glibmm/threads.h>
27
28 #include "pbd/enumwriter.h"
29 #include "pbd/xml++.h"
30 #include "evoral/Beats.hpp"
31
32 #include "ardour/debug.h"
33 #include "ardour/lmath.h"
34 #include "ardour/tempo.h"
35
36 #include "i18n.h"
37 #include <locale.h>
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace PBD;
42
43 using Timecode::BBT_Time;
44
45 /* _default tempo is 4/4 qtr=120 */
46
47 Meter    TempoMap::_default_meter (4.0, 4.0);
48 Tempo    TempoMap::_default_tempo (120.0);
49
50 /***********************************************************************/
51
52 double
53 Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
54 {
55         /* This is tempo- and meter-sensitive. The number it returns
56            is based on the interval between any two lines in the
57            grid that is constructed from tempo and meter sections.
58
59            The return value IS NOT interpretable in terms of "beats".
60         */
61
62         return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
63 }
64
65 double
66 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
67 {
68         return frames_per_grid (tempo, sr) * _divisions_per_bar;
69 }
70
71 /***********************************************************************/
72
73 const string TempoSection::xml_state_node_name = "Tempo";
74
75 TempoSection::TempoSection (const XMLNode& node)
76         : MetricSection (0.0, 0, MusicTime)
77         , Tempo (TempoMap::default_tempo())
78         , _c_func (0.0)
79         , _active (true)
80         , _locked_to_meter (false)
81 {
82         XMLProperty const * prop;
83         LocaleGuard lg;
84         BBT_Time bbt;
85         double pulse;
86         uint32_t frame;
87
88         _legacy_bbt = BBT_Time (0, 0, 0);
89
90         if ((prop = node.property ("start")) != 0) {
91                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
92                             &bbt.bars,
93                             &bbt.beats,
94                             &bbt.ticks) == 3) {
95                         /* legacy session - start used to be in bbt*/
96                         _legacy_bbt = bbt;
97                         pulse = -1.0;
98                         info << _("Legacy session detected. TempoSection XML node will be altered.") << endmsg;
99                 }
100         }
101
102         if ((prop = node.property ("pulse")) != 0) {
103                 if (sscanf (prop->value().c_str(), "%lf", &pulse) != 1) {
104                         error << _("TempoSection XML node has an illegal \"pulse\" value") << endmsg;
105                 }
106         }
107
108         set_pulse (pulse);
109
110         if ((prop = node.property ("frame")) != 0) {
111                 if (sscanf (prop->value().c_str(), "%" PRIu32, &frame) != 1) {
112                         error << _("TempoSection XML node has an illegal \"frame\" value") << endmsg;
113                 } else {
114                         set_frame (frame);
115                 }
116         }
117
118         if ((prop = node.property ("beats-per-minute")) == 0) {
119                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
120                 throw failed_constructor();
121         }
122
123         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
124                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
125                 throw failed_constructor();
126         }
127
128         if ((prop = node.property ("note-type")) == 0) {
129                 /* older session, make note type be quarter by default */
130                 _note_type = 4.0;
131         } else {
132                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
133                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
134                         throw failed_constructor();
135                 }
136         }
137
138         if ((prop = node.property ("movable")) == 0) {
139                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
140                 throw failed_constructor();
141         }
142
143         set_movable (string_is_affirmative (prop->value()));
144
145         if ((prop = node.property ("active")) == 0) {
146                 warning << _("TempoSection XML node has no \"active\" property") << endmsg;
147                 set_active(true);
148         } else {
149                 set_active (string_is_affirmative (prop->value()));
150         }
151
152         if ((prop = node.property ("tempo-type")) == 0) {
153                 _type = Constant;
154         } else {
155                 _type = Type (string_2_enum (prop->value(), _type));
156         }
157
158         if ((prop = node.property ("lock-style")) == 0) {
159                 if (movable()) {
160                         set_position_lock_style (MusicTime);
161                 } else {
162                         set_position_lock_style (AudioTime);
163                 }
164         } else {
165                 set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
166         }
167
168         if ((prop = node.property ("locked-to-meter")) == 0) {
169                 set_locked_to_meter (false);
170         } else {
171                 set_locked_to_meter (string_is_affirmative (prop->value()));
172         }
173 }
174
175 XMLNode&
176 TempoSection::get_state() const
177 {
178         XMLNode *root = new XMLNode (xml_state_node_name);
179         char buf[256];
180         LocaleGuard lg;
181
182         snprintf (buf, sizeof (buf), "%f", pulse());
183         root->add_property ("pulse", buf);
184         snprintf (buf, sizeof (buf), "%li", frame());
185         root->add_property ("frame", buf);
186         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
187         root->add_property ("beats-per-minute", buf);
188         snprintf (buf, sizeof (buf), "%f", _note_type);
189         root->add_property ("note-type", buf);
190         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
191         root->add_property ("movable", buf);
192         snprintf (buf, sizeof (buf), "%s", active()?"yes":"no");
193         root->add_property ("active", buf);
194         root->add_property ("tempo-type", enum_2_string (_type));
195         root->add_property ("lock-style", enum_2_string (position_lock_style()));
196         root->add_property ("locked-to-meter", locked_to_meter()?"yes":"no");
197
198         return *root;
199 }
200
201 void
202 TempoSection::set_type (Type type)
203 {
204         _type = type;
205 }
206
207 /** returns the tempo in whole pulses per minute at the zero-based (relative to session) frame.
208 */
209 double
210 TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
211 {
212
213         if (_type == Constant || _c_func == 0.0) {
214                 return pulses_per_minute();
215         }
216
217         return pulse_tempo_at_time (frame_to_minute (f - frame(), frame_rate));
218 }
219
220 /** returns the zero-based frame (relative to session)
221    where the tempo in whole pulses per minute occurs in this section.
222    pulse p is only used for constant tempos.
223    note that the tempo map may have multiple such values.
224 */
225 framepos_t
226 TempoSection::frame_at_tempo (const double& ppm, const double& p, const framecnt_t& frame_rate) const
227 {
228         if (_type == Constant || _c_func == 0.0) {
229                 return ((p - pulse()) * frames_per_pulse (frame_rate))  + frame();
230         }
231
232         return minute_to_frame (time_at_pulse_tempo (ppm), frame_rate) + frame();
233 }
234 /** returns the tempo in pulses per minute at the zero-based (relative to session) beat.
235 */
236 double
237 TempoSection::tempo_at_pulse (const double& p) const
238 {
239
240         if (_type == Constant || _c_func == 0.0) {
241                 return pulses_per_minute();
242         }
243         double const ppm = pulse_tempo_at_pulse (p - pulse());
244         return ppm;
245 }
246
247 /** returns the zero-based beat (relative to session)
248    where the tempo in whole pulses per minute occurs given frame f. frame f is only used for constant tempos.
249    note that the session tempo map may have multiple beats at a given tempo.
250 */
251 double
252 TempoSection::pulse_at_tempo (const double& ppm, const framepos_t& f, const framecnt_t& frame_rate) const
253 {
254         if (_type == Constant || _c_func == 0.0) {
255                 double const pulses = ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
256                 return  pulses;
257         }
258         return pulse_at_pulse_tempo (ppm) + pulse();
259 }
260
261 /** returns the zero-based pulse (relative to session origin)
262    where the zero-based frame (relative to session)
263    lies.
264 */
265 double
266 TempoSection::pulse_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
267 {
268         if (_type == Constant || _c_func == 0.0) {
269                 return ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
270         }
271
272         return pulse_at_time (frame_to_minute (f - frame(), frame_rate)) + pulse();
273 }
274
275 /** returns the zero-based frame (relative to session start frame)
276    where the zero-based pulse (relative to session start)
277    falls.
278 */
279
280 framepos_t
281 TempoSection::frame_at_pulse (const double& p, const framecnt_t& frame_rate) const
282 {
283         if (_type == Constant || _c_func == 0.0) {
284                 return (framepos_t) floor ((p - pulse()) * frames_per_pulse (frame_rate)) + frame();
285         }
286
287         return minute_to_frame (time_at_pulse (p - pulse()), frame_rate) + frame();
288 }
289
290 /*
291 Ramp Overview
292
293       |                     *
294 Tempo |                   *
295 Tt----|-----------------*|
296 Ta----|--------------|*  |
297       |            * |   |
298       |         *    |   |
299       |     *        |   |
300 T0----|*             |   |
301   *   |              |   |
302       _______________|___|____
303       time           a   t (next tempo)
304       [        c         ] defines c
305
306 Duration in beats at time a is the integral of some Tempo function.
307 In our case, the Tempo function (Tempo at time t) is
308 T(t) = T0(e^(ct))
309
310 with function constant
311 c = log(Ta/T0)/a
312 so
313 a = log(Ta/T0)/c
314
315 The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
316 b(t) = T0(e^(ct) - 1) / c
317
318 To find the time t at beat duration b, we use the inverse function of the beat function (the time function) which can be shown to be:
319 t(b) = log((c.b / T0) + 1) / c
320
321 The time t at which Tempo T occurs is a as above:
322 t(T) = log(T / T0) / c
323
324 The beat at which a Tempo T occurs is:
325 b(T) = (T - T0) / c
326
327 The Tempo at which beat b occurs is:
328 T(b) = b.c + T0
329
330 We define c for this tempo ramp by placing a new tempo section at some time t after this one.
331 Our problem is that we usually don't know t.
332 We almost always know the duration in beats between this and the new section, so we need to find c in terms of the beat function.
333 Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
334 t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
335
336 By substituting our expanded t as a in the c function above, our problem is reduced to:
337 c = T0 (e^(log (Ta / T0)) - 1) / b
338
339 Of course the word 'beat' has been left loosely defined above.
340 In music, a beat is defined by the musical pulse (which comes from the tempo)
341 and the meter in use at a particular time (how many  pulse divisions there are in one bar).
342 It would be more accurate to substitute the work 'pulse' for 'beat' above.
343
344 Anyway ...
345
346 We can now store c for future time calculations.
347 If the following tempo section (the one that defines c in conjunction with this one)
348 is changed or moved, c is no longer valid.
349
350 The public methods are session-relative.
351
352 Most of this stuff is taken from this paper:
353
354 WHERE’S THE BEAT?
355 TOOLS FOR DYNAMIC TEMPO CALCULATIONS
356 Jan C. Schacher
357 Martin Neukom
358 Zurich University of Arts
359 Institute for Computer Music and Sound Technology
360
361 https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Tempopolyphony_ICMC07.pdf
362
363 */
364
365 /*
366   compute this ramp's function constant using the end tempo (in whole pulses per minute)
367   and duration (pulses into global start) of some later tempo section.
368 */
369 double
370 TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse, const framecnt_t& frame_rate)
371 {
372         double const log_tempo_ratio = log (end_bpm / pulses_per_minute());
373         return pulses_per_minute() *  (expm1 (log_tempo_ratio)) / (end_pulse - pulse());
374 }
375
376 /* compute the function constant from some later tempo section, given tempo (whole pulses/min.) and distance (in frames) from session origin */
377 double
378 TempoSection::compute_c_func_frame (const double& end_bpm, const framepos_t& end_frame, const framecnt_t& frame_rate) const
379 {
380         return c_func (end_bpm, frame_to_minute (end_frame - frame(), frame_rate));
381 }
382
383 framepos_t
384 TempoSection::minute_to_frame (const double& time, const framecnt_t& frame_rate) const
385 {
386         return (framepos_t) floor ((time * 60.0 * frame_rate) + 0.5);
387 }
388
389 double
390 TempoSection::frame_to_minute (const framepos_t& frame, const framecnt_t& frame_rate) const
391 {
392         return (frame / (double) frame_rate) / 60.0;
393 }
394
395 /* position function */
396 double
397 TempoSection::a_func (double end_ppm, double c_func) const
398 {
399         return log (end_ppm / pulses_per_minute()) /  c_func;
400 }
401
402 /*function constant*/
403 double
404 TempoSection::c_func (double end_ppm, double end_time) const
405 {
406         return log (end_ppm / pulses_per_minute()) /  end_time;
407 }
408
409 /* tempo in ppm at time in minutes */
410 double
411 TempoSection::pulse_tempo_at_time (const double& time) const
412 {
413         return exp (_c_func * time) * pulses_per_minute();
414 }
415
416 /* time in minutes at tempo in ppm */
417 double
418 TempoSection::time_at_pulse_tempo (const double& pulse_tempo) const
419 {
420         return log (pulse_tempo / pulses_per_minute()) / _c_func;
421 }
422
423 /* tick at tempo in ppm */
424 double
425 TempoSection::pulse_at_pulse_tempo (const double& pulse_tempo) const
426 {
427         return (pulse_tempo - pulses_per_minute()) / _c_func;
428 }
429
430 /* tempo in ppm at tick */
431 double
432 TempoSection::pulse_tempo_at_pulse (const double& pulse) const
433 {
434         return (pulse * _c_func) + pulses_per_minute();
435 }
436
437 /* pulse at time in minutes */
438 double
439 TempoSection::pulse_at_time (const double& time) const
440 {
441         return expm1 (_c_func * time) * (pulses_per_minute() / _c_func);
442 }
443
444 /* time in minutes at pulse */
445 double
446 TempoSection::time_at_pulse (const double& pulse) const
447 {
448         return log1p ((_c_func * pulse) / pulses_per_minute()) / _c_func;
449 }
450
451 /***********************************************************************/
452
453 const string MeterSection::xml_state_node_name = "Meter";
454
455 MeterSection::MeterSection (const XMLNode& node)
456         : MetricSection (0.0, 0, MusicTime), 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_frame_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_frame_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::beat_at_frame (const framecnt_t& frame) const
1390 {
1391         Glib::Threads::RWLock::ReaderLock lm (lock);
1392         return beat_at_frame_locked (_metrics, frame);
1393 }
1394
1395 /* meter / tempo section based */
1396 double
1397 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1398 {
1399         const TempoSection& ts = tempo_section_at_frame_locked (metrics, frame);
1400         MeterSection* prev_m = 0;
1401         MeterSection* next_m = 0;
1402
1403         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1404                 MeterSection* m;
1405                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1406                         if (prev_m && m->frame() > frame) {
1407                                 next_m = m;
1408                                 break;
1409                         }
1410                         prev_m = m;
1411                 }
1412         }
1413         if (frame < prev_m->frame()) {
1414                 return 0.0;
1415         }
1416         const double beat = prev_m->beat() + (ts.pulse_at_frame (frame, _frame_rate) - prev_m->pulse()) * prev_m->note_divisor();
1417
1418         if (next_m && next_m->beat() < beat) {
1419                 return next_m->beat();
1420         }
1421
1422         return beat;
1423 }
1424
1425 framecnt_t
1426 TempoMap::frame_at_beat (const double& beat) const
1427 {
1428         Glib::Threads::RWLock::ReaderLock lm (lock);
1429         return frame_at_beat_locked (_metrics, beat);
1430 }
1431
1432 /* meter section based */
1433 framecnt_t
1434 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1435 {
1436         const TempoSection& prev_t = tempo_section_at_beat_locked (metrics, beat);
1437         MeterSection* prev_m = 0;
1438
1439         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1440                 MeterSection* m;
1441                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1442                         if (prev_m && m->beat() > beat) {
1443                                 break;
1444                         }
1445                         prev_m = m;
1446                 }
1447         }
1448
1449         return prev_t.frame_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse(), _frame_rate);
1450 }
1451
1452 Tempo
1453 TempoMap::tempo_at_frame (const framepos_t& frame) const
1454 {
1455         Glib::Threads::RWLock::ReaderLock lm (lock);
1456         return tempo_at_frame_locked (_metrics, frame);
1457 }
1458
1459 Tempo
1460 TempoMap::tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1461 {
1462         TempoSection* prev_t = 0;
1463
1464         Metrics::const_iterator i;
1465
1466         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
1467                 TempoSection* t;
1468                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1469                         if (!t->active()) {
1470                                 continue;
1471                         }
1472                         if ((prev_t) && t->frame() > frame) {
1473                                 /* t is the section past frame */
1474                                 const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
1475                                 const Tempo ret_tempo (ret_bpm, prev_t->note_type());
1476                                 return ret_tempo;
1477                         }
1478                         prev_t = t;
1479                 }
1480         }
1481
1482         const double ret = prev_t->beats_per_minute();
1483         const Tempo ret_tempo (ret, prev_t->note_type ());
1484
1485         return ret_tempo;
1486 }
1487
1488 /** returns the frame at which the supplied tempo occurs, or
1489  *  the frame of the last tempo section (search exhausted)
1490  *  only the position of the first occurence will be returned
1491  *  (extend me)
1492 */
1493 framepos_t
1494 TempoMap::frame_at_tempo (const Tempo& tempo) const
1495 {
1496         Glib::Threads::RWLock::ReaderLock lm (lock);
1497         return frame_at_tempo_locked (_metrics, tempo);
1498 }
1499
1500
1501 framepos_t
1502 TempoMap::frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const
1503 {
1504         TempoSection* prev_t = 0;
1505         const double tempo_ppm = tempo.beats_per_minute() / tempo.note_type();
1506
1507         Metrics::const_iterator i;
1508
1509         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
1510                 TempoSection* t;
1511                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1512
1513                         if (!t->active()) {
1514                                 continue;
1515                         }
1516
1517                         const double t_ppm = t->beats_per_minute() / t->note_type();
1518
1519                         if (t_ppm == tempo_ppm) {
1520                                 return t->frame();
1521                         }
1522
1523                         if (prev_t) {
1524                                 const double prev_t_ppm = prev_t->beats_per_minute() / prev_t->note_type();
1525
1526                                 if ((t_ppm > tempo_ppm && prev_t_ppm < tempo_ppm) || (t_ppm < tempo_ppm && prev_t_ppm > tempo_ppm)) {
1527                                         const framepos_t ret_frame = prev_t->frame_at_tempo (tempo_ppm, prev_t->pulse(), _frame_rate);
1528                                         return ret_frame;
1529                                 }
1530                         }
1531                         prev_t = t;
1532                 }
1533         }
1534
1535         return prev_t->frame();
1536 }
1537
1538 Tempo
1539 TempoMap::tempo_at_beat (const double& beat) const
1540 {
1541         Glib::Threads::RWLock::ReaderLock lm (lock);
1542         const MeterSection* prev_m = &meter_section_at_beat_locked (_metrics, beat);
1543         const TempoSection* prev_t = &tempo_section_at_beat_locked (_metrics, beat);
1544         const double note_type = prev_t->note_type();
1545
1546         return Tempo (prev_t->tempo_at_pulse (((beat - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse()) * note_type, note_type);
1547 }
1548
1549 double
1550 TempoMap::pulse_at_beat (const double& beat) const
1551 {
1552         Glib::Threads::RWLock::ReaderLock lm (lock);
1553         return pulse_at_beat_locked (_metrics, beat);
1554 }
1555
1556 double
1557 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1558 {
1559         MeterSection* prev_m = 0;
1560
1561         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1562                 MeterSection* m;
1563                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1564                         if (prev_m && m->beat() > beat) {
1565                                 break;
1566                         }
1567                         prev_m = m;
1568                 }
1569
1570         }
1571         double const ret = prev_m->pulse() + ((beat - prev_m->beat()) / prev_m->note_divisor());
1572         return ret;
1573 }
1574
1575 double
1576 TempoMap::beat_at_pulse (const double& pulse) const
1577 {
1578         Glib::Threads::RWLock::ReaderLock lm (lock);
1579         return beat_at_pulse_locked (_metrics, pulse);
1580 }
1581
1582 double
1583 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1584 {
1585         MeterSection* prev_m = 0;
1586
1587         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1588                 MeterSection* m;
1589                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1590                         if (prev_m && m->pulse() > pulse) {
1591                                 if (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > m->beat()) {
1592                                         break;
1593                                 }
1594                         }
1595                         prev_m = m;
1596                 }
1597         }
1598
1599         double const ret = ((pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat();
1600         return ret;
1601 }
1602
1603 double
1604 TempoMap::pulse_at_frame (const framecnt_t& frame) const
1605 {
1606         Glib::Threads::RWLock::ReaderLock lm (lock);
1607         return pulse_at_frame_locked (_metrics, frame);
1608 }
1609
1610 /* tempo section based */
1611 double
1612 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1613 {
1614         /* HOLD (at least) THE READER LOCK */
1615         TempoSection* prev_t = 0;
1616
1617         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1618                 TempoSection* t;
1619                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1620                         if (!t->active()) {
1621                                 continue;
1622                         }
1623                         if (prev_t && t->frame() > frame) {
1624                                 /*the previous ts is the one containing the frame */
1625                                 const double ret = prev_t->pulse_at_frame (frame, _frame_rate);
1626                                 return ret;
1627                         }
1628                         prev_t = t;
1629                 }
1630         }
1631
1632         /* treated as constant for this ts */
1633         const double pulses_in_section = (frame - prev_t->frame()) / prev_t->frames_per_pulse (_frame_rate);
1634
1635         return pulses_in_section + prev_t->pulse();
1636 }
1637
1638 framecnt_t
1639 TempoMap::frame_at_pulse (const double& pulse) const
1640 {
1641         Glib::Threads::RWLock::ReaderLock lm (lock);
1642         return frame_at_pulse_locked (_metrics, pulse);
1643 }
1644
1645 /* tempo section based */
1646 framecnt_t
1647 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1648 {
1649         /* HOLD THE READER LOCK */
1650
1651         const TempoSection* prev_t = 0;
1652
1653         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1654                 TempoSection* t;
1655
1656                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1657                         if (!t->active()) {
1658                                 continue;
1659                         }
1660                         if (prev_t && t->pulse() > pulse) {
1661                                 return prev_t->frame_at_pulse (pulse, _frame_rate);
1662                         }
1663
1664                         prev_t = t;
1665                 }
1666         }
1667         /* must be treated as constant, irrespective of _type */
1668         double const pulses_in_section = pulse - prev_t->pulse();
1669         double const dtime = pulses_in_section * prev_t->frames_per_pulse (_frame_rate);
1670
1671         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_t->frame();
1672
1673         return ret;
1674 }
1675
1676 double
1677 TempoMap::beat_at_bbt (const Timecode::BBT_Time& bbt)
1678 {
1679         Glib::Threads::RWLock::ReaderLock lm (lock);
1680         return beat_at_bbt_locked (_metrics, bbt);
1681 }
1682
1683
1684 double
1685 TempoMap::beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1686 {
1687         /* CALLER HOLDS READ LOCK */
1688
1689         MeterSection* prev_m = 0;
1690
1691         /* because audio-locked meters have 'fake' integral beats,
1692            there is no pulse offset here.
1693         */
1694         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1695                 MeterSection* m;
1696                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1697                         if (prev_m) {
1698                                 const double bars_to_m = (m->beat() - prev_m->beat()) / prev_m->divisions_per_bar();
1699                                 if ((bars_to_m + (prev_m->bbt().bars - 1)) > (bbt.bars - 1)) {
1700                                         break;
1701                                 }
1702                         }
1703                         prev_m = m;
1704                 }
1705         }
1706
1707         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1708         const double remaining_bars_in_beats = remaining_bars * prev_m->divisions_per_bar();
1709         const double ret = remaining_bars_in_beats + prev_m->beat() + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1710
1711         return ret;
1712 }
1713
1714 Timecode::BBT_Time
1715 TempoMap::bbt_at_beat (const double& beats)
1716 {
1717         Glib::Threads::RWLock::ReaderLock lm (lock);
1718         return bbt_at_beat_locked (_metrics, beats);
1719 }
1720
1721 Timecode::BBT_Time
1722 TempoMap::bbt_at_beat_locked (const Metrics& metrics, const double& b) const
1723 {
1724         /* CALLER HOLDS READ LOCK */
1725         MeterSection* prev_m = 0;
1726         const double beats = max (0.0, b);
1727
1728         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1729                 MeterSection* m = 0;
1730
1731                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1732                         if (prev_m) {
1733                                 if (m->beat() > beats) {
1734                                         /* this is the meter after the one our beat is on*/
1735                                         break;
1736                                 }
1737                         }
1738
1739                         prev_m = m;
1740                 }
1741         }
1742
1743         const double beats_in_ms = beats - prev_m->beat();
1744         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1745         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1746         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1747         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1748
1749         BBT_Time ret;
1750
1751         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1752         ret.beats = (uint32_t) floor (remaining_beats);
1753         ret.bars = total_bars;
1754
1755         /* 0 0 0 to 1 1 0 - based mapping*/
1756         ++ret.bars;
1757         ++ret.beats;
1758
1759         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1760                 ++ret.beats;
1761                 ret.ticks -= BBT_Time::ticks_per_beat;
1762         }
1763
1764         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1765                 ++ret.bars;
1766                 ret.beats = 1;
1767         }
1768
1769         return ret;
1770 }
1771
1772 double
1773 TempoMap::pulse_at_bbt (const Timecode::BBT_Time& bbt)
1774 {
1775         Glib::Threads::RWLock::ReaderLock lm (lock);
1776
1777         return pulse_at_bbt_locked (_metrics, bbt);
1778 }
1779
1780 double
1781 TempoMap::pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1782 {
1783         /* CALLER HOLDS READ LOCK */
1784
1785         MeterSection* prev_m = 0;
1786
1787         /* because audio-locked meters have 'fake' integral beats,
1788            there is no pulse offset here.
1789         */
1790         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1791                 MeterSection* m;
1792                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1793                         if (prev_m) {
1794                                 if (m->bbt().bars > bbt.bars) {
1795                                         break;
1796                                 }
1797                         }
1798                         prev_m = m;
1799                 }
1800         }
1801
1802         const double remaining_bars = bbt.bars - prev_m->bbt().bars;
1803         const double remaining_pulses = remaining_bars * prev_m->divisions_per_bar() / prev_m->note_divisor();
1804         const double ret = remaining_pulses + prev_m->pulse() + (((bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat)) / prev_m->note_divisor());
1805
1806         return ret;
1807 }
1808
1809 Timecode::BBT_Time
1810 TempoMap::bbt_at_pulse (const double& pulse)
1811 {
1812         Glib::Threads::RWLock::ReaderLock lm (lock);
1813
1814         return bbt_at_pulse_locked (_metrics, pulse);
1815 }
1816
1817 Timecode::BBT_Time
1818 TempoMap::bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1819 {
1820         MeterSection* prev_m = 0;
1821
1822         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1823                 MeterSection* m = 0;
1824
1825                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1826
1827                         if (prev_m) {
1828                                 double const pulses_to_m = m->pulse() - prev_m->pulse();
1829                                 if (prev_m->pulse() + pulses_to_m > pulse) {
1830                                         /* this is the meter after the one our beat is on*/
1831                                         break;
1832                                 }
1833                         }
1834
1835                         prev_m = m;
1836                 }
1837         }
1838
1839         const double beats_in_ms = (pulse - prev_m->pulse()) * prev_m->note_divisor();
1840         const uint32_t bars_in_ms = (uint32_t) floor (beats_in_ms / prev_m->divisions_per_bar());
1841         const uint32_t total_bars = bars_in_ms + (prev_m->bbt().bars - 1);
1842         const double remaining_beats = beats_in_ms - (bars_in_ms * prev_m->divisions_per_bar());
1843         const double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1844
1845         BBT_Time ret;
1846
1847         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1848         ret.beats = (uint32_t) floor (remaining_beats);
1849         ret.bars = total_bars;
1850
1851         /* 0 0 0 to 1 1 0 mapping*/
1852         ++ret.bars;
1853         ++ret.beats;
1854
1855         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1856                 ++ret.beats;
1857                 ret.ticks -= BBT_Time::ticks_per_beat;
1858         }
1859
1860         if (ret.beats >= prev_m->divisions_per_bar() + 1) {
1861                 ++ret.bars;
1862                 ret.beats = 1;
1863         }
1864
1865         return ret;
1866 }
1867
1868 BBT_Time
1869 TempoMap::bbt_at_frame (framepos_t frame)
1870 {
1871         if (frame < 0) {
1872                 BBT_Time bbt;
1873                 bbt.bars = 1;
1874                 bbt.beats = 1;
1875                 bbt.ticks = 0;
1876                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1877                 return bbt;
1878         }
1879         Glib::Threads::RWLock::ReaderLock lm (lock);
1880
1881         return bbt_at_frame_locked (_metrics, frame);
1882 }
1883
1884 Timecode::BBT_Time
1885 TempoMap::bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const
1886 {
1887         if (frame < 0) {
1888                 BBT_Time bbt;
1889                 bbt.bars = 1;
1890                 bbt.beats = 1;
1891                 bbt.ticks = 0;
1892                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1893                 return bbt;
1894         }
1895         const double beat = beat_at_frame_locked (metrics, frame);
1896
1897         return bbt_at_beat_locked (metrics, beat);
1898 }
1899
1900 framepos_t
1901 TempoMap::frame_at_bbt (const BBT_Time& bbt)
1902 {
1903         if (bbt.bars < 1) {
1904                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1905                 return 0;
1906         }
1907
1908         if (bbt.beats < 1) {
1909                 throw std::logic_error ("beats are counted from one");
1910         }
1911         Glib::Threads::RWLock::ReaderLock lm (lock);
1912
1913         return frame_at_bbt_locked (_metrics, bbt);
1914 }
1915
1916 /* meter & tempo section based */
1917 framepos_t
1918 TempoMap::frame_at_bbt_locked (const Metrics& metrics, const BBT_Time& bbt) const
1919 {
1920         /* HOLD THE READER LOCK */
1921
1922         const framepos_t ret = frame_at_beat_locked (metrics, beat_at_bbt_locked (metrics, bbt));
1923         return ret;
1924 }
1925
1926 bool
1927 TempoMap::check_solved (const Metrics& metrics) const
1928 {
1929         TempoSection* prev_t = 0;
1930         MeterSection* prev_m = 0;
1931
1932         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1933                 TempoSection* t;
1934                 MeterSection* m;
1935                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1936                         if (!t->active()) {
1937                                 continue;
1938                         }
1939                         if (prev_t) {
1940                                 /* check ordering */
1941                                 if ((t->frame() <= prev_t->frame()) || (t->pulse() <= prev_t->pulse())) {
1942                                         return false;
1943                                 }
1944
1945                                 /* precision check ensures tempo and frames align.*/
1946                                 if (t->frame() != prev_t->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
1947                                         if (!t->locked_to_meter()) {
1948                                                 return false;
1949                                         }
1950                                 }
1951
1952                                 /* gradient limit - who knows what it should be?
1953                                    things are also ok (if a little chaotic) without this
1954                                 */
1955                                 if (fabs (prev_t->c_func()) > 1000.0) {
1956                                         //std::cout << "c : " << prev_t->c_func() << std::endl;
1957                                         return false;
1958                                 }
1959                         }
1960                         prev_t = t;
1961                 }
1962
1963                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1964                         if (prev_m && m->position_lock_style() == AudioTime) {
1965                                 TempoSection* t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (metrics, m->frame() - 1));
1966                                 const double nascent_m_pulse = ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
1967                                 const framepos_t nascent_m_frame = t->frame_at_pulse (nascent_m_pulse, _frame_rate);
1968
1969                                 if (t && (nascent_m_frame > m->frame() || nascent_m_frame < 0)) {
1970                                         return false;
1971                                 }
1972                         }
1973
1974                         prev_m = m;
1975                 }
1976
1977         }
1978
1979         return true;
1980 }
1981
1982 bool
1983 TempoMap::set_active_tempos (const Metrics& metrics, const framepos_t& frame)
1984 {
1985         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1986                 TempoSection* t;
1987                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1988                         if (!t->movable()) {
1989                                 t->set_active (true);
1990                                 continue;
1991                         }
1992                         if (t->movable() && t->active () && t->position_lock_style() == AudioTime && t->frame() < frame) {
1993                                 t->set_active (false);
1994                                 t->set_pulse (0.0);
1995                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() > frame) {
1996                                 t->set_active (true);
1997                         } else if (t->movable() && t->position_lock_style() == AudioTime && t->frame() == frame) {
1998                                 return false;
1999                         }
2000                 }
2001         }
2002         return true;
2003 }
2004
2005 bool
2006 TempoMap::solve_map_frame (Metrics& imaginary, TempoSection* section, const framepos_t& frame)
2007 {
2008         TempoSection* prev_t = 0;
2009         TempoSection* section_prev = 0;
2010         framepos_t first_m_frame = 0;
2011
2012         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2013                 MeterSection* m;
2014                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2015                         if (!m->movable()) {
2016                                 first_m_frame = m->frame();
2017                                 break;
2018                         }
2019                 }
2020         }
2021         if (section->movable() && frame <= first_m_frame) {
2022                 return false;
2023         }
2024
2025         section->set_active (true);
2026         section->set_frame (frame);
2027
2028         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2029                 TempoSection* t;
2030                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2031
2032                         if (!t->active()) {
2033                                 continue;
2034                         }
2035                         if (prev_t) {
2036                                 if (t == section) {
2037                                         section_prev = prev_t;
2038                                         continue;
2039                                 }
2040                                 if (t->position_lock_style() == MusicTime) {
2041                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2042                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2043                                 } else {
2044                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2045                                         if (!t->locked_to_meter()) {
2046                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2047                                         }
2048                                 }
2049                         }
2050                         prev_t = t;
2051                 }
2052         }
2053
2054         if (section_prev) {
2055                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
2056                 if (!section->locked_to_meter()) {
2057                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2058                 }
2059         }
2060
2061         recompute_tempos (imaginary);
2062
2063         if (check_solved (imaginary)) {
2064                 return true;
2065         }
2066
2067         MetricSectionFrameSorter fcmp;
2068         imaginary.sort (fcmp);
2069
2070         recompute_tempos (imaginary);
2071
2072         if (check_solved (imaginary)) {
2073                 return true;
2074         }
2075
2076         return false;
2077 }
2078
2079 bool
2080 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2081 {
2082         TempoSection* prev_t = 0;
2083         TempoSection* section_prev = 0;
2084
2085         section->set_pulse (pulse);
2086
2087         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2088                 TempoSection* t;
2089                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2090                         if (!t->active()) {
2091                                 continue;
2092                         }
2093                         if (!t->movable()) {
2094                                 t->set_pulse (0.0);
2095                                 prev_t = t;
2096                                 continue;
2097                         }
2098                         if (prev_t) {
2099                                 if (t == section) {
2100                                         section_prev = prev_t;
2101                                         continue;
2102                                 }
2103                                 if (t->position_lock_style() == MusicTime) {
2104                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2105                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2106                                 } else {
2107                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2108                                         if (!t->locked_to_meter()) {
2109                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2110                                         }
2111                                 }
2112                         }
2113                         prev_t = t;
2114                 }
2115         }
2116
2117         if (section_prev) {
2118                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
2119                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2120         }
2121
2122         recompute_tempos (imaginary);
2123
2124         if (check_solved (imaginary)) {
2125                 return true;
2126         }
2127
2128         MetricSectionSorter cmp;
2129         imaginary.sort (cmp);
2130
2131         recompute_tempos (imaginary);
2132         /* Reordering
2133          * XX need a restriction here, but only for this case,
2134          * as audio locked tempos don't interact in the same way.
2135          *
2136          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2137          * e.g.
2138          * |50 bpm                        |250 bpm |60 bpm
2139          *                drag 250 to the pulse after 60->
2140          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2141          */
2142         if (check_solved (imaginary)) {
2143                 return true;
2144         }
2145
2146         return false;
2147 }
2148
2149 bool
2150 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2151 {
2152         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2153         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2154         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2155                 return false;
2156         }
2157
2158         if (!section->movable()) {
2159                 /* lock the first tempo to our first meter */
2160                 if (!set_active_tempos (imaginary, frame)) {
2161                         return false;
2162                 }
2163         }
2164
2165         /* it would make sense to bail out if there is no audio-locked meter,
2166            however it may be desirable to move a music-locked meter by frame at some point.
2167         */
2168         TempoSection* meter_locked_tempo = 0;
2169         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2170                 TempoSection* t;
2171                 if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2172                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2173                                 meter_locked_tempo = t;
2174                                 break;
2175                         }
2176                 }
2177         }
2178
2179         if (!meter_locked_tempo) {
2180                 return false;
2181         }
2182
2183         MeterSection* prev_m = 0;
2184         Metrics future_map;
2185         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2186         bool solved = false;
2187
2188         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2189                 MeterSection* m;
2190                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2191                         if (m == section){
2192                                 if (prev_m && section->movable()) {
2193                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2194                                         if (beats + prev_m->beat() < section->beat()) {
2195                                                 /* set the frame/pulse corresponding to its musical position,
2196                                                  * as an earlier time than this has been requested.
2197                                                 */
2198                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2199                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2200
2201                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2202
2203                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2204                                                         meter_locked_tempo->set_pulse (new_pulse);
2205                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2206                                                         section->set_frame (smallest_frame);
2207                                                         section->set_pulse (new_pulse);
2208                                                 } else {
2209                                                         solved = false;
2210                                                 }
2211
2212                                                 Metrics::const_iterator d = future_map.begin();
2213                                                 while (d != future_map.end()) {
2214                                                         delete (*d);
2215                                                         ++d;
2216                                                 }
2217
2218                                                 if (!solved) {
2219                                                         return false;
2220                                                 }
2221                                         } else {
2222                                                 /* all is ok. set section's tempo */
2223                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2224                                                 meter_copy->set_frame (frame);
2225
2226                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2227                                                         section->set_frame (frame);
2228                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2229                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2230                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2231                                                 } else {
2232                                                         solved = false;
2233                                                 }
2234
2235                                                 Metrics::const_iterator d = future_map.begin();
2236                                                 while (d != future_map.end()) {
2237                                                         delete (*d);
2238                                                         ++d;
2239                                                 }
2240
2241                                                 if (!solved) {
2242                                                         return false;
2243                                                 }
2244                                         }
2245                                 } else {
2246                                         /* not movable (first meter atm) */
2247
2248                                         tempo_copy->set_frame (frame);
2249                                         tempo_copy->set_pulse (0.0);
2250
2251                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2252                                                 section->set_frame (frame);
2253                                                 meter_locked_tempo->set_frame (frame);
2254                                                 meter_locked_tempo->set_pulse (0.0);
2255                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2256                                         } else {
2257                                                 solved = false;
2258                                         }
2259
2260                                         Metrics::const_iterator d = future_map.begin();
2261                                         while (d != future_map.end()) {
2262                                                 delete (*d);
2263                                                 ++d;
2264                                         }
2265
2266                                         if (!solved) {
2267                                                 return false;
2268                                         }
2269
2270                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2271                                         section->set_beat (b_bbt);
2272                                         section->set_pulse (0.0);
2273
2274                                 }
2275                                 break;
2276                         }
2277
2278                         prev_m = m;
2279                 }
2280         }
2281
2282         MetricSectionFrameSorter fcmp;
2283         imaginary.sort (fcmp);
2284
2285         recompute_meters (imaginary);
2286
2287         return true;
2288 }
2289
2290 bool
2291 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2292 {
2293         /* disallow setting section to an existing meter's bbt */
2294         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2295                 MeterSection* m;
2296                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2297                         if (m != section && m->bbt().bars == when.bars) {
2298                                 return false;
2299                         }
2300                 }
2301         }
2302
2303         MeterSection* prev_m = 0;
2304         MeterSection* section_prev = 0;
2305
2306         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2307                 MeterSection* m;
2308                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2309                         pair<double, BBT_Time> b_bbt;
2310                         double new_pulse = 0.0;
2311
2312                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2313                                 section_prev = prev_m;
2314                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2315                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2316                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2317
2318                                 section->set_beat (b_bbt);
2319                                 section->set_pulse (pulse);
2320                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2321                                 prev_m = section;
2322                                 continue;
2323                         }
2324
2325                         if (m->position_lock_style() == AudioTime) {
2326                                 TempoSection* meter_locked_tempo = 0;
2327
2328                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2329                                         TempoSection* t;
2330                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2331                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2332                                                         meter_locked_tempo = t;
2333                                                         break;
2334                                                 }
2335                                         }
2336                                 }
2337
2338                                 if (!meter_locked_tempo) {
2339                                         return false;
2340                                 }
2341
2342                                 if (prev_m) {
2343                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2344
2345                                         if (beats + prev_m->beat() != m->beat()) {
2346                                                 /* tempo/ meter change caused a change in beat (bar). */
2347                                                 b_bbt = make_pair (beats + prev_m->beat()
2348                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2349                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2350                                         } else if (m->movable()) {
2351                                                 b_bbt = make_pair (m->beat(), m->bbt());
2352                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2353                                         }
2354                                 } else {
2355                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2356                                 }
2357
2358                                 meter_locked_tempo->set_pulse (new_pulse);
2359                                 m->set_beat (b_bbt);
2360                                 m->set_pulse (new_pulse);
2361
2362                         } else {
2363                                 /* MusicTime */
2364                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2365                                 if (beats + prev_m->beat() != m->beat()) {
2366                                         /* tempo/ meter change caused a change in beat (bar). */
2367                                         b_bbt = make_pair (beats + prev_m->beat()
2368                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2369                                 } else {
2370                                         b_bbt = make_pair (beats + prev_m->beat()
2371                                                            , m->bbt());
2372                                 }
2373                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2374                                 m->set_beat (b_bbt);
2375                                 m->set_pulse (new_pulse);
2376                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2377                         }
2378
2379                         prev_m = m;
2380                 }
2381         }
2382
2383         if (!section_prev) {
2384
2385                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2386                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2387                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2388
2389                 section->set_beat (b_bbt);
2390                 section->set_pulse (pulse);
2391                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2392         }
2393
2394         MetricSectionSorter cmp;
2395         imaginary.sort (cmp);
2396
2397         recompute_meters (imaginary);
2398
2399         return true;
2400 }
2401
2402 /** places a copy of _metrics into copy and returns a pointer
2403  *  to section's equivalent in copy.
2404  */
2405 TempoSection*
2406 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2407 {
2408         TempoSection* ret = 0;
2409
2410         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2411                 TempoSection* t;
2412                 MeterSection* m;
2413                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2414                         if (t == section) {
2415                                 ret = new TempoSection (*t);
2416                                 copy.push_back (ret);
2417                                 continue;
2418                         }
2419
2420                         TempoSection* cp = new TempoSection (*t);
2421                         copy.push_back (cp);
2422                 }
2423                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2424                         MeterSection* cp = new MeterSection (*m);
2425                         copy.push_back (cp);
2426                 }
2427         }
2428
2429         return ret;
2430 }
2431
2432 MeterSection*
2433 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2434 {
2435         MeterSection* ret = 0;
2436
2437         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2438                 TempoSection* t;
2439                 MeterSection* m;
2440                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2441                         TempoSection* cp = new TempoSection (*t);
2442                         copy.push_back (cp);
2443                 }
2444
2445                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2446                         if (m == section) {
2447                                 ret = new MeterSection (*m);
2448                                 copy.push_back (ret);
2449                                 continue;
2450                         }
2451                         MeterSection* cp = new MeterSection (*m);
2452                         copy.push_back (cp);
2453                 }
2454         }
2455
2456         return ret;
2457 }
2458
2459 /** answers the question "is this a valid beat position for this tempo section?".
2460  *  it returns true if the tempo section can be moved to the requested bbt position,
2461  *  leaving the tempo map in a solved state.
2462  * @param section the tempo section to be moved
2463  * @param bbt the requested new position for the tempo section
2464  * @return true if the tempo section can be moved to the position, otherwise false.
2465  */
2466 bool
2467 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2468 {
2469         Metrics copy;
2470         TempoSection* tempo_copy = 0;
2471
2472         {
2473                 Glib::Threads::RWLock::ReaderLock lm (lock);
2474                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2475                 if (!tempo_copy) {
2476                         return false;
2477                 }
2478         }
2479
2480         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2481
2482         Metrics::const_iterator d = copy.begin();
2483         while (d != copy.end()) {
2484                 delete (*d);
2485                 ++d;
2486         }
2487
2488         return ret;
2489 }
2490
2491 /**
2492 * 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,
2493 * taking any possible reordering as a consequence of this into account.
2494 * @param section - the section to be altered
2495 * @param bbt - the bbt where the altered tempo will fall
2496 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2497 */
2498 pair<double, framepos_t>
2499 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2500 {
2501         Metrics future_map;
2502         pair<double, framepos_t> ret = make_pair (0.0, 0);
2503
2504         Glib::Threads::RWLock::ReaderLock lm (lock);
2505
2506         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2507
2508         const double beat = beat_at_bbt_locked (future_map, bbt);
2509
2510         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2511                 ret.first = tempo_copy->pulse();
2512                 ret.second = tempo_copy->frame();
2513         } else {
2514                 ret.first = section->pulse();
2515                 ret.second = section->frame();
2516         }
2517
2518         Metrics::const_iterator d = future_map.begin();
2519         while (d != future_map.end()) {
2520                 delete (*d);
2521                 ++d;
2522         }
2523         return ret;
2524 }
2525
2526 void
2527 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame)
2528 {
2529         Metrics future_map;
2530
2531         if (ts->position_lock_style() == MusicTime) {
2532                 {
2533                         Glib::Threads::RWLock::WriterLock lm (lock);
2534                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2535                         const double pulse = pulse_at_frame_locked (future_map, frame);
2536                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2537                                 solve_map_pulse (_metrics, ts, pulse);
2538                                 recompute_meters (_metrics);
2539                         }
2540                 }
2541
2542         } else {
2543
2544                 {
2545                         Glib::Threads::RWLock::WriterLock lm (lock);
2546                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2547                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2548                                 solve_map_frame (_metrics, ts, frame);
2549                                 recompute_meters (_metrics);
2550                         }
2551                 }
2552         }
2553
2554         Metrics::const_iterator d = future_map.begin();
2555         while (d != future_map.end()) {
2556                 delete (*d);
2557                 ++d;
2558         }
2559
2560         MetricPositionChanged (); // Emit Signal
2561 }
2562
2563 void
2564 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2565 {
2566         Metrics future_map;
2567
2568         if (ms->position_lock_style() == AudioTime) {
2569
2570                 {
2571                         Glib::Threads::RWLock::WriterLock lm (lock);
2572                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2573
2574                         if (solve_map_frame (future_map, copy, frame)) {
2575                                 solve_map_frame (_metrics, ms, frame);
2576                                 recompute_tempos (_metrics);
2577                         }
2578                 }
2579         } else {
2580                 {
2581                         Glib::Threads::RWLock::WriterLock lm (lock);
2582                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2583
2584                         const double beat = beat_at_frame_locked (_metrics, frame);
2585                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2586
2587                         if (solve_map_bbt (future_map, copy, bbt)) {
2588                                 solve_map_bbt (_metrics, ms, bbt);
2589                                 recompute_tempos (_metrics);
2590                         }
2591                 }
2592         }
2593
2594         Metrics::const_iterator d = future_map.begin();
2595         while (d != future_map.end()) {
2596                 delete (*d);
2597                 ++d;
2598         }
2599
2600         MetricPositionChanged (); // Emit Signal
2601 }
2602
2603 bool
2604 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2605 {
2606         Metrics future_map;
2607         bool can_solve = false;
2608         {
2609                 Glib::Threads::RWLock::WriterLock lm (lock);
2610                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2611                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2612                 recompute_tempos (future_map);
2613
2614                 if (check_solved (future_map)) {
2615                         ts->set_beats_per_minute (bpm.beats_per_minute());
2616                         recompute_map (_metrics);
2617                         can_solve = true;
2618                 }
2619         }
2620
2621         Metrics::const_iterator d = future_map.begin();
2622         while (d != future_map.end()) {
2623                 delete (*d);
2624                 ++d;
2625         }
2626         if (can_solve) {
2627                 MetricPositionChanged (); // Emit Signal
2628         }
2629         return can_solve;
2630 }
2631
2632 void
2633 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2634 {
2635         /*
2636           Ts (future prev_t)   Tnext
2637           |                    |
2638           |     [drag^]        |
2639           |----------|----------
2640                 e_f  pulse(frame)
2641         */
2642
2643         Metrics future_map;
2644
2645         {
2646                 Glib::Threads::RWLock::WriterLock lm (lock);
2647
2648                 if (!ts) {
2649                         return;
2650                 }
2651
2652                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2653                 TempoSection* prev_to_prev_t = 0;
2654                 const frameoffset_t fr_off = end_frame - frame;
2655
2656                 if (prev_t && prev_t->pulse() > 0.0) {
2657                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2658                 }
2659
2660                 TempoSection* next_t = 0;
2661                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2662                         TempoSection* t = 0;
2663                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2664                                 if (t->frame() > ts->frame()) {
2665                                         next_t = t;
2666                                         break;
2667                                 }
2668                         }
2669                 }
2670
2671                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2672                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2673                 */
2674                 double contribution = 0.0;
2675                 double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2676
2677                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2678                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2679                 }
2680
2681                 frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2682                 double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2683                 double new_bpm;
2684
2685                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2686
2687                         if (prev_t->position_lock_style() == MusicTime) {
2688                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2689
2690                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2691                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2692
2693                                 } else {
2694                                         /* prev to prev is irrelevant */
2695
2696                                         if (start_pulse != prev_t->pulse()) {
2697                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2698                                         } else {
2699                                                 new_bpm = prev_t->beats_per_minute();
2700                                         }
2701                                 }
2702                         } else {
2703                                 /* AudioTime */
2704                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2705                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
2706                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
2707                                 } else {
2708                                         /* prev_to_prev_t is irrelevant */
2709
2710                                         if (end_frame != prev_t->frame()) {
2711                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2712                                         } else {
2713                                                 new_bpm = prev_t->beats_per_minute();
2714                                         }
2715                                 }
2716                         }
2717                 } else {
2718
2719                         double frame_ratio;
2720                         double pulse_ratio;
2721                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2722
2723                         if (prev_to_prev_t) {
2724
2725                                 frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2726                                 pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2727                         } else {
2728
2729                                 frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2730                                 pulse_ratio = (start_pulse / end_pulse);
2731                         }
2732                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2733                 }
2734
2735                 prev_t->set_beats_per_minute (new_bpm);
2736                 recompute_tempos (future_map);
2737                 recompute_meters (future_map);
2738
2739                 if (check_solved (future_map)) {
2740                         ts->set_beats_per_minute (new_bpm);
2741                         recompute_tempos (_metrics);
2742                         recompute_meters (_metrics);
2743                 }
2744         }
2745
2746         Metrics::const_iterator d = future_map.begin();
2747         while (d != future_map.end()) {
2748                 delete (*d);
2749                 ++d;
2750         }
2751
2752         MetricPositionChanged (); // Emit Signal
2753 }
2754
2755 framecnt_t
2756 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2757 {
2758         Glib::Threads::RWLock::ReaderLock lm (lock);
2759
2760         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2761         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2762         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2763
2764         return frame_at_beat_locked (_metrics, total_beats);
2765 }
2766
2767 framepos_t
2768 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2769 {
2770         return round_to_type (fr, dir, Bar);
2771 }
2772
2773 framepos_t
2774 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2775 {
2776         return round_to_type (fr, dir, Beat);
2777 }
2778
2779 framepos_t
2780 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2781 {
2782         Glib::Threads::RWLock::ReaderLock lm (lock);
2783         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2784         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2785         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2786
2787         ticks -= beats * BBT_Time::ticks_per_beat;
2788
2789         if (dir > 0) {
2790                 /* round to next (or same iff dir == RoundUpMaybe) */
2791
2792                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2793
2794                 if (mod == 0 && dir == RoundUpMaybe) {
2795                         /* right on the subdivision, which is fine, so do nothing */
2796
2797                 } else if (mod == 0) {
2798                         /* right on the subdivision, so the difference is just the subdivision ticks */
2799                         ticks += ticks_one_subdivisions_worth;
2800
2801                 } else {
2802                         /* not on subdivision, compute distance to next subdivision */
2803
2804                         ticks += ticks_one_subdivisions_worth - mod;
2805                 }
2806
2807                 if (ticks >= BBT_Time::ticks_per_beat) {
2808                         ticks -= BBT_Time::ticks_per_beat;
2809                 }
2810         } else if (dir < 0) {
2811
2812                 /* round to previous (or same iff dir == RoundDownMaybe) */
2813
2814                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2815
2816                 if (difference == 0 && dir == RoundDownAlways) {
2817                         /* right on the subdivision, but force-rounding down,
2818                            so the difference is just the subdivision ticks */
2819                         difference = ticks_one_subdivisions_worth;
2820                 }
2821
2822                 if (ticks < difference) {
2823                         ticks = BBT_Time::ticks_per_beat - ticks;
2824                 } else {
2825                         ticks -= difference;
2826                 }
2827
2828         } else {
2829                 /* round to nearest */
2830                 double rem;
2831
2832                 /* compute the distance to the previous and next subdivision */
2833
2834                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2835
2836                         /* closer to the next subdivision, so shift forward */
2837
2838                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2839
2840                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2841
2842                         if (ticks > BBT_Time::ticks_per_beat) {
2843                                 ++beats;
2844                                 ticks -= BBT_Time::ticks_per_beat;
2845                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2846                         }
2847
2848                 } else if (rem > 0) {
2849
2850                         /* closer to previous subdivision, so shift backward */
2851
2852                         if (rem > ticks) {
2853                                 if (beats == 0) {
2854                                         /* can't go backwards past zero, so ... */
2855                                         return 0;
2856                                 }
2857                                 /* step back to previous beat */
2858                                 --beats;
2859                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2860                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2861                         } else {
2862                                 ticks = lrint (ticks - rem);
2863                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2864                         }
2865                 } else {
2866                         /* on the subdivision, do nothing */
2867                 }
2868         }
2869
2870         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2871
2872         return ret_frame;
2873 }
2874
2875 framepos_t
2876 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2877 {
2878         Glib::Threads::RWLock::ReaderLock lm (lock);
2879
2880         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2881         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
2882
2883         switch (type) {
2884         case Bar:
2885                 if (dir < 0) {
2886                         /* find bar previous to 'frame' */
2887                         bbt.beats = 1;
2888                         bbt.ticks = 0;
2889                         return frame_at_bbt_locked (_metrics, bbt);
2890
2891                 } else if (dir > 0) {
2892                         /* find bar following 'frame' */
2893                         ++bbt.bars;
2894                         bbt.beats = 1;
2895                         bbt.ticks = 0;
2896                         return frame_at_bbt_locked (_metrics, bbt);
2897                 } else {
2898                         /* true rounding: find nearest bar */
2899                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
2900                         bbt.beats = 1;
2901                         bbt.ticks = 0;
2902                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
2903                         ++bbt.bars;
2904                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
2905
2906                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2907                                 return next_ft;
2908                         } else {
2909                                 return prev_ft;
2910                         }
2911                 }
2912
2913                 break;
2914
2915         case Beat:
2916                 if (dir < 0) {
2917                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2918                 } else if (dir > 0) {
2919                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2920                 } else {
2921                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2922                 }
2923                 break;
2924         }
2925
2926         return 0;
2927 }
2928
2929 void
2930 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2931                     framepos_t lower, framepos_t upper)
2932 {
2933         Glib::Threads::RWLock::ReaderLock lm (lock);
2934         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
2935         framecnt_t pos = 0;
2936         /* although the map handles negative beats, bbt doesn't. */
2937         if (cnt < 0.0) {
2938                 cnt = 0.0;
2939         }
2940         while (pos < upper) {
2941                 pos = frame_at_beat_locked (_metrics, cnt);
2942                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
2943                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
2944                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
2945                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
2946                 ++cnt;
2947         }
2948 }
2949
2950 const TempoSection&
2951 TempoMap::tempo_section_at_frame (framepos_t frame) const
2952 {
2953         Glib::Threads::RWLock::ReaderLock lm (lock);
2954         return tempo_section_at_frame_locked (_metrics, frame);
2955 }
2956
2957 const TempoSection&
2958 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
2959 {
2960         Metrics::const_iterator i;
2961         TempoSection* prev = 0;
2962
2963         for (i = metrics.begin(); i != metrics.end(); ++i) {
2964                 TempoSection* t;
2965
2966                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2967                         if (!t->active()) {
2968                                 continue;
2969                         }
2970                         if (prev && t->frame() > frame) {
2971                                 break;
2972                         }
2973
2974                         prev = t;
2975                 }
2976         }
2977
2978         if (prev == 0) {
2979                 fatal << endmsg;
2980                 abort(); /*NOTREACHED*/
2981         }
2982
2983         return *prev;
2984 }
2985
2986 const TempoSection&
2987 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
2988 {
2989         TempoSection* prev_t = 0;
2990         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
2991
2992         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2993                 TempoSection* t;
2994                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2995                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
2996                                 break;
2997                         }
2998                         prev_t = t;
2999                 }
3000
3001         }
3002         return *prev_t;
3003 }
3004
3005 /* don't use this to calculate length (the tempo is only correct for this frame).
3006    do that stuff based on the beat_at_frame and frame_at_beat api
3007 */
3008 double
3009 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3010 {
3011         Glib::Threads::RWLock::ReaderLock lm (lock);
3012
3013         const TempoSection* ts_at = &tempo_section_at_frame_locked (_metrics, frame);
3014         const TempoSection* ts_after = 0;
3015         Metrics::const_iterator i;
3016
3017         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3018                 TempoSection* t;
3019
3020                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3021                         if (!t->active()) {
3022                                 continue;
3023                         }
3024                         if ((*i)->frame() > frame) {
3025                                 ts_after = t;
3026                                 break;
3027                         }
3028                 }
3029         }
3030
3031         if (ts_after) {
3032                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
3033         }
3034         /* must be treated as constant tempo */
3035         return ts_at->frames_per_beat (_frame_rate);
3036 }
3037
3038 const MeterSection&
3039 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3040 {
3041         Metrics::const_iterator i;
3042         MeterSection* prev = 0;
3043
3044         for (i = metrics.begin(); i != metrics.end(); ++i) {
3045                 MeterSection* m;
3046
3047                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3048
3049                         if (prev && (*i)->frame() > frame) {
3050                                 break;
3051                         }
3052
3053                         prev = m;
3054                 }
3055         }
3056
3057         if (prev == 0) {
3058                 fatal << endmsg;
3059                 abort(); /*NOTREACHED*/
3060         }
3061
3062         return *prev;
3063 }
3064
3065
3066 const MeterSection&
3067 TempoMap::meter_section_at_frame (framepos_t frame) const
3068 {
3069         Glib::Threads::RWLock::ReaderLock lm (lock);
3070         return meter_section_at_frame_locked (_metrics, frame);
3071 }
3072
3073 const MeterSection&
3074 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3075 {
3076         MeterSection* prev_m = 0;
3077
3078         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3079                 MeterSection* m;
3080                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3081                         if (prev_m && m->beat() > beat) {
3082                                 break;
3083                         }
3084                         prev_m = m;
3085                 }
3086
3087         }
3088         return *prev_m;
3089 }
3090
3091 const MeterSection&
3092 TempoMap::meter_section_at_beat (double beat) const
3093 {
3094         Glib::Threads::RWLock::ReaderLock lm (lock);
3095         return meter_section_at_beat_locked (_metrics, beat);
3096 }
3097
3098 const Meter&
3099 TempoMap::meter_at_frame (framepos_t frame) const
3100 {
3101         TempoMetric m (metric_at (frame));
3102         return m.meter();
3103 }
3104
3105 void
3106 TempoMap::fix_legacy_session ()
3107 {
3108         MeterSection* prev_m = 0;
3109         TempoSection* prev_t = 0;
3110
3111         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3112                 MeterSection* m;
3113                 TempoSection* t;
3114
3115                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3116                         if (!m->movable()) {
3117                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3118                                 m->set_beat (bbt);
3119                                 m->set_pulse (0.0);
3120                                 m->set_frame (0);
3121                                 m->set_position_lock_style (AudioTime);
3122                                 prev_m = m;
3123                                 continue;
3124                         }
3125                         if (prev_m) {
3126                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3127                                                                           + (m->bbt().beats - 1)
3128                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3129                                                                           , m->bbt());
3130                                 m->set_beat (start);
3131                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3132                                         + (m->bbt().beats - 1)
3133                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3134                                 m->set_pulse (start_beat / prev_m->note_divisor());
3135                         }
3136                         prev_m = m;
3137                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3138
3139                         if (!t->active()) {
3140                                 continue;
3141                         }
3142
3143                         if (!t->movable()) {
3144                                 t->set_pulse (0.0);
3145                                 t->set_frame (0);
3146                                 t->set_position_lock_style (AudioTime);
3147                                 prev_t = t;
3148                                 continue;
3149                         }
3150
3151                         if (prev_t) {
3152                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3153                                         + (t->legacy_bbt().beats - 1)
3154                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3155                                 if (prev_m) {
3156                                         t->set_pulse (beat / prev_m->note_divisor());
3157                                 } else {
3158                                         /* really shouldn't happen but.. */
3159                                         t->set_pulse (beat / 4.0);
3160                                 }
3161                         }
3162                         prev_t = t;
3163                 }
3164         }
3165 }
3166
3167 XMLNode&
3168 TempoMap::get_state ()
3169 {
3170         Metrics::const_iterator i;
3171         XMLNode *root = new XMLNode ("TempoMap");
3172
3173         {
3174                 Glib::Threads::RWLock::ReaderLock lm (lock);
3175                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3176                         root->add_child_nocopy ((*i)->get_state());
3177                 }
3178         }
3179
3180         return *root;
3181 }
3182
3183 int
3184 TempoMap::set_state (const XMLNode& node, int /*version*/)
3185 {
3186         {
3187                 Glib::Threads::RWLock::WriterLock lm (lock);
3188
3189                 XMLNodeList nlist;
3190                 XMLNodeConstIterator niter;
3191                 Metrics old_metrics (_metrics);
3192                 _metrics.clear();
3193
3194                 nlist = node.children();
3195
3196                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3197                         XMLNode* child = *niter;
3198
3199                         if (child->name() == TempoSection::xml_state_node_name) {
3200
3201                                 try {
3202                                         TempoSection* ts = new TempoSection (*child);
3203                                         _metrics.push_back (ts);
3204                                 }
3205
3206                                 catch (failed_constructor& err){
3207                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3208                                         _metrics = old_metrics;
3209                                         break;
3210                                 }
3211
3212                         } else if (child->name() == MeterSection::xml_state_node_name) {
3213
3214                                 try {
3215                                         MeterSection* ms = new MeterSection (*child);
3216                                         _metrics.push_back (ms);
3217                                 }
3218
3219                                 catch (failed_constructor& err) {
3220                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3221                                         _metrics = old_metrics;
3222                                         break;
3223                                 }
3224                         }
3225                 }
3226
3227                 if (niter == nlist.end()) {
3228                         MetricSectionSorter cmp;
3229                         _metrics.sort (cmp);
3230                 }
3231
3232                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3233                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3234                         TempoSection* t;
3235                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3236                                 if (t->legacy_bbt().bars != 0) {
3237                                         fix_legacy_session();
3238                                         break;
3239                                 }
3240                                 break;
3241                         }
3242                 }
3243
3244                 /* check for multiple tempo/meters at the same location, which
3245                    ardour2 somehow allowed.
3246                 */
3247
3248                 Metrics::iterator prev = _metrics.end();
3249                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3250                         if (prev != _metrics.end()) {
3251                                 MeterSection* ms;
3252                                 MeterSection* prev_m;
3253                                 TempoSection* ts;
3254                                 TempoSection* prev_t;
3255                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3256                                         if (prev_m->pulse() == ms->pulse()) {
3257                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3258                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3259                                                 return -1;
3260                                         }
3261                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3262                                         if (prev_t->pulse() == ts->pulse()) {
3263                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3264                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3265                                                 return -1;
3266                                         }
3267                                 }
3268                         }
3269                         prev = i;
3270                 }
3271
3272                 recompute_map (_metrics);
3273         }
3274
3275         PropertyChanged (PropertyChange ());
3276
3277         return 0;
3278 }
3279
3280 void
3281 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3282 {
3283         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3284         const MeterSection* m;
3285         const TempoSection* t;
3286         const TempoSection* prev_t = 0;
3287
3288         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3289
3290                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3291                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3292                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3293                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3294                         if (prev_t) {
3295                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3296                                 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;
3297                         }
3298                         prev_t = t;
3299                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3300                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3301                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3302                 }
3303         }
3304         o << "------" << std::endl;
3305 }
3306
3307 int
3308 TempoMap::n_tempos() const
3309 {
3310         Glib::Threads::RWLock::ReaderLock lm (lock);
3311         int cnt = 0;
3312
3313         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3314                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3315                         cnt++;
3316                 }
3317         }
3318
3319         return cnt;
3320 }
3321
3322 int
3323 TempoMap::n_meters() const
3324 {
3325         Glib::Threads::RWLock::ReaderLock lm (lock);
3326         int cnt = 0;
3327
3328         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3329                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3330                         cnt++;
3331                 }
3332         }
3333
3334         return cnt;
3335 }
3336
3337 void
3338 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3339 {
3340         {
3341                 Glib::Threads::RWLock::WriterLock lm (lock);
3342                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3343                         if ((*i)->frame() >= where && (*i)->movable ()) {
3344                                 (*i)->set_frame ((*i)->frame() + amount);
3345                         }
3346                 }
3347
3348                 /* now reset the BBT time of all metrics, based on their new
3349                  * audio time. This is the only place where we do this reverse
3350                  * timestamp.
3351                  */
3352
3353                 Metrics::iterator i;
3354                 const MeterSection* meter;
3355                 const TempoSection* tempo;
3356                 MeterSection *m;
3357                 TempoSection *t;
3358
3359                 meter = &first_meter ();
3360                 tempo = &first_tempo ();
3361
3362                 BBT_Time start;
3363                 BBT_Time end;
3364
3365                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3366
3367                 bool first = true;
3368                 MetricSection* prev = 0;
3369
3370                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3371
3372                         BBT_Time bbt;
3373                         //TempoMetric metric (*meter, *tempo);
3374                         MeterSection* ms = const_cast<MeterSection*>(meter);
3375                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3376                         if (prev) {
3377                                 if (ts){
3378                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3379                                                 if (!t->active()) {
3380                                                         continue;
3381                                                 }
3382                                                 ts->set_pulse (t->pulse());
3383                                         }
3384                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3385                                                 ts->set_pulse (m->pulse());
3386                                         }
3387                                         ts->set_frame (prev->frame());
3388
3389                                 }
3390                                 if (ms) {
3391                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3392                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3393                                                 ms->set_beat (start);
3394                                                 ms->set_pulse (m->pulse());
3395                                         }
3396                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3397                                                 if (!t->active()) {
3398                                                         continue;
3399                                                 }
3400                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3401                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3402                                                 ms->set_beat (start);
3403                                                 ms->set_pulse (t->pulse());
3404                                         }
3405                                         ms->set_frame (prev->frame());
3406                                 }
3407
3408                         } else {
3409                                 // metric will be at frames=0 bbt=1|1|0 by default
3410                                 // which is correct for our purpose
3411                         }
3412
3413                         // cerr << bbt << endl;
3414
3415                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3416                                 if (!t->active()) {
3417                                         continue;
3418                                 }
3419                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3420                                 tempo = t;
3421                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3422                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3423                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3424
3425                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3426
3427                                 if (first) {
3428                                         first = false;
3429                                 } else {
3430
3431                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3432                                                 /* round up to next beat */
3433                                                 bbt.beats += 1;
3434                                         }
3435
3436                                         bbt.ticks = 0;
3437
3438                                         if (bbt.beats != 1) {
3439                                                 /* round up to next bar */
3440                                                 bbt.bars += 1;
3441                                                 bbt.beats = 1;
3442                                         }
3443                                 }
3444                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3445                                 m->set_beat (start);
3446                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3447                                 meter = m;
3448                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3449                         } else {
3450                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3451                                 abort(); /*NOTREACHED*/
3452                         }
3453
3454                         prev = (*i);
3455                 }
3456
3457                 recompute_map (_metrics);
3458         }
3459
3460
3461         PropertyChanged (PropertyChange ());
3462 }
3463 bool
3464 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3465 {
3466         bool moved = false;
3467
3468         std::list<MetricSection*> metric_kill_list;
3469
3470         TempoSection* last_tempo = NULL;
3471         MeterSection* last_meter = NULL;
3472         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3473         bool meter_after = false; // is there a meter marker likewise?
3474         {
3475                 Glib::Threads::RWLock::WriterLock lm (lock);
3476                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3477                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3478                                 metric_kill_list.push_back(*i);
3479                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3480                                 if (lt)
3481                                         last_tempo = lt;
3482                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3483                                 if (lm)
3484                                         last_meter = lm;
3485                         }
3486                         else if ((*i)->frame() >= where) {
3487                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3488                                 (*i)->set_frame ((*i)->frame() - amount);
3489                                 if ((*i)->frame() == where) {
3490                                         // marker was immediately after end of range
3491                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3492                                         meter_after = dynamic_cast<MeterSection*> (*i);
3493                                 }
3494                                 moved = true;
3495                         }
3496                 }
3497
3498                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3499                 if (last_tempo && !tempo_after) {
3500                         metric_kill_list.remove(last_tempo);
3501                         last_tempo->set_frame(where);
3502                         moved = true;
3503                 }
3504                 if (last_meter && !meter_after) {
3505                         metric_kill_list.remove(last_meter);
3506                         last_meter->set_frame(where);
3507                         moved = true;
3508                 }
3509
3510                 //remove all the remaining metrics
3511                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3512                         _metrics.remove(*i);
3513                         moved = true;
3514                 }
3515
3516                 if (moved) {
3517                         recompute_map (_metrics);
3518                 }
3519         }
3520         PropertyChanged (PropertyChange ());
3521         return moved;
3522 }
3523
3524 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3525  *  pos can be -ve, if required.
3526  */
3527 framepos_t
3528 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3529 {
3530         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
3531 }
3532
3533 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3534 framepos_t
3535 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3536 {
3537         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
3538 }
3539
3540 /** Add the BBT interval op to pos and return the result */
3541 framepos_t
3542 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3543 {
3544         Glib::Threads::RWLock::ReaderLock lm (lock);
3545
3546         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3547         pos_bbt.ticks += op.ticks;
3548         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3549                 ++pos_bbt.beats;
3550                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3551         }
3552         pos_bbt.beats += op.beats;
3553         /* the meter in effect will start on the bar */
3554         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();
3555         while (pos_bbt.beats >= divisions_per_bar + 1) {
3556                 ++pos_bbt.bars;
3557                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3558                 pos_bbt.beats -= divisions_per_bar;
3559         }
3560         pos_bbt.bars += op.bars;
3561
3562         return frame_at_bbt_locked (_metrics, pos_bbt);
3563 }
3564
3565 /** Count the number of beats that are equivalent to distance when going forward,
3566     starting at pos.
3567 */
3568 Evoral::Beats
3569 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3570 {
3571         return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
3572 }
3573
3574 struct bbtcmp {
3575     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3576             return a < b;
3577     }
3578 };
3579
3580 std::ostream&
3581 operator<< (std::ostream& o, const Meter& m) {
3582         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3583 }
3584
3585 std::ostream&
3586 operator<< (std::ostream& o, const Tempo& t) {
3587         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3588 }
3589
3590 std::ostream&
3591 operator<< (std::ostream& o, const MetricSection& section) {
3592
3593         o << "MetricSection @ " << section.frame() << ' ';
3594
3595         const TempoSection* ts;
3596         const MeterSection* ms;
3597
3598         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3599                 o << *((const Tempo*) ts);
3600         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3601                 o << *((const Meter*) ms);
3602         }
3603
3604         return o;
3605 }