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