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