Amend last commit.
[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
2675                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2676                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2677                 */
2678                 double contribution = 0.0;
2679
2680                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2681                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2682                 }
2683
2684                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2685
2686                 const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2687                 const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2688
2689                 double new_bpm;
2690
2691                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2692
2693                         if (prev_t->position_lock_style() == MusicTime) {
2694                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2695
2696                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2697                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2698
2699                                 } else {
2700                                         /* prev to prev is irrelevant */
2701
2702                                         if (start_pulse != prev_t->pulse()) {
2703                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2704                                         } else {
2705                                                 new_bpm = prev_t->beats_per_minute();
2706                                         }
2707                                 }
2708                         } else {
2709                                 /* AudioTime */
2710                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2711                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2712                                                                                 / (double) ((end_frame) - prev_to_prev_t->frame()));
2713                                 } else {
2714                                         /* prev_to_prev_t is irrelevant */
2715
2716                                         if (end_frame != prev_t->frame()) {
2717                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2718                                         } else {
2719                                                 new_bpm = prev_t->beats_per_minute();
2720                                         }
2721                                 }
2722                         }
2723                 } else {
2724
2725                         double frame_ratio;
2726                         double pulse_ratio;
2727                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2728
2729                         if (prev_to_prev_t) {
2730
2731                                 frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2732                                 pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2733                         } else {
2734
2735                                 frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2736                                 pulse_ratio = (start_pulse / end_pulse);
2737                         }
2738                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2739                 }
2740
2741                 prev_t->set_beats_per_minute (new_bpm);
2742                 recompute_tempos (future_map);
2743                 recompute_meters (future_map);
2744
2745                 if (check_solved (future_map)) {
2746                         ts->set_beats_per_minute (new_bpm);
2747                         recompute_tempos (_metrics);
2748                         recompute_meters (_metrics);
2749                 }
2750         }
2751
2752         Metrics::const_iterator d = future_map.begin();
2753         while (d != future_map.end()) {
2754                 delete (*d);
2755                 ++d;
2756         }
2757
2758         MetricPositionChanged (); // Emit Signal
2759 }
2760
2761 framecnt_t
2762 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2763 {
2764         Glib::Threads::RWLock::ReaderLock lm (lock);
2765
2766         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2767         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2768         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2769
2770         return frame_at_beat_locked (_metrics, total_beats);
2771 }
2772
2773 framepos_t
2774 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2775 {
2776         return round_to_type (fr, dir, Bar);
2777 }
2778
2779 framepos_t
2780 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2781 {
2782         return round_to_type (fr, dir, Beat);
2783 }
2784
2785 framepos_t
2786 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2787 {
2788         Glib::Threads::RWLock::ReaderLock lm (lock);
2789         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2790         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2791         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2792
2793         ticks -= beats * BBT_Time::ticks_per_beat;
2794
2795         if (dir > 0) {
2796                 /* round to next (or same iff dir == RoundUpMaybe) */
2797
2798                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2799
2800                 if (mod == 0 && dir == RoundUpMaybe) {
2801                         /* right on the subdivision, which is fine, so do nothing */
2802
2803                 } else if (mod == 0) {
2804                         /* right on the subdivision, so the difference is just the subdivision ticks */
2805                         ticks += ticks_one_subdivisions_worth;
2806
2807                 } else {
2808                         /* not on subdivision, compute distance to next subdivision */
2809
2810                         ticks += ticks_one_subdivisions_worth - mod;
2811                 }
2812
2813                 if (ticks >= BBT_Time::ticks_per_beat) {
2814                         ticks -= BBT_Time::ticks_per_beat;
2815                 }
2816         } else if (dir < 0) {
2817
2818                 /* round to previous (or same iff dir == RoundDownMaybe) */
2819
2820                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2821
2822                 if (difference == 0 && dir == RoundDownAlways) {
2823                         /* right on the subdivision, but force-rounding down,
2824                            so the difference is just the subdivision ticks */
2825                         difference = ticks_one_subdivisions_worth;
2826                 }
2827
2828                 if (ticks < difference) {
2829                         ticks = BBT_Time::ticks_per_beat - ticks;
2830                 } else {
2831                         ticks -= difference;
2832                 }
2833
2834         } else {
2835                 /* round to nearest */
2836                 double rem;
2837
2838                 /* compute the distance to the previous and next subdivision */
2839
2840                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2841
2842                         /* closer to the next subdivision, so shift forward */
2843
2844                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2845
2846                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2847
2848                         if (ticks > BBT_Time::ticks_per_beat) {
2849                                 ++beats;
2850                                 ticks -= BBT_Time::ticks_per_beat;
2851                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2852                         }
2853
2854                 } else if (rem > 0) {
2855
2856                         /* closer to previous subdivision, so shift backward */
2857
2858                         if (rem > ticks) {
2859                                 if (beats == 0) {
2860                                         /* can't go backwards past zero, so ... */
2861                                         return 0;
2862                                 }
2863                                 /* step back to previous beat */
2864                                 --beats;
2865                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2866                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2867                         } else {
2868                                 ticks = lrint (ticks - rem);
2869                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2870                         }
2871                 } else {
2872                         /* on the subdivision, do nothing */
2873                 }
2874         }
2875
2876         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2877
2878         return ret_frame;
2879 }
2880
2881 framepos_t
2882 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2883 {
2884         Glib::Threads::RWLock::ReaderLock lm (lock);
2885
2886         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2887         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
2888
2889         switch (type) {
2890         case Bar:
2891                 if (dir < 0) {
2892                         /* find bar previous to 'frame' */
2893                         bbt.beats = 1;
2894                         bbt.ticks = 0;
2895                         return frame_at_bbt_locked (_metrics, bbt);
2896
2897                 } else if (dir > 0) {
2898                         /* find bar following 'frame' */
2899                         ++bbt.bars;
2900                         bbt.beats = 1;
2901                         bbt.ticks = 0;
2902                         return frame_at_bbt_locked (_metrics, bbt);
2903                 } else {
2904                         /* true rounding: find nearest bar */
2905                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
2906                         bbt.beats = 1;
2907                         bbt.ticks = 0;
2908                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
2909                         ++bbt.bars;
2910                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
2911
2912                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2913                                 return next_ft;
2914                         } else {
2915                                 return prev_ft;
2916                         }
2917                 }
2918
2919                 break;
2920
2921         case Beat:
2922                 if (dir < 0) {
2923                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2924                 } else if (dir > 0) {
2925                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2926                 } else {
2927                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2928                 }
2929                 break;
2930         }
2931
2932         return 0;
2933 }
2934
2935 void
2936 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2937                     framepos_t lower, framepos_t upper)
2938 {
2939         Glib::Threads::RWLock::ReaderLock lm (lock);
2940         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
2941         framecnt_t pos = 0;
2942         /* although the map handles negative beats, bbt doesn't. */
2943         if (cnt < 0.0) {
2944                 cnt = 0.0;
2945         }
2946
2947         if (frame_at_beat_locked (_metrics, cnt) >= upper) {
2948                 return;
2949         }
2950
2951         while (pos < upper) {
2952                 pos = frame_at_beat_locked (_metrics, cnt);
2953                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
2954                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
2955                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
2956                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
2957                 ++cnt;
2958         }
2959 }
2960
2961 const TempoSection&
2962 TempoMap::tempo_section_at_frame (framepos_t frame) const
2963 {
2964         Glib::Threads::RWLock::ReaderLock lm (lock);
2965         return tempo_section_at_frame_locked (_metrics, frame);
2966 }
2967
2968 const TempoSection&
2969 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
2970 {
2971         Metrics::const_iterator i;
2972         TempoSection* prev = 0;
2973
2974         for (i = metrics.begin(); i != metrics.end(); ++i) {
2975                 TempoSection* t;
2976
2977                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2978                         if (!t->active()) {
2979                                 continue;
2980                         }
2981                         if (prev && t->frame() > frame) {
2982                                 break;
2983                         }
2984
2985                         prev = t;
2986                 }
2987         }
2988
2989         if (prev == 0) {
2990                 fatal << endmsg;
2991                 abort(); /*NOTREACHED*/
2992         }
2993
2994         return *prev;
2995 }
2996
2997 const TempoSection&
2998 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
2999 {
3000         TempoSection* prev_t = 0;
3001         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
3002
3003         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3004                 TempoSection* t;
3005                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3006                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
3007                                 break;
3008                         }
3009                         prev_t = t;
3010                 }
3011
3012         }
3013         return *prev_t;
3014 }
3015
3016 /* don't use this to calculate length (the tempo is only correct for this frame).
3017    do that stuff based on the beat_at_frame and frame_at_beat api
3018 */
3019 double
3020 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3021 {
3022         Glib::Threads::RWLock::ReaderLock lm (lock);
3023
3024         const TempoSection* ts_at = &tempo_section_at_frame_locked (_metrics, frame);
3025         const TempoSection* ts_after = 0;
3026         Metrics::const_iterator i;
3027
3028         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3029                 TempoSection* t;
3030
3031                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3032                         if (!t->active()) {
3033                                 continue;
3034                         }
3035                         if ((*i)->frame() > frame) {
3036                                 ts_after = t;
3037                                 break;
3038                         }
3039                 }
3040         }
3041
3042         if (ts_after) {
3043                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate) * ts_at->note_type());
3044         }
3045         /* must be treated as constant tempo */
3046         return ts_at->frames_per_beat (_frame_rate);
3047 }
3048
3049 const MeterSection&
3050 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3051 {
3052         Metrics::const_iterator i;
3053         MeterSection* prev = 0;
3054
3055         for (i = metrics.begin(); i != metrics.end(); ++i) {
3056                 MeterSection* m;
3057
3058                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3059
3060                         if (prev && (*i)->frame() > frame) {
3061                                 break;
3062                         }
3063
3064                         prev = m;
3065                 }
3066         }
3067
3068         if (prev == 0) {
3069                 fatal << endmsg;
3070                 abort(); /*NOTREACHED*/
3071         }
3072
3073         return *prev;
3074 }
3075
3076
3077 const MeterSection&
3078 TempoMap::meter_section_at_frame (framepos_t frame) const
3079 {
3080         Glib::Threads::RWLock::ReaderLock lm (lock);
3081         return meter_section_at_frame_locked (_metrics, frame);
3082 }
3083
3084 const MeterSection&
3085 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3086 {
3087         MeterSection* prev_m = 0;
3088
3089         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3090                 MeterSection* m;
3091                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3092                         if (prev_m && m->beat() > beat) {
3093                                 break;
3094                         }
3095                         prev_m = m;
3096                 }
3097
3098         }
3099         return *prev_m;
3100 }
3101
3102 const MeterSection&
3103 TempoMap::meter_section_at_beat (double beat) const
3104 {
3105         Glib::Threads::RWLock::ReaderLock lm (lock);
3106         return meter_section_at_beat_locked (_metrics, beat);
3107 }
3108
3109 const Meter&
3110 TempoMap::meter_at_frame (framepos_t frame) const
3111 {
3112         TempoMetric m (metric_at (frame));
3113         return m.meter();
3114 }
3115
3116 void
3117 TempoMap::fix_legacy_session ()
3118 {
3119         MeterSection* prev_m = 0;
3120         TempoSection* prev_t = 0;
3121
3122         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3123                 MeterSection* m;
3124                 TempoSection* t;
3125
3126                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3127                         if (!m->movable()) {
3128                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3129                                 m->set_beat (bbt);
3130                                 m->set_pulse (0.0);
3131                                 m->set_frame (0);
3132                                 m->set_position_lock_style (AudioTime);
3133                                 prev_m = m;
3134                                 continue;
3135                         }
3136                         if (prev_m) {
3137                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3138                                                                           + (m->bbt().beats - 1)
3139                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3140                                                                           , m->bbt());
3141                                 m->set_beat (start);
3142                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3143                                         + (m->bbt().beats - 1)
3144                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3145                                 m->set_pulse (start_beat / prev_m->note_divisor());
3146                         }
3147                         prev_m = m;
3148                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3149
3150                         if (!t->active()) {
3151                                 continue;
3152                         }
3153
3154                         if (!t->movable()) {
3155                                 t->set_pulse (0.0);
3156                                 t->set_frame (0);
3157                                 t->set_position_lock_style (AudioTime);
3158                                 prev_t = t;
3159                                 continue;
3160                         }
3161
3162                         if (prev_t) {
3163                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3164                                         + (t->legacy_bbt().beats - 1)
3165                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3166                                 if (prev_m) {
3167                                         t->set_pulse (beat / prev_m->note_divisor());
3168                                 } else {
3169                                         /* really shouldn't happen but.. */
3170                                         t->set_pulse (beat / 4.0);
3171                                 }
3172                         }
3173                         prev_t = t;
3174                 }
3175         }
3176 }
3177
3178 XMLNode&
3179 TempoMap::get_state ()
3180 {
3181         Metrics::const_iterator i;
3182         XMLNode *root = new XMLNode ("TempoMap");
3183
3184         {
3185                 Glib::Threads::RWLock::ReaderLock lm (lock);
3186                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3187                         root->add_child_nocopy ((*i)->get_state());
3188                 }
3189         }
3190
3191         return *root;
3192 }
3193
3194 int
3195 TempoMap::set_state (const XMLNode& node, int /*version*/)
3196 {
3197         {
3198                 Glib::Threads::RWLock::WriterLock lm (lock);
3199
3200                 XMLNodeList nlist;
3201                 XMLNodeConstIterator niter;
3202                 Metrics old_metrics (_metrics);
3203                 _metrics.clear();
3204
3205                 nlist = node.children();
3206
3207                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3208                         XMLNode* child = *niter;
3209
3210                         if (child->name() == TempoSection::xml_state_node_name) {
3211
3212                                 try {
3213                                         TempoSection* ts = new TempoSection (*child);
3214                                         _metrics.push_back (ts);
3215                                 }
3216
3217                                 catch (failed_constructor& err){
3218                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3219                                         _metrics = old_metrics;
3220                                         break;
3221                                 }
3222
3223                         } else if (child->name() == MeterSection::xml_state_node_name) {
3224
3225                                 try {
3226                                         MeterSection* ms = new MeterSection (*child);
3227                                         _metrics.push_back (ms);
3228                                 }
3229
3230                                 catch (failed_constructor& err) {
3231                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3232                                         _metrics = old_metrics;
3233                                         break;
3234                                 }
3235                         }
3236                 }
3237
3238                 if (niter == nlist.end()) {
3239                         MetricSectionSorter cmp;
3240                         _metrics.sort (cmp);
3241                 }
3242
3243                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3244                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3245                         TempoSection* t;
3246                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3247                                 if (t->legacy_bbt().bars != 0) {
3248                                         fix_legacy_session();
3249                                         break;
3250                                 }
3251                                 break;
3252                         }
3253                 }
3254
3255                 /* check for multiple tempo/meters at the same location, which
3256                    ardour2 somehow allowed.
3257                 */
3258
3259                 Metrics::iterator prev = _metrics.end();
3260                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3261                         if (prev != _metrics.end()) {
3262                                 MeterSection* ms;
3263                                 MeterSection* prev_m;
3264                                 TempoSection* ts;
3265                                 TempoSection* prev_t;
3266                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3267                                         if (prev_m->pulse() == ms->pulse()) {
3268                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3269                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3270                                                 return -1;
3271                                         }
3272                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3273                                         if (prev_t->pulse() == ts->pulse()) {
3274                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3275                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3276                                                 return -1;
3277                                         }
3278                                 }
3279                         }
3280                         prev = i;
3281                 }
3282
3283                 recompute_map (_metrics);
3284         }
3285
3286         PropertyChanged (PropertyChange ());
3287
3288         return 0;
3289 }
3290
3291 void
3292 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3293 {
3294         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3295         const MeterSection* m;
3296         const TempoSection* t;
3297         const TempoSection* prev_t = 0;
3298
3299         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3300
3301                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3302                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3303                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3304                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3305                         if (prev_t) {
3306                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3307                                 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;
3308                         }
3309                         prev_t = t;
3310                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3311                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3312                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3313                 }
3314         }
3315         o << "------" << std::endl;
3316 }
3317
3318 int
3319 TempoMap::n_tempos() const
3320 {
3321         Glib::Threads::RWLock::ReaderLock lm (lock);
3322         int cnt = 0;
3323
3324         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3325                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3326                         cnt++;
3327                 }
3328         }
3329
3330         return cnt;
3331 }
3332
3333 int
3334 TempoMap::n_meters() const
3335 {
3336         Glib::Threads::RWLock::ReaderLock lm (lock);
3337         int cnt = 0;
3338
3339         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3340                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3341                         cnt++;
3342                 }
3343         }
3344
3345         return cnt;
3346 }
3347
3348 void
3349 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3350 {
3351         {
3352                 Glib::Threads::RWLock::WriterLock lm (lock);
3353                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3354                         if ((*i)->frame() >= where && (*i)->movable ()) {
3355                                 (*i)->set_frame ((*i)->frame() + amount);
3356                         }
3357                 }
3358
3359                 /* now reset the BBT time of all metrics, based on their new
3360                  * audio time. This is the only place where we do this reverse
3361                  * timestamp.
3362                  */
3363
3364                 Metrics::iterator i;
3365                 const MeterSection* meter;
3366                 const TempoSection* tempo;
3367                 MeterSection *m;
3368                 TempoSection *t;
3369
3370                 meter = &first_meter ();
3371                 tempo = &first_tempo ();
3372
3373                 BBT_Time start;
3374                 BBT_Time end;
3375
3376                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3377
3378                 bool first = true;
3379                 MetricSection* prev = 0;
3380
3381                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3382
3383                         BBT_Time bbt;
3384                         //TempoMetric metric (*meter, *tempo);
3385                         MeterSection* ms = const_cast<MeterSection*>(meter);
3386                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3387                         if (prev) {
3388                                 if (ts){
3389                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3390                                                 if (!t->active()) {
3391                                                         continue;
3392                                                 }
3393                                                 ts->set_pulse (t->pulse());
3394                                         }
3395                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3396                                                 ts->set_pulse (m->pulse());
3397                                         }
3398                                         ts->set_frame (prev->frame());
3399
3400                                 }
3401                                 if (ms) {
3402                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3403                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3404                                                 ms->set_beat (start);
3405                                                 ms->set_pulse (m->pulse());
3406                                         }
3407                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3408                                                 if (!t->active()) {
3409                                                         continue;
3410                                                 }
3411                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3412                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3413                                                 ms->set_beat (start);
3414                                                 ms->set_pulse (t->pulse());
3415                                         }
3416                                         ms->set_frame (prev->frame());
3417                                 }
3418
3419                         } else {
3420                                 // metric will be at frames=0 bbt=1|1|0 by default
3421                                 // which is correct for our purpose
3422                         }
3423
3424                         // cerr << bbt << endl;
3425
3426                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3427                                 if (!t->active()) {
3428                                         continue;
3429                                 }
3430                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3431                                 tempo = t;
3432                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3433                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3434                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3435
3436                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3437
3438                                 if (first) {
3439                                         first = false;
3440                                 } else {
3441
3442                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3443                                                 /* round up to next beat */
3444                                                 bbt.beats += 1;
3445                                         }
3446
3447                                         bbt.ticks = 0;
3448
3449                                         if (bbt.beats != 1) {
3450                                                 /* round up to next bar */
3451                                                 bbt.bars += 1;
3452                                                 bbt.beats = 1;
3453                                         }
3454                                 }
3455                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3456                                 m->set_beat (start);
3457                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3458                                 meter = m;
3459                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3460                         } else {
3461                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3462                                 abort(); /*NOTREACHED*/
3463                         }
3464
3465                         prev = (*i);
3466                 }
3467
3468                 recompute_map (_metrics);
3469         }
3470
3471
3472         PropertyChanged (PropertyChange ());
3473 }
3474 bool
3475 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3476 {
3477         bool moved = false;
3478
3479         std::list<MetricSection*> metric_kill_list;
3480
3481         TempoSection* last_tempo = NULL;
3482         MeterSection* last_meter = NULL;
3483         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3484         bool meter_after = false; // is there a meter marker likewise?
3485         {
3486                 Glib::Threads::RWLock::WriterLock lm (lock);
3487                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3488                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3489                                 metric_kill_list.push_back(*i);
3490                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3491                                 if (lt)
3492                                         last_tempo = lt;
3493                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3494                                 if (lm)
3495                                         last_meter = lm;
3496                         }
3497                         else if ((*i)->frame() >= where) {
3498                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3499                                 (*i)->set_frame ((*i)->frame() - amount);
3500                                 if ((*i)->frame() == where) {
3501                                         // marker was immediately after end of range
3502                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3503                                         meter_after = dynamic_cast<MeterSection*> (*i);
3504                                 }
3505                                 moved = true;
3506                         }
3507                 }
3508
3509                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3510                 if (last_tempo && !tempo_after) {
3511                         metric_kill_list.remove(last_tempo);
3512                         last_tempo->set_frame(where);
3513                         moved = true;
3514                 }
3515                 if (last_meter && !meter_after) {
3516                         metric_kill_list.remove(last_meter);
3517                         last_meter->set_frame(where);
3518                         moved = true;
3519                 }
3520
3521                 //remove all the remaining metrics
3522                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3523                         _metrics.remove(*i);
3524                         moved = true;
3525                 }
3526
3527                 if (moved) {
3528                         recompute_map (_metrics);
3529                 }
3530         }
3531         PropertyChanged (PropertyChange ());
3532         return moved;
3533 }
3534
3535 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3536  *  pos can be -ve, if required.
3537  */
3538 framepos_t
3539 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3540 {
3541         Glib::Threads::RWLock::ReaderLock lm (lock);
3542
3543         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) + beats.to_double());
3544 }
3545
3546 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3547 framepos_t
3548 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3549 {
3550         Glib::Threads::RWLock::ReaderLock lm (lock);
3551
3552         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
3553 }
3554
3555 /** Add the BBT interval op to pos and return the result */
3556 framepos_t
3557 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3558 {
3559         Glib::Threads::RWLock::ReaderLock lm (lock);
3560
3561         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3562         pos_bbt.ticks += op.ticks;
3563         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3564                 ++pos_bbt.beats;
3565                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3566         }
3567         pos_bbt.beats += op.beats;
3568         /* the meter in effect will start on the bar */
3569         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();
3570         while (pos_bbt.beats >= divisions_per_bar + 1) {
3571                 ++pos_bbt.bars;
3572                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3573                 pos_bbt.beats -= divisions_per_bar;
3574         }
3575         pos_bbt.bars += op.bars;
3576
3577         return frame_at_bbt_locked (_metrics, pos_bbt);
3578 }
3579
3580 /** Count the number of beats that are equivalent to distance when going forward,
3581     starting at pos.
3582 */
3583 Evoral::Beats
3584 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3585 {
3586         Glib::Threads::RWLock::ReaderLock lm (lock);
3587
3588         return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
3589 }
3590
3591 struct bbtcmp {
3592     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3593             return a < b;
3594     }
3595 };
3596
3597 std::ostream&
3598 operator<< (std::ostream& o, const Meter& m) {
3599         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3600 }
3601
3602 std::ostream&
3603 operator<< (std::ostream& o, const Tempo& t) {
3604         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3605 }
3606
3607 std::ostream&
3608 operator<< (std::ostream& o, const MetricSection& section) {
3609
3610         o << "MetricSection @ " << section.frame() << ' ';
3611
3612         const TempoSection* ts;
3613         const MeterSection* ms;
3614
3615         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3616                 o << *((const Tempo*) ts);
3617         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3618                 o << *((const Meter*) ms);
3619         }
3620
3621         return o;
3622 }