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