Make TempoMap::framepos_plus_beats() & TempoMap::framepos_minus_beats() more correct.
[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                                         continue;
2031                                 }
2032                                 if (t->position_lock_style() == MusicTime) {
2033                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2034                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2035                                 } else {
2036                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2037                                         if (!t->locked_to_meter()) {
2038                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2039                                         }
2040                                 }
2041                         }
2042                         prev_t = t;
2043                 }
2044         }
2045
2046         if (section_prev) {
2047                 section_prev->set_c_func (section_prev->compute_c_func_frame (section->pulses_per_minute(), frame, _frame_rate));
2048                 if (!section->locked_to_meter()) {
2049                         section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2050                 }
2051         }
2052
2053 #if (0)
2054         recompute_tempos (imaginary);
2055
2056         if (check_solved (imaginary)) {
2057                 return true;
2058         } else {
2059                 dunp (imaginary, std::cout);
2060         }
2061 #endif
2062
2063         MetricSectionFrameSorter fcmp;
2064         imaginary.sort (fcmp);
2065
2066         recompute_tempos (imaginary);
2067
2068         if (check_solved (imaginary)) {
2069                 return true;
2070         }
2071
2072         return false;
2073 }
2074
2075 bool
2076 TempoMap::solve_map_pulse (Metrics& imaginary, TempoSection* section, const double& pulse)
2077 {
2078         TempoSection* prev_t = 0;
2079         TempoSection* section_prev = 0;
2080
2081         section->set_pulse (pulse);
2082
2083         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2084                 TempoSection* t;
2085                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2086                         if (!t->active()) {
2087                                 continue;
2088                         }
2089                         if (!t->movable()) {
2090                                 t->set_pulse (0.0);
2091                                 prev_t = t;
2092                                 continue;
2093                         }
2094                         if (prev_t) {
2095                                 if (t == section) {
2096                                         section_prev = prev_t;
2097                                         continue;
2098                                 }
2099                                 if (t->position_lock_style() == MusicTime) {
2100                                         prev_t->set_c_func (prev_t->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2101                                         t->set_frame (prev_t->frame_at_pulse (t->pulse(), _frame_rate));
2102                                 } else {
2103                                         prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2104                                         if (!t->locked_to_meter()) {
2105                                                 t->set_pulse (prev_t->pulse_at_frame (t->frame(), _frame_rate));
2106                                         }
2107                                 }
2108                         }
2109                         prev_t = t;
2110                 }
2111         }
2112
2113         if (section_prev) {
2114                 section_prev->set_c_func (section_prev->compute_c_func_pulse (section->pulses_per_minute(), pulse, _frame_rate));
2115                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2116         }
2117
2118 #if (0)
2119         recompute_tempos (imaginary);
2120
2121         if (check_solved (imaginary)) {
2122                 return true;
2123         } else {
2124                 dunp (imaginary, std::cout);
2125         }
2126 #endif
2127
2128         MetricSectionSorter cmp;
2129         imaginary.sort (cmp);
2130
2131         recompute_tempos (imaginary);
2132         /* Reordering
2133          * XX need a restriction here, but only for this case,
2134          * as audio locked tempos don't interact in the same way.
2135          *
2136          * With music-locked tempos, the solution to cross-dragging can fly off the screen
2137          * e.g.
2138          * |50 bpm                        |250 bpm |60 bpm
2139          *                drag 250 to the pulse after 60->
2140          * a clue: dragging the second 60 <- past the 250 would cause no such problem.
2141          */
2142         if (check_solved (imaginary)) {
2143                 return true;
2144         }
2145
2146         return false;
2147 }
2148
2149 bool
2150 TempoMap::solve_map_frame (Metrics& imaginary, MeterSection* section, const framepos_t& frame)
2151 {
2152         /* disallow moving first meter past any subsequent one, and any movable meter before the first one */
2153         const MeterSection* other =  &meter_section_at_frame_locked (imaginary, frame);
2154         if ((!section->movable() && other->movable()) || (!other->movable() && section->movable() && other->frame() >= frame)) {
2155                 return false;
2156         }
2157
2158         if (!section->movable()) {
2159                 /* lock the first tempo to our first meter */
2160                 if (!set_active_tempos (imaginary, frame)) {
2161                         return false;
2162                 }
2163         }
2164
2165         TempoSection* meter_locked_tempo = 0;
2166
2167         for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2168                 TempoSection* t;
2169                 if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2170                         if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
2171                                 meter_locked_tempo = t;
2172                                 break;
2173                         }
2174                 }
2175         }
2176
2177         if (!meter_locked_tempo) {
2178                 return false;
2179         }
2180
2181         MeterSection* prev_m = 0;
2182         Metrics future_map;
2183         TempoSection* tempo_copy = copy_metrics_and_point (imaginary, future_map, meter_locked_tempo);
2184         bool solved = false;
2185
2186         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2187                 MeterSection* m;
2188                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2189                         if (m == section){
2190                                 if (prev_m && section->movable()) {
2191                                         const double beats = (pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor();
2192                                         if (beats + prev_m->beat() < section->beat()) {
2193                                                 /* set the frame/pulse corresponding to its musical position,
2194                                                  * as an earlier time than this has been requested.
2195                                                 */
2196                                                 const double new_pulse = ((section->beat() - prev_m->beat())
2197                                                                           / prev_m->note_divisor()) + prev_m->pulse();
2198
2199                                                 const framepos_t smallest_frame = frame_at_pulse_locked (future_map, new_pulse);
2200
2201                                                 if ((solved = solve_map_frame (future_map, tempo_copy, smallest_frame))) {
2202                                                         meter_locked_tempo->set_pulse (new_pulse);
2203                                                         solve_map_frame (imaginary, meter_locked_tempo, smallest_frame);
2204                                                         section->set_frame (smallest_frame);
2205                                                         section->set_pulse (new_pulse);
2206                                                 } else {
2207                                                         solved = false;
2208                                                 }
2209
2210                                                 Metrics::const_iterator d = future_map.begin();
2211                                                 while (d != future_map.end()) {
2212                                                         delete (*d);
2213                                                         ++d;
2214                                                 }
2215
2216                                                 if (!solved) {
2217                                                         return false;
2218                                                 }
2219                                         } else {
2220                                                 /* all is ok. set section's locked tempo if allowed.
2221                                                    possibly disallowed if there is an adjacent audio-locked tempo.
2222                                                    XX this check could possibly go. its never actually happened here.
2223                                                 */
2224                                                 MeterSection* meter_copy = const_cast<MeterSection*> (&meter_section_at_frame_locked (future_map, section->frame()));
2225                                                 meter_copy->set_frame (frame);
2226
2227                                                 if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2228                                                         section->set_frame (frame);
2229                                                         meter_locked_tempo->set_pulse (((section->beat() - prev_m->beat())
2230                                                                                                 / prev_m->note_divisor()) + prev_m->pulse());
2231                                                         solve_map_frame (imaginary, meter_locked_tempo, frame);
2232                                                 } else {
2233                                                         solved = false;
2234                                                 }
2235
2236                                                 Metrics::const_iterator d = future_map.begin();
2237                                                 while (d != future_map.end()) {
2238                                                         delete (*d);
2239                                                         ++d;
2240                                                 }
2241
2242                                                 if (!solved) {
2243                                                         return false;
2244                                                 }
2245                                         }
2246                                 } else {
2247                                         /* not movable (first meter atm) */
2248
2249                                         tempo_copy->set_frame (frame);
2250                                         tempo_copy->set_pulse (0.0);
2251
2252                                         if ((solved = solve_map_frame (future_map, tempo_copy, frame))) {
2253                                                 section->set_frame (frame);
2254                                                 meter_locked_tempo->set_frame (frame);
2255                                                 meter_locked_tempo->set_pulse (0.0);
2256                                                 solve_map_frame (imaginary, meter_locked_tempo, frame);
2257                                         } else {
2258                                                 solved = false;
2259                                         }
2260
2261                                         Metrics::const_iterator d = future_map.begin();
2262                                         while (d != future_map.end()) {
2263                                                 delete (*d);
2264                                                 ++d;
2265                                         }
2266
2267                                         if (!solved) {
2268                                                 return false;
2269                                         }
2270
2271                                         pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2272                                         section->set_beat (b_bbt);
2273                                         section->set_pulse (0.0);
2274
2275                                 }
2276                                 break;
2277                         }
2278
2279                         prev_m = m;
2280                 }
2281         }
2282
2283         MetricSectionFrameSorter fcmp;
2284         imaginary.sort (fcmp);
2285
2286         recompute_meters (imaginary);
2287
2288         return true;
2289 }
2290
2291 bool
2292 TempoMap::solve_map_bbt (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
2293 {
2294         /* disallow setting section to an existing meter's bbt */
2295         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2296                 MeterSection* m;
2297                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2298                         if (m != section && m->bbt().bars == when.bars) {
2299                                 return false;
2300                         }
2301                 }
2302         }
2303
2304         MeterSection* prev_m = 0;
2305         MeterSection* section_prev = 0;
2306
2307         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2308                 MeterSection* m;
2309                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2310                         pair<double, BBT_Time> b_bbt;
2311                         double new_pulse = 0.0;
2312
2313                         if (prev_m && m->bbt().bars > when.bars && !section_prev){
2314                                 section_prev = prev_m;
2315                                 const double beats = (when.bars - section_prev->bbt().bars) * section_prev->divisions_per_bar();
2316                                 const double pulse = (beats / section_prev->note_divisor()) + section_prev->pulse();
2317                                 pair<double, BBT_Time> b_bbt = make_pair (beats + section_prev->beat(), when);
2318
2319                                 section->set_beat (b_bbt);
2320                                 section->set_pulse (pulse);
2321                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2322                                 prev_m = section;
2323                                 continue;
2324                         }
2325
2326                         if (m->position_lock_style() == AudioTime) {
2327                                 TempoSection* meter_locked_tempo = 0;
2328
2329                                 for (Metrics::const_iterator ii = imaginary.begin(); ii != imaginary.end(); ++ii) {
2330                                         TempoSection* t;
2331                                         if ((t = dynamic_cast<TempoSection*> (*ii)) != 0) {
2332                                                 if ((t->locked_to_meter() || !t->movable()) && t->frame() == m->frame()) {
2333                                                         meter_locked_tempo = t;
2334                                                         break;
2335                                                 }
2336                                         }
2337                                 }
2338
2339                                 if (!meter_locked_tempo) {
2340                                         return false;
2341                                 }
2342
2343                                 if (prev_m) {
2344                                         const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2345
2346                                         if (beats + prev_m->beat() != m->beat()) {
2347                                                 /* tempo/ meter change caused a change in beat (bar). */
2348                                                 b_bbt = make_pair (beats + prev_m->beat()
2349                                                                    , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2350                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2351                                         } else if (m->movable()) {
2352                                                 b_bbt = make_pair (m->beat(), m->bbt());
2353                                                 new_pulse = prev_m->pulse() + (beats / prev_m->note_divisor());
2354                                         }
2355                                 } else {
2356                                         b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
2357                                 }
2358
2359                                 meter_locked_tempo->set_pulse (new_pulse);
2360                                 m->set_beat (b_bbt);
2361                                 m->set_pulse (new_pulse);
2362
2363                         } else {
2364                                 /* MusicTime */
2365                                 const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
2366                                 if (beats + prev_m->beat() != m->beat()) {
2367                                         /* tempo/ meter change caused a change in beat (bar). */
2368                                         b_bbt = make_pair (beats + prev_m->beat()
2369                                                            , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
2370                                 } else {
2371                                         b_bbt = make_pair (beats + prev_m->beat()
2372                                                            , m->bbt());
2373                                 }
2374                                 new_pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2375                                 m->set_beat (b_bbt);
2376                                 m->set_pulse (new_pulse);
2377                                 m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
2378                         }
2379
2380                         prev_m = m;
2381                 }
2382         }
2383
2384         if (!section_prev) {
2385
2386                 const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
2387                 const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
2388                 pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), when);
2389
2390                 section->set_beat (b_bbt);
2391                 section->set_pulse (pulse);
2392                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2393         }
2394
2395         MetricSectionSorter cmp;
2396         imaginary.sort (cmp);
2397
2398         recompute_meters (imaginary);
2399
2400         return true;
2401 }
2402
2403 /** places a copy of _metrics into copy and returns a pointer
2404  *  to section's equivalent in copy.
2405  */
2406 TempoSection*
2407 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section)
2408 {
2409         TempoSection* ret = 0;
2410
2411         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2412                 TempoSection* t;
2413                 MeterSection* m;
2414                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2415                         if (t == section) {
2416                                 ret = new TempoSection (*t);
2417                                 copy.push_back (ret);
2418                                 continue;
2419                         }
2420
2421                         TempoSection* cp = new TempoSection (*t);
2422                         copy.push_back (cp);
2423                 }
2424                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2425                         MeterSection* cp = new MeterSection (*m);
2426                         copy.push_back (cp);
2427                 }
2428         }
2429
2430         return ret;
2431 }
2432
2433 MeterSection*
2434 TempoMap::copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section)
2435 {
2436         MeterSection* ret = 0;
2437
2438         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2439                 TempoSection* t;
2440                 MeterSection* m;
2441                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2442                         TempoSection* cp = new TempoSection (*t);
2443                         copy.push_back (cp);
2444                 }
2445
2446                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
2447                         if (m == section) {
2448                                 ret = new MeterSection (*m);
2449                                 copy.push_back (ret);
2450                                 continue;
2451                         }
2452                         MeterSection* cp = new MeterSection (*m);
2453                         copy.push_back (cp);
2454                 }
2455         }
2456
2457         return ret;
2458 }
2459
2460 /** answers the question "is this a valid beat position for this tempo section?".
2461  *  it returns true if the tempo section can be moved to the requested bbt position,
2462  *  leaving the tempo map in a solved state.
2463  * @param section the tempo section to be moved
2464  * @param bbt the requested new position for the tempo section
2465  * @return true if the tempo section can be moved to the position, otherwise false.
2466  */
2467 bool
2468 TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
2469 {
2470         Metrics copy;
2471         TempoSection* tempo_copy = 0;
2472
2473         {
2474                 Glib::Threads::RWLock::ReaderLock lm (lock);
2475                 tempo_copy = copy_metrics_and_point (_metrics, copy, ts);
2476                 if (!tempo_copy) {
2477                         return false;
2478                 }
2479         }
2480
2481         const bool ret = solve_map_pulse (copy, tempo_copy, pulse_at_bbt_locked (copy, bbt));
2482
2483         Metrics::const_iterator d = copy.begin();
2484         while (d != copy.end()) {
2485                 delete (*d);
2486                 ++d;
2487         }
2488
2489         return ret;
2490 }
2491
2492 /**
2493 * 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,
2494 * taking any possible reordering as a consequence of this into account.
2495 * @param section - the section to be altered
2496 * @param bbt - the bbt where the altered tempo will fall
2497 * @return returns - the position in pulses and frames (as a pair) where the new tempo section will lie.
2498 */
2499 pair<double, framepos_t>
2500 TempoMap::predict_tempo_position (TempoSection* section, const BBT_Time& bbt)
2501 {
2502         Metrics future_map;
2503         pair<double, framepos_t> ret = make_pair (0.0, 0);
2504
2505         Glib::Threads::RWLock::ReaderLock lm (lock);
2506
2507         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, section);
2508
2509         const double beat = beat_at_bbt_locked (future_map, bbt);
2510
2511         if (solve_map_pulse (future_map, tempo_copy, pulse_at_beat_locked (future_map, beat))) {
2512                 ret.first = tempo_copy->pulse();
2513                 ret.second = tempo_copy->frame();
2514         } else {
2515                 ret.first = section->pulse();
2516                 ret.second = section->frame();
2517         }
2518
2519         Metrics::const_iterator d = future_map.begin();
2520         while (d != future_map.end()) {
2521                 delete (*d);
2522                 ++d;
2523         }
2524         return ret;
2525 }
2526
2527 void
2528 TempoMap::gui_move_tempo (TempoSection* ts, const framepos_t& frame)
2529 {
2530         Metrics future_map;
2531
2532         if (ts->position_lock_style() == MusicTime) {
2533                 {
2534                         Glib::Threads::RWLock::WriterLock lm (lock);
2535                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2536                         const double pulse = pulse_at_frame_locked (future_map, frame);
2537                         if (solve_map_pulse (future_map, tempo_copy, pulse)) {
2538                                 solve_map_pulse (_metrics, ts, pulse);
2539                                 recompute_meters (_metrics);
2540                         }
2541                 }
2542
2543         } else {
2544
2545                 {
2546                         Glib::Threads::RWLock::WriterLock lm (lock);
2547                         TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2548                         if (solve_map_frame (future_map, tempo_copy, frame)) {
2549                                 solve_map_frame (_metrics, ts, frame);
2550                                 recompute_meters (_metrics);
2551                         }
2552                 }
2553         }
2554
2555         Metrics::const_iterator d = future_map.begin();
2556         while (d != future_map.end()) {
2557                 delete (*d);
2558                 ++d;
2559         }
2560
2561         MetricPositionChanged (); // Emit Signal
2562 }
2563
2564 void
2565 TempoMap::gui_move_meter (MeterSection* ms, const framepos_t& frame)
2566 {
2567         Metrics future_map;
2568
2569         if (ms->position_lock_style() == AudioTime) {
2570
2571                 {
2572                         Glib::Threads::RWLock::WriterLock lm (lock);
2573                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2574
2575                         if (solve_map_frame (future_map, copy, frame)) {
2576                                 solve_map_frame (_metrics, ms, frame);
2577                                 recompute_tempos (_metrics);
2578                         }
2579                 }
2580         } else {
2581                 {
2582                         Glib::Threads::RWLock::WriterLock lm (lock);
2583                         MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
2584
2585                         const double beat = beat_at_frame_locked (_metrics, frame);
2586                         const Timecode::BBT_Time bbt = bbt_at_beat_locked (_metrics, beat);
2587
2588                         if (solve_map_bbt (future_map, copy, bbt)) {
2589                                 solve_map_bbt (_metrics, ms, bbt);
2590                                 recompute_tempos (_metrics);
2591                         }
2592                 }
2593         }
2594
2595         Metrics::const_iterator d = future_map.begin();
2596         while (d != future_map.end()) {
2597                 delete (*d);
2598                 ++d;
2599         }
2600
2601         MetricPositionChanged (); // Emit Signal
2602 }
2603
2604 bool
2605 TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
2606 {
2607         Metrics future_map;
2608         bool can_solve = false;
2609         {
2610                 Glib::Threads::RWLock::WriterLock lm (lock);
2611                 TempoSection* tempo_copy = copy_metrics_and_point (_metrics, future_map, ts);
2612                 tempo_copy->set_beats_per_minute (bpm.beats_per_minute());
2613                 recompute_tempos (future_map);
2614
2615                 if (check_solved (future_map)) {
2616                         ts->set_beats_per_minute (bpm.beats_per_minute());
2617                         recompute_map (_metrics);
2618                         can_solve = true;
2619                 }
2620         }
2621
2622         Metrics::const_iterator d = future_map.begin();
2623         while (d != future_map.end()) {
2624                 delete (*d);
2625                 ++d;
2626         }
2627         if (can_solve) {
2628                 MetricPositionChanged (); // Emit Signal
2629         }
2630         return can_solve;
2631 }
2632
2633 void
2634 TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
2635 {
2636         /*
2637           Ts (future prev_t)   Tnext
2638           |                    |
2639           |     [drag^]        |
2640           |----------|----------
2641                 e_f  pulse(frame)
2642         */
2643
2644         Metrics future_map;
2645
2646         {
2647                 Glib::Threads::RWLock::WriterLock lm (lock);
2648
2649                 if (!ts) {
2650                         return;
2651                 }
2652
2653                 TempoSection* prev_t = copy_metrics_and_point (_metrics, future_map, ts);
2654                 TempoSection* prev_to_prev_t = 0;
2655                 const frameoffset_t fr_off = end_frame - frame;
2656
2657                 if (prev_t && prev_t->pulse() > 0.0) {
2658                         prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_frame_locked (future_map, prev_t->frame() - 1));
2659                 }
2660
2661                 TempoSection* next_t = 0;
2662                 for (Metrics::iterator i = future_map.begin(); i != future_map.end(); ++i) {
2663                         TempoSection* t = 0;
2664                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2665                                 if (t->frame() > ts->frame()) {
2666                                         next_t = t;
2667                                         break;
2668                                 }
2669                         }
2670                 }
2671
2672                 /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
2673                    constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
2674                 */
2675                 double contribution = 0.0;
2676
2677                 if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2678                         contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
2679                 }
2680
2681                 const frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
2682
2683                 const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
2684                 const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
2685
2686                 double new_bpm;
2687
2688                 if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
2689
2690                         if (prev_t->position_lock_style() == MusicTime) {
2691                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2692
2693                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2694                                                                                 / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
2695
2696                                 } else {
2697                                         /* prev to prev is irrelevant */
2698
2699                                         if (start_pulse != prev_t->pulse()) {
2700                                                 new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
2701                                         } else {
2702                                                 new_bpm = prev_t->beats_per_minute();
2703                                         }
2704                                 }
2705                         } else {
2706                                 /* AudioTime */
2707                                 if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
2708                                         new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
2709                                                                                 / (double) ((end_frame) - prev_to_prev_t->frame()));
2710                                 } else {
2711                                         /* prev_to_prev_t is irrelevant */
2712
2713                                         if (end_frame != prev_t->frame()) {
2714                                                 new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
2715                                         } else {
2716                                                 new_bpm = prev_t->beats_per_minute();
2717                                         }
2718                                 }
2719                         }
2720                 } else {
2721
2722                         double frame_ratio;
2723                         double pulse_ratio;
2724                         const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
2725
2726                         if (prev_to_prev_t) {
2727
2728                                 frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
2729                                 pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (end_pulse - prev_to_prev_t->pulse()));
2730                         } else {
2731
2732                                 frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
2733                                 pulse_ratio = (start_pulse / end_pulse);
2734                         }
2735                         new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
2736                 }
2737
2738                 prev_t->set_beats_per_minute (new_bpm);
2739                 recompute_tempos (future_map);
2740                 recompute_meters (future_map);
2741
2742                 if (check_solved (future_map)) {
2743                         ts->set_beats_per_minute (new_bpm);
2744                         recompute_tempos (_metrics);
2745                         recompute_meters (_metrics);
2746                 }
2747         }
2748
2749         Metrics::const_iterator d = future_map.begin();
2750         while (d != future_map.end()) {
2751                 delete (*d);
2752                 ++d;
2753         }
2754
2755         MetricPositionChanged (); // Emit Signal
2756 }
2757
2758 framecnt_t
2759 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2760 {
2761         Glib::Threads::RWLock::ReaderLock lm (lock);
2762
2763         const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2764         const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2765         const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2766
2767         return frame_at_beat_locked (_metrics, total_beats);
2768 }
2769
2770 framepos_t
2771 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2772 {
2773         return round_to_type (fr, dir, Bar);
2774 }
2775
2776 framepos_t
2777 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2778 {
2779         return round_to_type (fr, dir, Beat);
2780 }
2781
2782 framepos_t
2783 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2784 {
2785         Glib::Threads::RWLock::ReaderLock lm (lock);
2786         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2787         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2788         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2789
2790         ticks -= beats * BBT_Time::ticks_per_beat;
2791
2792         if (dir > 0) {
2793                 /* round to next (or same iff dir == RoundUpMaybe) */
2794
2795                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2796
2797                 if (mod == 0 && dir == RoundUpMaybe) {
2798                         /* right on the subdivision, which is fine, so do nothing */
2799
2800                 } else if (mod == 0) {
2801                         /* right on the subdivision, so the difference is just the subdivision ticks */
2802                         ticks += ticks_one_subdivisions_worth;
2803
2804                 } else {
2805                         /* not on subdivision, compute distance to next subdivision */
2806
2807                         ticks += ticks_one_subdivisions_worth - mod;
2808                 }
2809
2810                 if (ticks >= BBT_Time::ticks_per_beat) {
2811                         ticks -= BBT_Time::ticks_per_beat;
2812                 }
2813         } else if (dir < 0) {
2814
2815                 /* round to previous (or same iff dir == RoundDownMaybe) */
2816
2817                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2818
2819                 if (difference == 0 && dir == RoundDownAlways) {
2820                         /* right on the subdivision, but force-rounding down,
2821                            so the difference is just the subdivision ticks */
2822                         difference = ticks_one_subdivisions_worth;
2823                 }
2824
2825                 if (ticks < difference) {
2826                         ticks = BBT_Time::ticks_per_beat - ticks;
2827                 } else {
2828                         ticks -= difference;
2829                 }
2830
2831         } else {
2832                 /* round to nearest */
2833                 double rem;
2834
2835                 /* compute the distance to the previous and next subdivision */
2836
2837                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2838
2839                         /* closer to the next subdivision, so shift forward */
2840
2841                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2842
2843                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2844
2845                         if (ticks > BBT_Time::ticks_per_beat) {
2846                                 ++beats;
2847                                 ticks -= BBT_Time::ticks_per_beat;
2848                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2849                         }
2850
2851                 } else if (rem > 0) {
2852
2853                         /* closer to previous subdivision, so shift backward */
2854
2855                         if (rem > ticks) {
2856                                 if (beats == 0) {
2857                                         /* can't go backwards past zero, so ... */
2858                                         return 0;
2859                                 }
2860                                 /* step back to previous beat */
2861                                 --beats;
2862                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2863                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2864                         } else {
2865                                 ticks = lrint (ticks - rem);
2866                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2867                         }
2868                 } else {
2869                         /* on the subdivision, do nothing */
2870                 }
2871         }
2872
2873         const framepos_t ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2874
2875         return ret_frame;
2876 }
2877
2878 framepos_t
2879 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2880 {
2881         Glib::Threads::RWLock::ReaderLock lm (lock);
2882
2883         const double beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2884         BBT_Time bbt (bbt_at_beat_locked (_metrics, beat_at_framepos));
2885
2886         switch (type) {
2887         case Bar:
2888                 if (dir < 0) {
2889                         /* find bar previous to 'frame' */
2890                         bbt.beats = 1;
2891                         bbt.ticks = 0;
2892                         return frame_at_bbt_locked (_metrics, bbt);
2893
2894                 } else if (dir > 0) {
2895                         /* find bar following 'frame' */
2896                         ++bbt.bars;
2897                         bbt.beats = 1;
2898                         bbt.ticks = 0;
2899                         return frame_at_bbt_locked (_metrics, bbt);
2900                 } else {
2901                         /* true rounding: find nearest bar */
2902                         framepos_t raw_ft = frame_at_bbt_locked (_metrics, bbt);
2903                         bbt.beats = 1;
2904                         bbt.ticks = 0;
2905                         framepos_t prev_ft = frame_at_bbt_locked (_metrics, bbt);
2906                         ++bbt.bars;
2907                         framepos_t next_ft = frame_at_bbt_locked (_metrics, bbt);
2908
2909                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2910                                 return next_ft;
2911                         } else {
2912                                 return prev_ft;
2913                         }
2914                 }
2915
2916                 break;
2917
2918         case Beat:
2919                 if (dir < 0) {
2920                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2921                 } else if (dir > 0) {
2922                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2923                 } else {
2924                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2925                 }
2926                 break;
2927         }
2928
2929         return 0;
2930 }
2931
2932 void
2933 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2934                     framepos_t lower, framepos_t upper)
2935 {
2936         Glib::Threads::RWLock::ReaderLock lm (lock);
2937         int32_t cnt = ceil (beat_at_frame_locked (_metrics, lower));
2938         framecnt_t pos = 0;
2939         /* although the map handles negative beats, bbt doesn't. */
2940         if (cnt < 0.0) {
2941                 cnt = 0.0;
2942         }
2943         while (pos < upper) {
2944                 pos = frame_at_beat_locked (_metrics, cnt);
2945                 const TempoSection tempo = tempo_section_at_frame_locked (_metrics, pos);
2946                 const MeterSection meter = meter_section_at_frame_locked (_metrics, pos);
2947                 const BBT_Time bbt = bbt_at_beat_locked (_metrics, cnt);
2948                 points.push_back (BBTPoint (meter, tempo_at_frame_locked (_metrics, pos), pos, bbt.bars, bbt.beats, tempo.c_func()));
2949                 ++cnt;
2950         }
2951 }
2952
2953 const TempoSection&
2954 TempoMap::tempo_section_at_frame (framepos_t frame) const
2955 {
2956         Glib::Threads::RWLock::ReaderLock lm (lock);
2957         return tempo_section_at_frame_locked (_metrics, frame);
2958 }
2959
2960 const TempoSection&
2961 TempoMap::tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
2962 {
2963         Metrics::const_iterator i;
2964         TempoSection* prev = 0;
2965
2966         for (i = metrics.begin(); i != metrics.end(); ++i) {
2967                 TempoSection* t;
2968
2969                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2970                         if (!t->active()) {
2971                                 continue;
2972                         }
2973                         if (prev && t->frame() > frame) {
2974                                 break;
2975                         }
2976
2977                         prev = t;
2978                 }
2979         }
2980
2981         if (prev == 0) {
2982                 fatal << endmsg;
2983                 abort(); /*NOTREACHED*/
2984         }
2985
2986         return *prev;
2987 }
2988
2989 const TempoSection&
2990 TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const
2991 {
2992         TempoSection* prev_t = 0;
2993         const MeterSection* prev_m = &meter_section_at_beat_locked (metrics, beat);
2994
2995         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2996                 TempoSection* t;
2997                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2998                         if (prev_t && ((t->pulse() - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat() > beat) {
2999                                 break;
3000                         }
3001                         prev_t = t;
3002                 }
3003
3004         }
3005         return *prev_t;
3006 }
3007
3008 /* don't use this to calculate length (the tempo is only correct for this frame).
3009    do that stuff based on the beat_at_frame and frame_at_beat api
3010 */
3011 double
3012 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
3013 {
3014         Glib::Threads::RWLock::ReaderLock lm (lock);
3015
3016         const TempoSection* ts_at = &tempo_section_at_frame_locked (_metrics, frame);
3017         const TempoSection* ts_after = 0;
3018         Metrics::const_iterator i;
3019
3020         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3021                 TempoSection* t;
3022
3023                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3024                         if (!t->active()) {
3025                                 continue;
3026                         }
3027                         if ((*i)->frame() > frame) {
3028                                 ts_after = t;
3029                                 break;
3030                         }
3031                 }
3032         }
3033
3034         if (ts_after) {
3035                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
3036         }
3037         /* must be treated as constant tempo */
3038         return ts_at->frames_per_beat (_frame_rate);
3039 }
3040
3041 const MeterSection&
3042 TempoMap::meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const
3043 {
3044         Metrics::const_iterator i;
3045         MeterSection* prev = 0;
3046
3047         for (i = metrics.begin(); i != metrics.end(); ++i) {
3048                 MeterSection* m;
3049
3050                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3051
3052                         if (prev && (*i)->frame() > frame) {
3053                                 break;
3054                         }
3055
3056                         prev = m;
3057                 }
3058         }
3059
3060         if (prev == 0) {
3061                 fatal << endmsg;
3062                 abort(); /*NOTREACHED*/
3063         }
3064
3065         return *prev;
3066 }
3067
3068
3069 const MeterSection&
3070 TempoMap::meter_section_at_frame (framepos_t frame) const
3071 {
3072         Glib::Threads::RWLock::ReaderLock lm (lock);
3073         return meter_section_at_frame_locked (_metrics, frame);
3074 }
3075
3076 const MeterSection&
3077 TempoMap::meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const
3078 {
3079         MeterSection* prev_m = 0;
3080
3081         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3082                 MeterSection* m;
3083                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
3084                         if (prev_m && m->beat() > beat) {
3085                                 break;
3086                         }
3087                         prev_m = m;
3088                 }
3089
3090         }
3091         return *prev_m;
3092 }
3093
3094 const MeterSection&
3095 TempoMap::meter_section_at_beat (double beat) const
3096 {
3097         Glib::Threads::RWLock::ReaderLock lm (lock);
3098         return meter_section_at_beat_locked (_metrics, beat);
3099 }
3100
3101 const Meter&
3102 TempoMap::meter_at_frame (framepos_t frame) const
3103 {
3104         TempoMetric m (metric_at (frame));
3105         return m.meter();
3106 }
3107
3108 void
3109 TempoMap::fix_legacy_session ()
3110 {
3111         MeterSection* prev_m = 0;
3112         TempoSection* prev_t = 0;
3113
3114         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3115                 MeterSection* m;
3116                 TempoSection* t;
3117
3118                 if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3119                         if (!m->movable()) {
3120                                 pair<double, BBT_Time> bbt = make_pair (0.0, BBT_Time (1, 1, 0));
3121                                 m->set_beat (bbt);
3122                                 m->set_pulse (0.0);
3123                                 m->set_frame (0);
3124                                 m->set_position_lock_style (AudioTime);
3125                                 prev_m = m;
3126                                 continue;
3127                         }
3128                         if (prev_m) {
3129                                 pair<double, BBT_Time> start = make_pair (((m->bbt().bars - 1) * prev_m->note_divisor())
3130                                                                           + (m->bbt().beats - 1)
3131                                                                           + (m->bbt().ticks / BBT_Time::ticks_per_beat)
3132                                                                           , m->bbt());
3133                                 m->set_beat (start);
3134                                 const double start_beat = ((m->bbt().bars - 1) * prev_m->note_divisor())
3135                                         + (m->bbt().beats - 1)
3136                                         + (m->bbt().ticks / BBT_Time::ticks_per_beat);
3137                                 m->set_pulse (start_beat / prev_m->note_divisor());
3138                         }
3139                         prev_m = m;
3140                 } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3141
3142                         if (!t->active()) {
3143                                 continue;
3144                         }
3145
3146                         if (!t->movable()) {
3147                                 t->set_pulse (0.0);
3148                                 t->set_frame (0);
3149                                 t->set_position_lock_style (AudioTime);
3150                                 prev_t = t;
3151                                 continue;
3152                         }
3153
3154                         if (prev_t) {
3155                                 const double beat = ((t->legacy_bbt().bars - 1) * ((prev_m) ? prev_m->note_divisor() : 4.0))
3156                                         + (t->legacy_bbt().beats - 1)
3157                                         + (t->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
3158                                 if (prev_m) {
3159                                         t->set_pulse (beat / prev_m->note_divisor());
3160                                 } else {
3161                                         /* really shouldn't happen but.. */
3162                                         t->set_pulse (beat / 4.0);
3163                                 }
3164                         }
3165                         prev_t = t;
3166                 }
3167         }
3168 }
3169
3170 XMLNode&
3171 TempoMap::get_state ()
3172 {
3173         Metrics::const_iterator i;
3174         XMLNode *root = new XMLNode ("TempoMap");
3175
3176         {
3177                 Glib::Threads::RWLock::ReaderLock lm (lock);
3178                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3179                         root->add_child_nocopy ((*i)->get_state());
3180                 }
3181         }
3182
3183         return *root;
3184 }
3185
3186 int
3187 TempoMap::set_state (const XMLNode& node, int /*version*/)
3188 {
3189         {
3190                 Glib::Threads::RWLock::WriterLock lm (lock);
3191
3192                 XMLNodeList nlist;
3193                 XMLNodeConstIterator niter;
3194                 Metrics old_metrics (_metrics);
3195                 _metrics.clear();
3196
3197                 nlist = node.children();
3198
3199                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3200                         XMLNode* child = *niter;
3201
3202                         if (child->name() == TempoSection::xml_state_node_name) {
3203
3204                                 try {
3205                                         TempoSection* ts = new TempoSection (*child);
3206                                         _metrics.push_back (ts);
3207                                 }
3208
3209                                 catch (failed_constructor& err){
3210                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3211                                         _metrics = old_metrics;
3212                                         break;
3213                                 }
3214
3215                         } else if (child->name() == MeterSection::xml_state_node_name) {
3216
3217                                 try {
3218                                         MeterSection* ms = new MeterSection (*child);
3219                                         _metrics.push_back (ms);
3220                                 }
3221
3222                                 catch (failed_constructor& err) {
3223                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
3224                                         _metrics = old_metrics;
3225                                         break;
3226                                 }
3227                         }
3228                 }
3229
3230                 if (niter == nlist.end()) {
3231                         MetricSectionSorter cmp;
3232                         _metrics.sort (cmp);
3233                 }
3234
3235                 /* check for legacy sessions where bbt was the base musical unit for tempo */
3236                 for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3237                         TempoSection* t;
3238                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
3239                                 if (t->legacy_bbt().bars != 0) {
3240                                         fix_legacy_session();
3241                                         break;
3242                                 }
3243                                 break;
3244                         }
3245                 }
3246
3247                 /* check for multiple tempo/meters at the same location, which
3248                    ardour2 somehow allowed.
3249                 */
3250
3251                 Metrics::iterator prev = _metrics.end();
3252                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3253                         if (prev != _metrics.end()) {
3254                                 MeterSection* ms;
3255                                 MeterSection* prev_m;
3256                                 TempoSection* ts;
3257                                 TempoSection* prev_t;
3258                                 if ((prev_m = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
3259                                         if (prev_m->pulse() == ms->pulse()) {
3260                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3261                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_m->pulse()) << endmsg;
3262                                                 return -1;
3263                                         }
3264                                 } else if ((prev_t = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
3265                                         if (prev_t->pulse() == ts->pulse()) {
3266                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3267                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_t->pulse()) << endmsg;
3268                                                 return -1;
3269                                         }
3270                                 }
3271                         }
3272                         prev = i;
3273                 }
3274
3275                 recompute_map (_metrics);
3276         }
3277
3278         PropertyChanged (PropertyChange ());
3279
3280         return 0;
3281 }
3282
3283 void
3284 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
3285 {
3286         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
3287         const MeterSection* m;
3288         const TempoSection* t;
3289         const TempoSection* prev_t = 0;
3290
3291         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
3292
3293                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
3294                         o << "Tempo @ " << *i << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
3295                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
3296                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
3297                         if (prev_t) {
3298                                 o << "previous     : " << prev_t->beats_per_minute() << " | " << prev_t->pulse() << " | " << prev_t->frame() << std::endl;
3299                                 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;
3300                         }
3301                         prev_t = t;
3302                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
3303                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
3304                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
3305                 }
3306         }
3307         o << "------" << std::endl;
3308 }
3309
3310 int
3311 TempoMap::n_tempos() const
3312 {
3313         Glib::Threads::RWLock::ReaderLock lm (lock);
3314         int cnt = 0;
3315
3316         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3317                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
3318                         cnt++;
3319                 }
3320         }
3321
3322         return cnt;
3323 }
3324
3325 int
3326 TempoMap::n_meters() const
3327 {
3328         Glib::Threads::RWLock::ReaderLock lm (lock);
3329         int cnt = 0;
3330
3331         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3332                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
3333                         cnt++;
3334                 }
3335         }
3336
3337         return cnt;
3338 }
3339
3340 void
3341 TempoMap::insert_time (framepos_t where, framecnt_t amount)
3342 {
3343         {
3344                 Glib::Threads::RWLock::WriterLock lm (lock);
3345                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3346                         if ((*i)->frame() >= where && (*i)->movable ()) {
3347                                 (*i)->set_frame ((*i)->frame() + amount);
3348                         }
3349                 }
3350
3351                 /* now reset the BBT time of all metrics, based on their new
3352                  * audio time. This is the only place where we do this reverse
3353                  * timestamp.
3354                  */
3355
3356                 Metrics::iterator i;
3357                 const MeterSection* meter;
3358                 const TempoSection* tempo;
3359                 MeterSection *m;
3360                 TempoSection *t;
3361
3362                 meter = &first_meter ();
3363                 tempo = &first_tempo ();
3364
3365                 BBT_Time start;
3366                 BBT_Time end;
3367
3368                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
3369
3370                 bool first = true;
3371                 MetricSection* prev = 0;
3372
3373                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
3374
3375                         BBT_Time bbt;
3376                         //TempoMetric metric (*meter, *tempo);
3377                         MeterSection* ms = const_cast<MeterSection*>(meter);
3378                         TempoSection* ts = const_cast<TempoSection*>(tempo);
3379                         if (prev) {
3380                                 if (ts){
3381                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3382                                                 if (!t->active()) {
3383                                                         continue;
3384                                                 }
3385                                                 ts->set_pulse (t->pulse());
3386                                         }
3387                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3388                                                 ts->set_pulse (m->pulse());
3389                                         }
3390                                         ts->set_frame (prev->frame());
3391
3392                                 }
3393                                 if (ms) {
3394                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
3395                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
3396                                                 ms->set_beat (start);
3397                                                 ms->set_pulse (m->pulse());
3398                                         }
3399                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
3400                                                 if (!t->active()) {
3401                                                         continue;
3402                                                 }
3403                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
3404                                                 pair<double, BBT_Time> start = make_pair (beat, bbt_at_beat_locked (_metrics, beat));
3405                                                 ms->set_beat (start);
3406                                                 ms->set_pulse (t->pulse());
3407                                         }
3408                                         ms->set_frame (prev->frame());
3409                                 }
3410
3411                         } else {
3412                                 // metric will be at frames=0 bbt=1|1|0 by default
3413                                 // which is correct for our purpose
3414                         }
3415
3416                         // cerr << bbt << endl;
3417
3418                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
3419                                 if (!t->active()) {
3420                                         continue;
3421                                 }
3422                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3423                                 tempo = t;
3424                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3425                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
3426                                 bbt = bbt_at_frame_locked (_metrics, m->frame());
3427
3428                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
3429
3430                                 if (first) {
3431                                         first = false;
3432                                 } else {
3433
3434                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
3435                                                 /* round up to next beat */
3436                                                 bbt.beats += 1;
3437                                         }
3438
3439                                         bbt.ticks = 0;
3440
3441                                         if (bbt.beats != 1) {
3442                                                 /* round up to next bar */
3443                                                 bbt.bars += 1;
3444                                                 bbt.beats = 1;
3445                                         }
3446                                 }
3447                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
3448                                 m->set_beat (start);
3449                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
3450                                 meter = m;
3451                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
3452                         } else {
3453                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
3454                                 abort(); /*NOTREACHED*/
3455                         }
3456
3457                         prev = (*i);
3458                 }
3459
3460                 recompute_map (_metrics);
3461         }
3462
3463
3464         PropertyChanged (PropertyChange ());
3465 }
3466 bool
3467 TempoMap::remove_time (framepos_t where, framecnt_t amount)
3468 {
3469         bool moved = false;
3470
3471         std::list<MetricSection*> metric_kill_list;
3472
3473         TempoSection* last_tempo = NULL;
3474         MeterSection* last_meter = NULL;
3475         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
3476         bool meter_after = false; // is there a meter marker likewise?
3477         {
3478                 Glib::Threads::RWLock::WriterLock lm (lock);
3479                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
3480                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
3481                                 metric_kill_list.push_back(*i);
3482                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
3483                                 if (lt)
3484                                         last_tempo = lt;
3485                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
3486                                 if (lm)
3487                                         last_meter = lm;
3488                         }
3489                         else if ((*i)->frame() >= where) {
3490                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
3491                                 (*i)->set_frame ((*i)->frame() - amount);
3492                                 if ((*i)->frame() == where) {
3493                                         // marker was immediately after end of range
3494                                         tempo_after = dynamic_cast<TempoSection*> (*i);
3495                                         meter_after = dynamic_cast<MeterSection*> (*i);
3496                                 }
3497                                 moved = true;
3498                         }
3499                 }
3500
3501                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
3502                 if (last_tempo && !tempo_after) {
3503                         metric_kill_list.remove(last_tempo);
3504                         last_tempo->set_frame(where);
3505                         moved = true;
3506                 }
3507                 if (last_meter && !meter_after) {
3508                         metric_kill_list.remove(last_meter);
3509                         last_meter->set_frame(where);
3510                         moved = true;
3511                 }
3512
3513                 //remove all the remaining metrics
3514                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
3515                         _metrics.remove(*i);
3516                         moved = true;
3517                 }
3518
3519                 if (moved) {
3520                         recompute_map (_metrics);
3521                 }
3522         }
3523         PropertyChanged (PropertyChange ());
3524         return moved;
3525 }
3526
3527 /** Add some (fractional) beats to a session frame position, and return the result in frames.
3528  *  pos can be -ve, if required.
3529  */
3530 framepos_t
3531 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
3532 {
3533         Glib::Threads::RWLock::ReaderLock lm (lock);
3534
3535         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) + beats.to_double());
3536 }
3537
3538 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
3539 framepos_t
3540 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
3541 {
3542         Glib::Threads::RWLock::ReaderLock lm (lock);
3543
3544         return frame_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos) - beats.to_double());
3545 }
3546
3547 /** Add the BBT interval op to pos and return the result */
3548 framepos_t
3549 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
3550 {
3551         Glib::Threads::RWLock::ReaderLock lm (lock);
3552
3553         BBT_Time pos_bbt = bbt_at_beat_locked (_metrics, beat_at_frame_locked (_metrics, pos));
3554         pos_bbt.ticks += op.ticks;
3555         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
3556                 ++pos_bbt.beats;
3557                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
3558         }
3559         pos_bbt.beats += op.beats;
3560         /* the meter in effect will start on the bar */
3561         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();
3562         while (pos_bbt.beats >= divisions_per_bar + 1) {
3563                 ++pos_bbt.bars;
3564                 divisions_per_bar = meter_section_at_beat (beat_at_bbt_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
3565                 pos_bbt.beats -= divisions_per_bar;
3566         }
3567         pos_bbt.bars += op.bars;
3568
3569         return frame_at_bbt_locked (_metrics, pos_bbt);
3570 }
3571
3572 /** Count the number of beats that are equivalent to distance when going forward,
3573     starting at pos.
3574 */
3575 Evoral::Beats
3576 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
3577 {
3578         Glib::Threads::RWLock::ReaderLock lm (lock);
3579
3580         return Evoral::Beats (beat_at_frame_locked (_metrics, pos + distance) - beat_at_frame_locked (_metrics, pos));
3581 }
3582
3583 struct bbtcmp {
3584     bool operator() (const BBT_Time& a, const BBT_Time& b) {
3585             return a < b;
3586     }
3587 };
3588
3589 std::ostream&
3590 operator<< (std::ostream& o, const Meter& m) {
3591         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3592 }
3593
3594 std::ostream&
3595 operator<< (std::ostream& o, const Tempo& t) {
3596         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3597 }
3598
3599 std::ostream&
3600 operator<< (std::ostream& o, const MetricSection& section) {
3601
3602         o << "MetricSection @ " << section.frame() << ' ';
3603
3604         const TempoSection* ts;
3605         const MeterSection* ms;
3606
3607         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3608                 o << *((const Tempo*) ts);
3609         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3610                 o << *((const Meter*) ms);
3611         }
3612
3613         return o;
3614 }