Tempo ramps - pressing constraint modifier keys during tempo drag changes tempo with...
[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), Tempo (TempoMap::default_tempo())
77 {
78         const XMLProperty *prop;
79         LocaleGuard lg;
80         BBT_Time bbt;
81         double pulse;
82         uint32_t frame;
83
84         if ((prop = node.property ("start")) != 0) {
85                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
86                             &bbt.bars,
87                             &bbt.beats,
88                             &bbt.ticks) == 3) {
89                         /* legacy session - start used to be in bbt*/
90                         _legacy_bbt = bbt;
91                         pulse = -1.0;
92                         set_pulse (pulse);
93                 }
94         } else {
95                 warning << _("TempoSection XML node has no \"start\" property") << endmsg;
96         }
97
98
99         if ((prop = node.property ("pulse")) != 0) {
100                 if (sscanf (prop->value().c_str(), "%lf", &pulse) != 1 || pulse < 0.0) {
101                         error << _("TempoSection XML node has an illegal \"beat\" value") << endmsg;
102                 } else {
103                         set_pulse (pulse);
104                 }
105         }
106         if ((prop = node.property ("frame")) != 0) {
107                 if (sscanf (prop->value().c_str(), "%" PRIu32, &frame) != 1) {
108                         error << _("TempoSection XML node has an illegal \"frame\" value") << endmsg;
109                 } else {
110                         set_frame (frame);
111                 }
112         }
113
114         if ((prop = node.property ("beats-per-minute")) == 0) {
115                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
116                 throw failed_constructor();
117         }
118
119         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
120                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
121                 throw failed_constructor();
122         }
123
124         if ((prop = node.property ("note-type")) == 0) {
125                 /* older session, make note type be quarter by default */
126                 _note_type = 4.0;
127         } else {
128                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
129                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
130                         throw failed_constructor();
131                 }
132         }
133
134         if ((prop = node.property ("movable")) == 0) {
135                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
136                 throw failed_constructor();
137         }
138
139         set_movable (string_is_affirmative (prop->value()));
140
141         if ((prop = node.property ("bar-offset")) == 0) {
142                 _bar_offset = -1.0;
143         } else {
144                 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
145                         error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
146                         throw failed_constructor();
147                 }
148         }
149
150         if ((prop = node.property ("tempo-type")) == 0) {
151                 _type = Constant;
152         } else {
153                 _type = Type (string_2_enum (prop->value(), _type));
154         }
155
156         if ((prop = node.property ("lock-style")) == 0) {
157                 set_position_lock_style (MusicTime);
158         } else {
159                 set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
160         }
161 }
162
163 XMLNode&
164 TempoSection::get_state() const
165 {
166         XMLNode *root = new XMLNode (xml_state_node_name);
167         char buf[256];
168         LocaleGuard lg;
169
170         snprintf (buf, sizeof (buf), "%f", pulse());
171         root->add_property ("pulse", buf);
172         snprintf (buf, sizeof (buf), "%li", frame());
173         root->add_property ("frame", buf);
174         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
175         root->add_property ("beats-per-minute", buf);
176         snprintf (buf, sizeof (buf), "%f", _note_type);
177         root->add_property ("note-type", buf);
178         // snprintf (buf, sizeof (buf), "%f", _bar_offset);
179         // root->add_property ("bar-offset", buf);
180         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
181         root->add_property ("movable", buf);
182         root->add_property ("tempo-type", enum_2_string (_type));
183         root->add_property ("lock-style", enum_2_string (position_lock_style()));
184
185         return *root;
186 }
187
188 void
189
190 TempoSection::update_bar_offset_from_bbt (const Meter& m)
191 {
192         _bar_offset = (pulse() * BBT_Time::ticks_per_beat) /
193                 (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
194
195         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, pulse(), m.divisions_per_bar()));
196 }
197
198 void
199 TempoSection::set_type (Type type)
200 {
201         _type = type;
202 }
203
204 /** returns the tempo in whole pulses per minute at the zero-based (relative to session) frame.
205 */
206 double
207 TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
208 {
209
210         if (_type == Constant) {
211                 return pulses_per_minute();
212         }
213
214         return pulse_tempo_at_time (frame_to_minute (f - frame(), frame_rate));
215 }
216
217 /** returns the zero-based frame (relative to session)
218    where the tempo in whole pulses per minute occurs in this section.
219    beat b is only used for constant tempos.
220    note that the tempo map may have multiple such values.
221 */
222 framepos_t
223 TempoSection::frame_at_tempo (const double& ppm, const double& b, const framecnt_t& frame_rate) const
224 {
225         if (_type == Constant) {
226                 return ((b - pulse())  * frames_per_pulse (frame_rate))  + frame();
227         }
228
229         return minute_to_frame (time_at_pulse_tempo (ppm), frame_rate) + frame();
230 }
231 /** returns the tempo in pulses per minute at the zero-based (relative to session) beat.
232 */
233 double
234 TempoSection::tempo_at_pulse (const double& p) const
235 {
236
237         if (_type == Constant) {
238                 return pulses_per_minute();
239         }
240         double const ppm = pulse_tempo_at_pulse (p - pulse());
241         return ppm;
242 }
243
244 /** returns the zero-based beat (relative to session)
245    where the tempo in whole pulses per minute occurs given frame f. frame f is only used for constant tempos.
246    note that the session tempo map may have multiple beats at a given tempo.
247 */
248 double
249 TempoSection::pulse_at_tempo (const double& ppm, const framepos_t& f, const framecnt_t& frame_rate) const
250 {
251         if (_type == Constant) {
252                 double const beats = ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
253                 return  beats;
254         }
255
256         return pulse_at_pulse_tempo (ppm) + pulse();
257 }
258
259 /** returns the zero-based pulse (relative to session origin)
260    where the zero-based frame (relative to session)
261    lies.
262 */
263 double
264 TempoSection::pulse_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
265 {
266         if (_type == Constant) {
267                 return ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
268         }
269
270         return pulse_at_time (frame_to_minute (f - frame(), frame_rate)) + pulse();
271 }
272
273 /** returns the zero-based frame (relative to session start frame)
274    where the zero-based pulse (relative to session start)
275    falls.
276 */
277
278 framepos_t
279 TempoSection::frame_at_pulse (const double& p, const framecnt_t& frame_rate) const
280 {
281         if (_type == Constant) {
282                 return (framepos_t) floor ((p - pulse()) * frames_per_pulse (frame_rate)) + frame();
283         }
284
285         return minute_to_frame (time_at_pulse (p - pulse()), frame_rate) + frame();
286 }
287
288 /*
289 Ramp Overview
290
291       |                     *
292 Tempo |                   *
293 Tt----|-----------------*|
294 Ta----|--------------|*  |
295       |            * |   |
296       |         *    |   |
297       |     *        |   |
298 T0----|*             |   |
299   *   |              |   |
300       _______________|___|____
301       time           a   t (next tempo)
302       [        c         ] defines c
303
304 Duration in beats at time a is the integral of some Tempo function.
305 In our case, the Tempo function (Tempo at time t) is
306 T(t) = T0(e^(ct))
307
308 with function constant
309 c = log(Ta/T0)/a
310 so
311 a = log(Ta/T0)/c
312
313 The integral over t of our Tempo function (the beat function, which is the duration in beats at some time t) is:
314 b(t) = T0(e^(ct) - 1) / c
315
316 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:
317 t(b) = log((cb / T0) + 1) / c
318
319 The time t at which Tempo T occurs is a as above:
320 t(T) = log(T / T0) / c
321
322 The beat at which a Tempo T occurs is:
323 b(T) = (T - T0) / c
324
325 The Tempo at which beat b occurs is:
326 T(b) = b.c + T0
327
328 We define c for this tempo ramp by placing a new tempo section at some time t after this one.
329 Our problem is that we usually don't know t.
330 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.
331 Where a = t (i.e. when a is equal to the time of the next tempo section), the beat function reveals:
332 t = b log (Ta / T0) / (T0 (e^(log (Ta / T0)) - 1))
333
334 By substituting our expanded t as a in the c function above, our problem is reduced to:
335 c = T0 (e^(log (Ta / T0)) - 1) / b
336
337 We can now store c for future time calculations.
338 If the following tempo section (the one that defines c in conjunction with this one)
339 is changed or moved, c is no longer valid.
340
341 The public methods are session-relative.
342
343 Most of this stuff is taken from this paper:
344
345 WHERE’S THE BEAT?
346 TOOLS FOR DYNAMIC TEMPO CALCULATIONS
347 Jan C. Schacher
348 Martin Neukom
349 Zurich University of Arts
350 Institute for Computer Music and Sound Technology
351
352 https://www.zhdk.ch/fileadmin/data_subsites/data_icst/Downloads/Timegrid/ICST_Tempopolyphony_ICMC07.pdf
353
354 */
355
356 /*
357   compute this ramp's function constant using the end tempo (in whole pulses per minute)
358   and duration (pulses into global start) of some later tempo section.
359 */
360 double
361 TempoSection::compute_c_func_pulse (const double& end_bpm, const double& end_pulse, const framecnt_t& frame_rate)
362 {
363         double const log_tempo_ratio = log (end_bpm / pulses_per_minute());
364         return pulses_per_minute() *  (exp (log_tempo_ratio) - 1) / (end_pulse - pulse());
365 }
366
367 /* compute the function constant from some later tempo section, given tempo (whole pulses/min.) and distance (in frames) from session origin */
368 double
369 TempoSection::compute_c_func_frame (const double& end_bpm, const framepos_t& end_frame, const framecnt_t& frame_rate) const
370 {
371         return c_func (end_bpm, frame_to_minute (end_frame - frame(), frame_rate));
372 }
373
374 framecnt_t
375 TempoSection::minute_to_frame (const double& time, const framecnt_t& frame_rate) const
376 {
377         return (framecnt_t) floor ((time * 60.0 * frame_rate) + 0.5);
378 }
379
380 double
381 TempoSection::frame_to_minute (const framecnt_t& frame, const framecnt_t& frame_rate) const
382 {
383         return (frame / (double) frame_rate) / 60.0;
384 }
385
386 /* position function */
387 double
388 TempoSection::a_func (double end_bpm, double c_func) const
389 {
390         return log (end_bpm / pulses_per_minute()) /  c_func;
391 }
392
393 /*function constant*/
394 double
395 TempoSection::c_func (double end_bpm, double end_time) const
396 {
397         return log (end_bpm / pulses_per_minute()) /  end_time;
398 }
399
400 /* tempo in ppm at time in minutes */
401 double
402 TempoSection::pulse_tempo_at_time (const double& time) const
403 {
404         return exp (_c_func * time) * pulses_per_minute();
405 }
406
407 /* time in minutes at tempo in ppm */
408 double
409 TempoSection::time_at_pulse_tempo (const double& pulse_tempo) const
410 {
411         return log (pulse_tempo / pulses_per_minute()) / _c_func;
412 }
413
414 /* tick at tempo in ppm */
415 double
416 TempoSection::pulse_at_pulse_tempo (const double& pulse_tempo) const
417 {
418         return (pulse_tempo - pulses_per_minute()) / _c_func;
419 }
420
421 /* tempo in ppm at tick */
422 double
423 TempoSection::pulse_tempo_at_pulse (const double& pulse) const
424 {
425         return (pulse * _c_func) + pulses_per_minute();
426 }
427
428 /* pulse at time in minutes */
429 double
430 TempoSection::pulse_at_time (const double& time) const
431 {
432         return ((exp (_c_func * time)) - 1) * (pulses_per_minute() / _c_func);
433 }
434
435 /* time in minutes at pulse */
436 double
437 TempoSection::time_at_pulse (const double& pulse) const
438 {
439         return log (((_c_func * pulse) / pulses_per_minute()) + 1) / _c_func;
440 }
441
442
443 void
444 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
445 {
446         double new_beat;
447
448         if (_bar_offset < 0.0) {
449                 /* not set yet */
450                 return;
451         }
452
453         new_beat = pulse();
454
455         double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
456         new_beat = ticks / BBT_Time::ticks_per_beat;
457
458         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
459                                                        _bar_offset, meter.divisions_per_bar(), ticks, new_beat, new_beat));
460
461         set_pulse (new_beat);
462 }
463
464 /***********************************************************************/
465
466 const string MeterSection::xml_state_node_name = "Meter";
467
468 MeterSection::MeterSection (const XMLNode& node)
469         : MetricSection (0.0), Meter (TempoMap::default_meter())
470 {
471         XMLProperty const * prop;
472         BBT_Time start;
473         LocaleGuard lg;
474         const XMLProperty *prop;
475         BBT_Time bbt;
476         double pulse = 0.0;
477         double beat = 0.0;
478         framepos_t frame = 0;
479         pair<double, BBT_Time> start;
480
481         if ((prop = node.property ("start")) != 0) {
482                 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
483                     &bbt.bars,
484                     &bbt.beats,
485                     &bbt.ticks) < 3) {
486                         error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
487                 } else {
488                         /* legacy session - start used to be in bbt*/
489                         pulse = -1.0;
490                 }
491         } else {
492                 error << _("MeterSection XML node has no \"start\" property") << endmsg;
493         }
494
495         if ((prop = node.property ("pulse")) != 0) {
496                 if (sscanf (prop->value().c_str(), "%lf", &pulse) != 1 || pulse < 0.0) {
497                         error << _("MeterSection XML node has an illegal \"pulse\" value") << endmsg;
498                 }
499         }
500         set_pulse (pulse);
501
502         if ((prop = node.property ("beat")) != 0) {
503                 if (sscanf (prop->value().c_str(), "%lf", &beat) != 1) {
504                         error << _("MeterSection XML node has an illegal \"beat\" vlue") << endmsg;
505                 }
506         }
507
508         start.first = beat;
509
510         if ((prop = node.property ("bbt")) == 0) {
511                 error << _("MeterSection XML node has no \"bbt\" property") << endmsg;
512         } else if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
513                     &bbt.bars,
514                     &bbt.beats,
515                     &bbt.ticks) < 3) {
516                 error << _("MeterSection XML node has an illegal \"bbt\" value") << endmsg;
517                 //throw failed_constructor();
518         }
519
520         start.second = bbt;
521         set_beat (start);
522
523         if ((prop = node.property ("frame")) != 0) {
524                 if (sscanf (prop->value().c_str(), "%li", &frame) != 1) {
525                         error << _("MeterSection XML node has an illegal \"frame\" value") << endmsg;
526                 } else {
527                         set_frame (frame);
528                 }
529         }
530
531         /* beats-per-bar is old; divisions-per-bar is new */
532
533         if ((prop = node.property ("divisions-per-bar")) == 0) {
534                 if ((prop = node.property ("beats-per-bar")) == 0) {
535                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
536                         throw failed_constructor();
537                 }
538         }
539         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
540                 error << _("MeterSection XML node has an illegal \"divisions-per-bar\" value") << endmsg;
541                 throw failed_constructor();
542         }
543
544         if ((prop = node.property ("note-type")) == 0) {
545                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
546                 throw failed_constructor();
547         }
548         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
549                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
550                 throw failed_constructor();
551         }
552
553         if ((prop = node.property ("lock-style")) == 0) {
554                 warning << _("MeterSection XML node has no \"lock-style\" property") << endmsg;
555                 set_position_lock_style (MusicTime);
556         } else {
557                 set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
558         }
559
560         if ((prop = node.property ("movable")) == 0) {
561                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
562                 throw failed_constructor();
563         }
564
565         set_movable (string_is_affirmative (prop->value()));
566 }
567
568 XMLNode&
569 MeterSection::get_state() const
570 {
571         XMLNode *root = new XMLNode (xml_state_node_name);
572         char buf[256];
573         LocaleGuard lg;
574
575         snprintf (buf, sizeof (buf), "%lf", pulse());
576         root->add_property ("pulse", buf);
577         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
578                   bbt().bars,
579                   bbt().beats,
580                   bbt().ticks);
581         root->add_property ("bbt", buf);
582         snprintf (buf, sizeof (buf), "%lf", beat());
583         root->add_property ("beat", buf);
584         snprintf (buf, sizeof (buf), "%f", _note_type);
585         root->add_property ("note-type", buf);
586         snprintf (buf, sizeof (buf), "%li", frame());
587         root->add_property ("frame", buf);
588         root->add_property ("lock-style", enum_2_string (position_lock_style()));
589         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
590         root->add_property ("divisions-per-bar", buf);
591         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
592         root->add_property ("movable", buf);
593
594         return *root;
595 }
596
597 /***********************************************************************/
598
599 struct MetricSectionSorter {
600     bool operator() (const MetricSection* a, const MetricSection* b) {
601             return a->pulse() < b->pulse();
602     }
603 };
604
605 struct MetricSectionFrameSorter {
606     bool operator() (const MetricSection* a, const MetricSection* b) {
607             return a->frame() < b->frame();
608     }
609 };
610
611 TempoMap::TempoMap (framecnt_t fr)
612 {
613         _frame_rate = fr;
614         BBT_Time start (1, 1, 0);
615
616         TempoSection *t = new TempoSection (0.0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Constant);
617         MeterSection *m = new MeterSection (0.0, 0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
618
619         t->set_movable (false);
620         m->set_movable (false);
621
622         /* note: frame time is correct (zero) for both of these */
623
624         _metrics.push_back (t);
625         _metrics.push_back (m);
626
627 }
628
629 TempoMap::~TempoMap ()
630 {
631 }
632
633 void
634 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
635 {
636         bool removed = false;
637
638         {
639                 Glib::Threads::RWLock::WriterLock lm (lock);
640                 if ((removed = remove_tempo_locked (tempo))) {
641                         if (complete_operation) {
642                                 recompute_map (_metrics);
643                         }
644                 }
645         }
646
647         if (removed && complete_operation) {
648                 PropertyChanged (PropertyChange ());
649         }
650 }
651
652 bool
653 TempoMap::remove_tempo_locked (const TempoSection& tempo)
654 {
655         Metrics::iterator i;
656
657         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
658                 if (dynamic_cast<TempoSection*> (*i) != 0) {
659                         if (tempo.frame() == (*i)->frame()) {
660                                 if ((*i)->movable()) {
661                                         _metrics.erase (i);
662                                         return true;
663                                 }
664                         }
665                 }
666         }
667
668         return false;
669 }
670
671 void
672 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
673 {
674         bool removed = false;
675
676         {
677                 Glib::Threads::RWLock::WriterLock lm (lock);
678                 if ((removed = remove_meter_locked (tempo))) {
679                         if (complete_operation) {
680                                 recompute_map (_metrics);
681                         }
682                 }
683         }
684
685         if (removed && complete_operation) {
686                 PropertyChanged (PropertyChange ());
687         }
688 }
689
690 bool
691 TempoMap::remove_meter_locked (const MeterSection& tempo)
692 {
693         Metrics::iterator i;
694
695         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
696                 if (dynamic_cast<MeterSection*> (*i) != 0) {
697                         if (tempo.frame() == (*i)->frame()) {
698                                 if ((*i)->movable()) {
699                                         _metrics.erase (i);
700                                         return true;
701                                 }
702                         }
703                 }
704         }
705
706         return false;
707 }
708
709 void
710 TempoMap::do_insert (MetricSection* section)
711 {
712         bool need_add = true;
713         /* we only allow new meters to be inserted on beat 1 of an existing
714          * measure.
715          */
716         MeterSection* m = 0;
717         if ((m = dynamic_cast<MeterSection*>(section)) != 0) {
718                 //assert (m->bbt().ticks == 0);
719
720                 if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) {
721
722                         pair<double, BBT_Time> corrected = make_pair (m->pulse(), m->bbt());
723                         corrected.second.beats = 1;
724                         corrected.second.ticks = 0;
725                         corrected.first = bbt_to_beats_locked (_metrics, corrected.second);
726                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
727                                                    m->bbt(), corrected.second) << endmsg;
728                         //m->set_pulse (corrected);
729                 }
730         }
731
732         /* Look for any existing MetricSection that is of the same type and
733            in the same bar as the new one, and remove it before adding
734            the new one. Note that this means that if we find a matching,
735            existing section, we can break out of the loop since we're
736            guaranteed that there is only one such match.
737         */
738
739         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
740
741                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
742                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
743                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
744                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
745
746                 if (tempo && insert_tempo) {
747
748                         /* Tempo sections */
749                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
750                         if ((ipm && tempo->pulse() == insert_tempo->pulse()) || (!ipm && tempo->frame() == insert_tempo->frame())) {
751
752                                 if (!tempo->movable()) {
753
754                                         /* can't (re)move this section, so overwrite
755                                          * its data content (but not its properties as
756                                          * a section).
757                                          */
758
759                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo));
760                                         need_add = false;
761                                 } else {
762                                         _metrics.erase (i);
763                                 }
764                                 break;
765                         }
766
767                 } else if (meter && insert_meter) {
768
769                         /* Meter Sections */
770
771                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
772
773                         if ((ipm && meter->pulse() == insert_meter->pulse()) || (!ipm && meter->frame() == insert_meter->frame())) {
774
775                                 if (!meter->movable()) {
776
777                                         /* can't (re)move this section, so overwrite
778                                          * its data content (but not its properties as
779                                          * a section
780                                          */
781
782                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter));
783                                         (*i)->set_position_lock_style (insert_meter->position_lock_style());
784                                         need_add = false;
785                                 } else {
786                                         _metrics.erase (i);
787
788                                 }
789
790                                 break;
791                         }
792                 } else {
793                         /* non-matching types, so we don't care */
794                 }
795         }
796
797         /* Add the given MetricSection, if we didn't just reset an existing
798          * one above
799          */
800
801         if (need_add) {
802                 MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section);
803                 TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section);
804                 Metrics::iterator i;
805                 if (insert_meter) {
806                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
807                                 MeterSection* const meter = dynamic_cast<MeterSection*> (*i);
808
809                                 if (meter) {
810                                         bool const ipm = insert_meter->position_lock_style() == MusicTime;
811                                         if ((ipm && meter->pulse() > insert_meter->pulse()) || (!ipm && meter->frame() > insert_meter->frame())) {
812                                                 break;
813                                         }
814                                 }
815                         }
816                 } else if (insert_tempo) {
817                         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
818                                 TempoSection* const tempo = dynamic_cast<TempoSection*> (*i);
819
820                                 if (tempo) {
821                                         bool const ipm = insert_tempo->position_lock_style() == MusicTime;
822                                         if ((ipm && tempo->pulse() > insert_tempo->pulse()) || (!ipm && tempo->frame() > insert_tempo->frame())) {
823                                                 break;
824                                         }
825                                 }
826                         }
827                 }
828
829                 _metrics.insert (i, section);
830                 //dump (_metrics, std::cerr);
831         }
832 }
833
834 void
835 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& pulse, TempoSection::Type type)
836 {
837         {
838                 Glib::Threads::RWLock::WriterLock lm (lock);
839                 TempoSection& first (first_tempo());
840                 if (ts.pulse() != first.pulse()) {
841                         remove_tempo_locked (ts);
842                         add_tempo_locked (tempo, pulse, true, type);
843                 } else {
844                         first.set_type (type);
845                         {
846                                 /* cannot move the first tempo section */
847                                 *static_cast<Tempo*>(&first) = tempo;
848                                 recompute_map (_metrics);
849                         }
850                 }
851         }
852
853         PropertyChanged (PropertyChange ());
854 }
855
856 void
857 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const framepos_t& frame, TempoSection::Type type)
858 {
859         {
860                 Glib::Threads::RWLock::WriterLock lm (lock);
861                 TempoSection& first (first_tempo());
862                 if (ts.frame() != first.frame()) {
863                         remove_tempo_locked (ts);
864                         add_tempo_locked (tempo, frame, true, type);
865                 } else {
866                         first.set_type (type);
867                         {
868                                 /* cannot move the first tempo section */
869                                 *static_cast<Tempo*>(&first) = tempo;
870                                 recompute_map (_metrics);
871                         }
872                 }
873         }
874         PropertyChanged (PropertyChange ());
875 }
876
877 void
878 TempoMap::add_tempo (const Tempo& tempo, const double& pulse, ARDOUR::TempoSection::Type type)
879 {
880         {
881                 Glib::Threads::RWLock::WriterLock lm (lock);
882                 add_tempo_locked (tempo, pulse, true, type);
883         }
884
885         PropertyChanged (PropertyChange ());
886 }
887
888 void
889 TempoMap::add_tempo (const Tempo& tempo, const framepos_t& frame, ARDOUR::TempoSection::Type type)
890 {
891         {
892                 Glib::Threads::RWLock::WriterLock lm (lock);
893                 add_tempo_locked (tempo, frame, true, type);
894         }
895
896
897         PropertyChanged (PropertyChange ());
898 }
899
900 void
901 TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, bool recompute, ARDOUR::TempoSection::Type type)
902 {
903         TempoSection* ts = new TempoSection (pulse, tempo.beats_per_minute(), tempo.note_type(), type);
904
905         do_insert (ts);
906
907         if (recompute) {
908                 solve_map (_metrics, ts, Tempo (ts->beats_per_minute(), ts->note_type()), ts->pulse());
909         }
910 }
911
912 void
913 TempoMap::add_tempo_locked (const Tempo& tempo, framepos_t frame, bool recompute, ARDOUR::TempoSection::Type type)
914 {
915         TempoSection* ts = new TempoSection (frame, tempo.beats_per_minute(), tempo.note_type(), type);
916
917         do_insert (ts);
918
919         if (recompute) {
920                 solve_map (_metrics, ts, Tempo (ts->beats_per_minute(), ts->note_type()), ts->frame());
921         }
922 }
923
924 void
925 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
926 {
927         {
928                 Glib::Threads::RWLock::WriterLock lm (lock);
929                 MeterSection& first (first_meter());
930                 const PositionLockStyle pl = ms.position_lock_style();
931                 if (ms.pulse() != first.pulse()) {
932                         remove_meter_locked (ms);
933                         add_meter_locked (meter, bbt_to_beats_locked (_metrics, where), where, true);
934                 } else {
935                         /* cannot move the first meter section */
936                         *static_cast<Meter*>(&first) = meter;
937                         first.set_position_lock_style (pl);
938                         recompute_map (_metrics);
939                 }
940         }
941
942         PropertyChanged (PropertyChange ());
943 }
944
945 void
946 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const framepos_t& frame)
947 {
948         {
949                 Glib::Threads::RWLock::WriterLock lm (lock);
950                 MeterSection& first (first_meter());
951                 const PositionLockStyle pl = ms.position_lock_style();
952                 if (ms.pulse() != first.pulse()) {
953                         remove_meter_locked (ms);
954                         add_meter_locked (meter, frame, true);
955                 } else {
956                         /* cannot move the first meter section */
957                         *static_cast<Meter*>(&first) = meter;
958                         first.set_position_lock_style (pl);
959                         first.set_frame (frame);
960                         recompute_map (_metrics);
961                 }
962         }
963
964         PropertyChanged (PropertyChange ());
965 }
966
967
968 void
969 TempoMap::add_meter (const Meter& meter, const double& beat, const BBT_Time& where)
970 {
971         {
972                 Glib::Threads::RWLock::WriterLock lm (lock);
973                 add_meter_locked (meter, beat, where, true);
974         }
975
976
977 #ifndef NDEBUG
978         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
979                 dump (_metrics, std::cerr);
980         }
981 #endif
982
983         PropertyChanged (PropertyChange ());
984 }
985
986 void
987 TempoMap::add_meter (const Meter& meter, const framepos_t& frame)
988 {
989         {
990                 Glib::Threads::RWLock::WriterLock lm (lock);
991                 add_meter_locked (meter, frame, true);
992         }
993
994
995 #ifndef NDEBUG
996         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
997                 dump (_metrics, std::cerr);
998         }
999 #endif
1000
1001         PropertyChanged (PropertyChange ());
1002 }
1003
1004 void
1005 TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, bool recompute)
1006 {
1007         /* a new meter always starts a new bar on the first beat. so
1008            round the start time appropriately. remember that
1009            `where' is based on the existing tempo map, not
1010            the result after we insert the new meter.
1011
1012         */
1013
1014         if (where.beats != 1) {
1015                 where.beats = 1;
1016                 where.bars++;
1017         }
1018         /* new meters *always* start on a beat. */
1019         where.ticks = 0;
1020         double pulse = pulse_at_beat_locked (_metrics, beat);
1021
1022         MeterSection* new_meter = new MeterSection (pulse, beat, where, meter.divisions_per_bar(), meter.note_divisor());
1023         do_insert (new_meter);
1024
1025         if (recompute) {
1026                 solve_map (_metrics, new_meter, Meter (meter.divisions_per_bar(), meter.note_divisor()), pulse);
1027         }
1028
1029 }
1030
1031 void
1032 TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, bool recompute)
1033 {
1034
1035         MeterSection* new_meter = new MeterSection (frame, 0.0, meter.divisions_per_bar(), meter.note_divisor());
1036
1037         do_insert (new_meter);
1038
1039         if (recompute) {
1040                 solve_map (_metrics, new_meter, Meter (new_meter->divisions_per_bar(), new_meter->note_divisor()), frame);
1041         }
1042
1043 }
1044
1045 /**
1046 * This is for a gui that needs to know the frame of a tempo section if it were to be moved to some bbt time,
1047 * taking any possible reordering as a consequence of this into account.
1048 * @param section - the section to be altered
1049 * @param bpm - the new Tempo
1050 * @param bbt - the bbt where the altered tempo will fall
1051 * @return returns - the position in frames where the new tempo section will lie.
1052 */
1053 framepos_t
1054 TempoMap::predict_tempo_frame (TempoSection* section, const Tempo& bpm, const BBT_Time& bbt)
1055 {
1056         Glib::Threads::RWLock::ReaderLock lm (lock);
1057         Metrics future_map;
1058         framepos_t ret = 0;
1059         TempoSection* new_section = copy_metrics_and_point (future_map, section);
1060
1061         double const beat = bbt_to_beats_locked (future_map, bbt);
1062         if (solve_map (future_map, new_section, bpm, pulse_at_beat_locked (future_map, beat))) {
1063                 ret = new_section->frame();
1064         } else {
1065                 ret = frame_at_beat_locked (_metrics, beat);
1066         }
1067
1068         Metrics::const_iterator d = future_map.begin();
1069         while (d != future_map.end()) {
1070                 delete (*d);
1071                 ++d;
1072         }
1073         return ret;
1074 }
1075
1076 double
1077 TempoMap::predict_tempo_pulse (TempoSection* section, const Tempo& bpm, const framepos_t& frame)
1078 {
1079         Glib::Threads::RWLock::ReaderLock lm (lock);
1080         Metrics future_map;
1081         double ret = 0.0;
1082         TempoSection* new_section = copy_metrics_and_point (future_map, section);
1083
1084         if (solve_map (future_map, new_section, bpm, frame)) {
1085                 ret = new_section->pulse();
1086         } else {
1087                 ret = pulse_at_frame_locked (_metrics, frame);
1088         }
1089
1090         Metrics::const_iterator d = future_map.begin();
1091         while (d != future_map.end()) {
1092                 delete (*d);
1093                 ++d;
1094         }
1095         return ret;
1096 }
1097
1098 void
1099 TempoMap::gui_move_tempo_frame (TempoSection* ts,  const Tempo& bpm, const framepos_t& frame)
1100 {
1101         Metrics future_map;
1102         {
1103                 Glib::Threads::RWLock::WriterLock lm (lock);
1104                 TempoSection* new_section = copy_metrics_and_point (future_map, ts);
1105                 if (solve_map (future_map, new_section, bpm, frame)) {
1106                         solve_map (_metrics, ts, bpm, frame);
1107                 }
1108         }
1109
1110         Metrics::const_iterator d = future_map.begin();
1111         while (d != future_map.end()) {
1112                 delete (*d);
1113                 ++d;
1114         }
1115
1116         MetricPositionChanged (); // Emit Signal
1117 }
1118
1119 void
1120 TempoMap::gui_move_tempo_beat (TempoSection* ts,  const Tempo& bpm, const double& beat)
1121 {
1122         Metrics future_map;
1123         {
1124                 Glib::Threads::RWLock::WriterLock lm (lock);
1125                 TempoSection* new_section = copy_metrics_and_point (future_map, ts);
1126                 if (solve_map (future_map, new_section, bpm, pulse_at_beat_locked (future_map, beat))) {
1127                         solve_map (_metrics, ts, bpm, beat);
1128                 }
1129         }
1130
1131         Metrics::const_iterator d = future_map.begin();
1132         while (d != future_map.end()) {
1133                 delete (*d);
1134                 ++d;
1135         }
1136
1137         MetricPositionChanged (); // Emit Signal
1138 }
1139
1140 void
1141 TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const framepos_t&  frame)
1142 {
1143         {
1144                 Glib::Threads::RWLock::WriterLock lm (lock);
1145                 solve_map (_metrics, ms, mt, frame);
1146         }
1147
1148         MetricPositionChanged (); // Emit Signal
1149 }
1150
1151 void
1152 TempoMap::gui_move_meter (MeterSection* ms, const Meter& mt, const double&  beat)
1153 {
1154         {
1155                 Glib::Threads::RWLock::WriterLock lm (lock);
1156                 solve_map (_metrics, ms, mt, pulse_at_beat_locked (_metrics, beat));
1157         }
1158
1159         MetricPositionChanged (); // Emit Signal
1160 }
1161
1162 bool
1163 TempoMap::gui_change_tempo (TempoSection* ts,  const Tempo& bpm)
1164 {
1165         Metrics future_map;
1166         bool can_solve = false;
1167         {
1168                 Glib::Threads::RWLock::WriterLock lm (lock);
1169                 TempoSection* new_section = copy_metrics_and_point (future_map, ts);
1170                 new_section->set_beats_per_minute (bpm.beats_per_minute());
1171                 recompute_tempos (future_map);
1172
1173                 if (check_solved (future_map, true)) {
1174                         ts->set_beats_per_minute (bpm.beats_per_minute());
1175                         recompute_map (_metrics);
1176                         can_solve = true;
1177                 }
1178         }
1179
1180         Metrics::const_iterator d = future_map.begin();
1181         while (d != future_map.end()) {
1182                 delete (*d);
1183                 ++d;
1184         }
1185         if (can_solve) {
1186                 MetricPositionChanged (); // Emit Signal
1187         }
1188         return can_solve;
1189 }
1190 TempoSection*
1191 TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
1192 {
1193         TempoSection* t;
1194         TempoSection* ret = 0;
1195         MeterSection* m;
1196
1197         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1198                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1199                         if (t == section) {
1200                                 if (t->position_lock_style() == MusicTime) {
1201                                         ret = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
1202                                 } else {
1203                                         ret = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
1204                                 }
1205                                 copy.push_back (ret);
1206                                 continue;
1207                         }
1208                         if (t->position_lock_style() == MusicTime) {
1209                                 copy.push_back (new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type()));
1210                         } else {
1211                                 copy.push_back (new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type()));
1212                         }
1213                 }
1214                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1215                         if (m->position_lock_style() == MusicTime) {
1216                                 copy.push_back (new MeterSection (m->pulse(), m->beat(), m->bbt(), m->divisions_per_bar(), m->note_divisor()));
1217                         } else {
1218                                 copy.push_back (new MeterSection (m->frame(), m->beat(), m->divisions_per_bar(), m->note_divisor()));
1219                         }
1220                 }
1221         }
1222         recompute_map (copy);
1223         return ret;
1224 }
1225
1226 bool
1227 TempoMap::can_solve_bbt (TempoSection* ts,  const Tempo& bpm, const BBT_Time& bbt)
1228 {
1229         Metrics copy;
1230         TempoSection* new_section = 0;
1231
1232         {
1233                 Glib::Threads::RWLock::ReaderLock lm (lock);
1234                 new_section = copy_metrics_and_point (copy, ts);
1235         }
1236
1237         double const beat = bbt_to_beats_locked (copy, bbt);
1238         bool ret = solve_map (copy, new_section, bpm, pulse_at_beat_locked (copy, beat));
1239
1240         Metrics::const_iterator d = copy.begin();
1241         while (d != copy.end()) {
1242                 delete (*d);
1243                 ++d;
1244         }
1245
1246         return ret;
1247 }
1248
1249 void
1250 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
1251 {
1252         Tempo newtempo (beats_per_minute, note_type);
1253         TempoSection* t;
1254
1255         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1256                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1257                         {
1258                                 Glib::Threads::RWLock::WriterLock lm (lock);
1259                                 *((Tempo*) t) = newtempo;
1260                                 recompute_map (_metrics);
1261                         }
1262                         PropertyChanged (PropertyChange ());
1263                         break;
1264                 }
1265         }
1266 }
1267
1268 void
1269 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
1270 {
1271         Tempo newtempo (beats_per_minute, note_type);
1272
1273         TempoSection* prev;
1274         TempoSection* first;
1275         Metrics::iterator i;
1276
1277         /* find the TempoSection immediately preceding "where"
1278          */
1279
1280         for (first = 0, i = _metrics.begin(), prev = 0; i != _metrics.end(); ++i) {
1281
1282                 if ((*i)->frame() > where) {
1283                         break;
1284                 }
1285
1286                 TempoSection* t;
1287
1288                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
1289                         if (!first) {
1290                                 first = t;
1291                         }
1292                         prev = t;
1293                 }
1294         }
1295
1296         if (!prev) {
1297                 if (!first) {
1298                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
1299                         return;
1300                 }
1301
1302                 prev = first;
1303         }
1304
1305         /* reset */
1306
1307         {
1308                 Glib::Threads::RWLock::WriterLock lm (lock);
1309                 /* cannot move the first tempo section */
1310                 *((Tempo*)prev) = newtempo;
1311                 recompute_map (_metrics);
1312         }
1313
1314         PropertyChanged (PropertyChange ());
1315 }
1316
1317 const MeterSection&
1318 TempoMap::first_meter () const
1319 {
1320         const MeterSection *m = 0;
1321
1322         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1323                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
1324                         return *m;
1325                 }
1326         }
1327
1328         fatal << _("programming error: no meter section in tempo map!") << endmsg;
1329         abort(); /*NOTREACHED*/
1330         return *m;
1331 }
1332
1333 MeterSection&
1334 TempoMap::first_meter ()
1335 {
1336         MeterSection *m = 0;
1337
1338         /* CALLER MUST HOLD LOCK */
1339
1340         for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1341                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
1342                         return *m;
1343                 }
1344         }
1345
1346         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1347         abort(); /*NOTREACHED*/
1348         return *m;
1349 }
1350
1351 const TempoSection&
1352 TempoMap::first_tempo () const
1353 {
1354         const TempoSection *t = 0;
1355
1356         /* CALLER MUST HOLD LOCK */
1357
1358         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1359                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
1360                         return *t;
1361                 }
1362         }
1363
1364         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1365         abort(); /*NOTREACHED*/
1366         return *t;
1367 }
1368
1369 TempoSection&
1370 TempoMap::first_tempo ()
1371 {
1372         TempoSection *t = 0;
1373
1374         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1375                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1376                         return *t;
1377                 }
1378         }
1379
1380         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1381         abort(); /*NOTREACHED*/
1382         return *t;
1383 }
1384 void
1385 TempoMap::recompute_tempos (Metrics& metrics)
1386 {
1387         TempoSection* prev_ts = 0;
1388
1389         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1390                 TempoSection* t;
1391
1392                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1393                         if (prev_ts) {
1394                                 if (t->position_lock_style() == AudioTime) {
1395                                         prev_ts->set_c_func (prev_ts->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1396                                         t->set_pulse (prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate));
1397
1398                                 } else {
1399                                         prev_ts->set_c_func (prev_ts->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1400                                         t->set_frame (prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate));
1401
1402                                 }
1403                         }
1404                         prev_ts = t;
1405                 }
1406         }
1407 }
1408
1409 /* tempos must be positioned correctly */
1410 void
1411 TempoMap::recompute_meters (Metrics& metrics)
1412 {
1413         MeterSection* meter = 0;
1414         MeterSection* prev_m = 0;
1415         double accumulated_beats = 0.0;
1416         uint32_t accumulated_bars = 0;
1417         for (Metrics::const_iterator mi = metrics.begin(); mi != metrics.end(); ++mi) {
1418                 if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
1419                         if (prev_m) {
1420                                 const double beats_in_m = (meter->pulse() - prev_m->pulse()) * prev_m->note_divisor();
1421                                 accumulated_beats += beats_in_m;
1422                                 accumulated_bars += (beats_in_m + 1) / prev_m->divisions_per_bar();
1423                         }
1424
1425                         if (meter->position_lock_style() == AudioTime) {
1426                                 pair<double, BBT_Time> bt = make_pair (accumulated_beats, BBT_Time (accumulated_bars + 1, 1, 0));
1427                                 meter->set_beat (bt);
1428                                 if (prev_m) {
1429                                         const double pulse = prev_m->pulse() + (meter->beat() - prev_m->beat()) / prev_m->note_divisor();
1430                                         meter->set_pulse (pulse);
1431                                 } else {
1432                                         const double pulse = pulse_at_frame_locked (metrics, meter->frame());
1433                                         meter->set_pulse (pulse);
1434                                 }
1435                         } else {
1436                                 if (prev_m) {
1437                                         const double pulse = prev_m->pulse() + (meter->beat() - prev_m->beat()) / prev_m->note_divisor();
1438                                         meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1439                                         meter->set_pulse (pulse);
1440                                 } else {
1441                                         const double pulse = pulse_at_beat_locked (metrics, meter->beat());
1442                                         meter->set_frame (frame_at_pulse_locked (metrics, pulse));
1443                                         meter->set_pulse (pulse);
1444                                 }
1445                         }
1446
1447                         prev_m = meter;
1448                 }
1449         }
1450 }
1451
1452 void
1453 TempoMap::recompute_map (Metrics& metrics, framepos_t end)
1454 {
1455         /* CALLER MUST HOLD WRITE LOCK */
1456
1457         if (end < 0) {
1458
1459                 /* we will actually stop once we hit
1460                    the last metric.
1461                 */
1462                 end = max_framepos;
1463
1464         }
1465
1466         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1467
1468         if (end == 0) {
1469                 /* silly call from Session::process() during startup
1470                  */
1471                 return;
1472         }
1473
1474         recompute_tempos (metrics);
1475         recompute_meters (metrics);
1476 }
1477
1478 double
1479 TempoMap::pulse_at_beat (const double& beat) const
1480 {
1481         Glib::Threads::RWLock::ReaderLock lm (lock);
1482         return pulse_at_beat_locked (_metrics, beat);
1483 }
1484
1485 double
1486 TempoMap::pulse_at_beat_locked (const Metrics& metrics, const double& beat) const
1487 {
1488         MeterSection* prev_ms = 0;
1489         double accumulated_beats = 0.0;
1490
1491         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1492                 MeterSection* m;
1493                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1494                         if (prev_ms && m->beat() > beat) {
1495                                 break;
1496                         }
1497                         accumulated_beats = m->beat();
1498                         prev_ms = m;
1499                 }
1500
1501         }
1502         double const ret = prev_ms->pulse() + ((beat - accumulated_beats) / prev_ms->note_divisor());
1503         return ret;
1504 }
1505
1506 double
1507 TempoMap::beat_at_pulse (const double& pulse) const
1508 {
1509         Glib::Threads::RWLock::ReaderLock lm (lock);
1510         return beat_at_pulse_locked (_metrics, pulse);
1511 }
1512
1513 double
1514 TempoMap::beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1515 {
1516         MeterSection* prev_ms = 0;
1517         double accumulated_beats = 0.0;
1518
1519         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1520                 MeterSection* m;
1521                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1522                         if (prev_ms && m->pulse() > pulse) {
1523                                 break;
1524                         }
1525                         accumulated_beats = m->beat();
1526                         prev_ms = m;
1527                 }
1528         }
1529
1530         double const beats_in_section = (pulse - prev_ms->pulse()) * prev_ms->note_divisor();
1531
1532         return beats_in_section + accumulated_beats;
1533 }
1534
1535 TempoMetric
1536 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1537 {
1538         Glib::Threads::RWLock::ReaderLock lm (lock);
1539         TempoMetric m (first_meter(), first_tempo());
1540
1541         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1542            at something, because we insert the default tempo and meter during
1543            TempoMap construction.
1544
1545            now see if we can find better candidates.
1546         */
1547
1548         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1549
1550                 if ((*i)->frame() > frame) {
1551                         break;
1552                 }
1553
1554                 m.set_metric(*i);
1555
1556                 if (last) {
1557                         *last = i;
1558                 }
1559         }
1560
1561         return m;
1562 }
1563
1564 /* XX meters only */
1565 TempoMetric
1566 TempoMap::metric_at (BBT_Time bbt) const
1567 {
1568         Glib::Threads::RWLock::ReaderLock lm (lock);
1569         TempoMetric m (first_meter(), first_tempo());
1570
1571         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1572            at something, because we insert the default tempo and meter during
1573            TempoMap construction.
1574
1575            now see if we can find better candidates.
1576         */
1577
1578         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1579                 MeterSection* mw;
1580                 if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) {
1581                         BBT_Time section_start (mw->bbt());
1582
1583                         if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1584                                 break;
1585                         }
1586
1587                         m.set_metric (*i);
1588                 }
1589         }
1590
1591         return m;
1592 }
1593
1594 void
1595 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1596 {
1597
1598         if (frame < 0) {
1599                 bbt.bars = 1;
1600                 bbt.beats = 1;
1601                 bbt.ticks = 0;
1602                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1603                 return;
1604         }
1605         Glib::Threads::RWLock::ReaderLock lm (lock);
1606         double const beat = beat_at_frame_locked (_metrics, frame);
1607
1608         bbt = beats_to_bbt_locked (_metrics, beat);
1609 }
1610
1611 double
1612 TempoMap::bbt_to_beats (const Timecode::BBT_Time& bbt)
1613 {
1614         Glib::Threads::RWLock::ReaderLock lm (lock);
1615
1616         return bbt_to_beats_locked (_metrics, bbt);
1617 }
1618
1619 double
1620 TempoMap::bbt_to_beats_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const
1621 {
1622         /* CALLER HOLDS READ LOCK */
1623
1624         double accumulated_beats = 0.0;
1625         double accumulated_bars = 0.0;
1626         MeterSection* prev_ms = 0;
1627         /* because audio-locked meters have 'fake' integral beats,
1628            there is no pulse offset here.
1629         */
1630         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1631                 MeterSection* m;
1632                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1633                         double bars_to_m = 0.0;
1634                         if (prev_ms) {
1635                                 bars_to_m = (m->beat() - prev_ms->beat()) / prev_ms->divisions_per_bar();
1636                                 if ((bars_to_m + accumulated_bars) > (bbt.bars - 1)) {
1637                                         break;
1638                                 }
1639                                 accumulated_beats = m->beat();
1640                                 accumulated_bars += bars_to_m;
1641                         }
1642                         prev_ms = m;
1643                 }
1644         }
1645
1646         double const remaining_bars = (bbt.bars - 1) - accumulated_bars;
1647         double const remaining_bars_in_beats = remaining_bars * prev_ms->divisions_per_bar();
1648         double const ret = remaining_bars_in_beats + accumulated_beats + (bbt.beats - 1) + (bbt.ticks / BBT_Time::ticks_per_beat);
1649
1650         return ret;
1651 }
1652
1653 Timecode::BBT_Time
1654 TempoMap::beats_to_bbt (const double& beats)
1655 {
1656         Glib::Threads::RWLock::ReaderLock lm (lock);
1657
1658         return beats_to_bbt_locked (_metrics, beats);
1659 }
1660
1661 Timecode::BBT_Time
1662 TempoMap::beats_to_bbt_locked (const Metrics& metrics, const double& b) const
1663 {
1664         /* CALLER HOLDS READ LOCK */
1665         MeterSection* prev_ms = 0;
1666         const double beats = (b < 0.0) ? 0.0 : b;
1667         uint32_t accumulated_bars = 0;
1668         double accumulated_beats = 0.0;
1669
1670         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1671                 MeterSection* m = 0;
1672
1673                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1674
1675                         if (prev_ms) {
1676                                 double const beats_to_m = m->beat() - prev_ms->beat();
1677                                 if (accumulated_beats + beats_to_m > beats) {
1678                                         /* this is the meter after the one our beat is on*/
1679                                         break;
1680                                 }
1681
1682                                 /* we need a whole number of bars. */
1683                                 accumulated_bars += (beats_to_m + 1) / prev_ms->divisions_per_bar();
1684                                 accumulated_beats += beats_to_m;
1685                         }
1686
1687                         prev_ms = m;
1688                 }
1689         }
1690
1691         double const beats_in_ms = beats - accumulated_beats;
1692         uint32_t const bars_in_ms = (uint32_t) floor (beats_in_ms / prev_ms->divisions_per_bar());
1693         uint32_t const total_bars = bars_in_ms + accumulated_bars;
1694         double const remaining_beats = beats_in_ms - (bars_in_ms * prev_ms->divisions_per_bar());
1695         double const remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1696
1697         BBT_Time ret;
1698
1699         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1700         ret.beats = (uint32_t) floor (remaining_beats);
1701         ret.bars = total_bars;
1702
1703         /* 0 0 0 to 1 1 0 - based mapping*/
1704         ++ret.bars;
1705         ++ret.beats;
1706
1707         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1708                 ++ret.beats;
1709                 ret.ticks -= BBT_Time::ticks_per_beat;
1710         }
1711
1712         if (ret.beats >= prev_ms->divisions_per_bar() + 1) {
1713                 ++ret.bars;
1714                 ret.beats = 1;
1715         }
1716
1717         return ret;
1718 }
1719
1720 Timecode::BBT_Time
1721 TempoMap::pulse_to_bbt (const double& pulse)
1722 {
1723         Glib::Threads::RWLock::ReaderLock lm (lock);
1724         MeterSection* prev_ms = 0;
1725         uint32_t accumulated_bars = 0;
1726         double accumulated_pulses = 0.0;
1727
1728         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
1729                 MeterSection* m = 0;
1730
1731                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1732
1733                         if (prev_ms) {
1734                                 double const pulses_to_m = m->pulse() - prev_ms->pulse();
1735                                 if (accumulated_pulses + pulses_to_m > pulse) {
1736                                         /* this is the meter after the one our beat is on*/
1737                                         break;
1738                                 }
1739
1740                                 /* we need a whole number of bars. */
1741                                 accumulated_pulses += pulses_to_m;
1742                                 accumulated_bars += ((pulses_to_m * prev_ms->note_divisor()) + 1) / prev_ms->divisions_per_bar();
1743                         }
1744
1745                         prev_ms = m;
1746                 }
1747         }
1748         double const beats_in_ms = (pulse - prev_ms->pulse()) * prev_ms->note_divisor();
1749         uint32_t const bars_in_ms = (uint32_t) floor (beats_in_ms / prev_ms->divisions_per_bar());
1750         uint32_t const total_bars = bars_in_ms + accumulated_bars;
1751         double const remaining_beats = beats_in_ms - (bars_in_ms * prev_ms->divisions_per_bar());
1752         double const remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1753
1754         BBT_Time ret;
1755
1756         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1757         ret.beats = (uint32_t) floor (remaining_beats);
1758         ret.bars = total_bars;
1759
1760         /* 0 0 0 to 1 1 0 mapping*/
1761         ++ret.bars;
1762         ++ret.beats;
1763
1764         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1765                 ++ret.beats;
1766                 ret.ticks -= BBT_Time::ticks_per_beat;
1767         }
1768
1769         if (ret.beats >= prev_ms->divisions_per_bar() + 1) {
1770                 ++ret.bars;
1771                 ret.beats = 1;
1772         }
1773
1774         return ret;
1775 }
1776
1777 double
1778 TempoMap::beat_at_frame (const framecnt_t& frame) const
1779 {
1780         Glib::Threads::RWLock::ReaderLock lm (lock);
1781         return beat_at_frame_locked (_metrics, frame);
1782 }
1783
1784 double
1785 TempoMap::beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1786 {
1787         framecnt_t const offset_frame = frame + frame_offset_at (metrics, frame);
1788         double const pulse = pulse_at_frame_locked (metrics, offset_frame);
1789
1790         return beat_at_pulse_locked (metrics, pulse);
1791 }
1792
1793 double
1794 TempoMap::pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const
1795 {
1796         /* HOLD (at least) THE READER LOCK */
1797         TempoSection* prev_ts = 0;
1798         double accumulated_pulses = 0.0;
1799
1800         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1801                 TempoSection* t;
1802                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1803
1804                         if (prev_ts && t->frame() > frame) {
1805                                 /*the previous ts is the one containing the frame */
1806                                 double const ret = prev_ts->pulse_at_frame (frame, _frame_rate);
1807                                 return ret;
1808                         }
1809                         accumulated_pulses = t->pulse();
1810                         prev_ts = t;
1811                 }
1812         }
1813
1814         /* treated as constant for this ts */
1815         double const pulses_in_section = (frame - prev_ts->frame()) / prev_ts->frames_per_pulse (_frame_rate);
1816
1817         return pulses_in_section + accumulated_pulses;
1818 }
1819
1820 framecnt_t
1821 TempoMap::frame_at_beat (const double& beat) const
1822 {
1823         Glib::Threads::RWLock::ReaderLock lm (lock);
1824         return frame_at_beat_locked (_metrics, beat);
1825 }
1826
1827 framecnt_t
1828 TempoMap::frame_at_beat_locked (const Metrics& metrics, const double& beat) const
1829 {
1830         framecnt_t const frame = frame_at_pulse_locked (metrics, pulse_at_beat_locked (metrics, beat));
1831         frameoffset_t const frame_off = frame_offset_at (metrics, frame);
1832         return frame - frame_off;
1833 }
1834
1835 framecnt_t
1836 TempoMap::frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const
1837 {
1838         /* HOLD THE READER LOCK */
1839
1840         const TempoSection* prev_ts = 0;
1841         double accumulated_pulses = 0.0;
1842
1843         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1844                 TempoSection* t;
1845
1846                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1847                         if (prev_ts && t->pulse() > pulse) {
1848                                 return prev_ts->frame_at_pulse (pulse, _frame_rate);
1849                         }
1850
1851                         accumulated_pulses = t->pulse();
1852                         prev_ts = t;
1853                 }
1854         }
1855         /* must be treated as constant, irrespective of _type */
1856         double const pulses_in_section = pulse - accumulated_pulses;
1857         double const dtime = pulses_in_section * prev_ts->frames_per_pulse (_frame_rate);
1858
1859         framecnt_t const ret = (framecnt_t) floor (dtime) + prev_ts->frame();
1860
1861         return ret;
1862 }
1863
1864 double
1865 TempoMap::beat_offset_at (const Metrics& metrics, const double& beat) const
1866 {
1867         MeterSection* prev_m = 0;
1868         double beat_off = first_meter().pulse();
1869
1870         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1871                 MeterSection* m = 0;
1872                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1873                         if (prev_m) {
1874                                 if (m->beat() > beat) {
1875                                         break;
1876                                 }
1877
1878                                 if (m->position_lock_style() == AudioTime) {
1879                                         beat_off += ((m->beat() - prev_m->beat()) / prev_m->note_divisor()) - floor (m->pulse() - prev_m->pulse());
1880                                 }
1881                         }
1882                         prev_m = m;
1883                 }
1884         }
1885
1886         return beat_off;
1887 }
1888
1889 frameoffset_t
1890 TempoMap::frame_offset_at (const Metrics& metrics, const framepos_t& frame) const
1891 {
1892         frameoffset_t frame_off = 0;
1893         MeterSection* prev_m = 0;
1894
1895         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1896                 MeterSection* m = 0;
1897                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1898                         if (m->frame() > frame) {
1899                                 break;
1900                         }
1901                         if (prev_m && m->position_lock_style() == AudioTime) {
1902                                 const double pulse = prev_m->pulse() + ((m->beat() - prev_m->beat()) / prev_m->note_divisor());
1903                                 frame_off += frame_at_pulse_locked (metrics, pulse) - m->frame();
1904                         }
1905                         prev_m = m;
1906                 }
1907         }
1908
1909         return frame_off;
1910 }
1911
1912 framepos_t
1913 TempoMap::frame_time (const BBT_Time& bbt)
1914 {
1915         if (bbt.bars < 1) {
1916                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1917                 return 0;
1918         }
1919
1920         if (bbt.beats < 1) {
1921                 throw std::logic_error ("beats are counted from one");
1922         }
1923         Glib::Threads::RWLock::ReaderLock lm (lock);
1924         double const beat = bbt_to_beats_locked (_metrics, bbt);
1925         framecnt_t const frame = frame_at_beat_locked (_metrics, beat);
1926         return frame;
1927 }
1928
1929 framepos_t
1930 TempoMap::frame_time_locked (const Metrics& metrics, const BBT_Time& bbt) const
1931 {
1932         /* HOLD THE READER LOCK */
1933
1934         framepos_t const ret = frame_at_pulse_locked (metrics, pulse_at_beat_locked (metrics, bbt_to_beats_locked (metrics, bbt)));
1935
1936         return ret;
1937 }
1938
1939 bool
1940 TempoMap::check_solved (Metrics& metrics, bool by_frame)
1941 {
1942         TempoSection* prev_ts = 0;
1943
1944         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1945                 TempoSection* t;
1946                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1947                         if (prev_ts) {
1948                                 if ((by_frame && t->frame() < prev_ts->frame()) || (!by_frame && t->pulse() < prev_ts->pulse())) {
1949                                         return false;
1950                                 }
1951                                 if (by_frame && t->frame() != prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate)) {
1952                                         return false;
1953                                 }
1954                                 /*
1955                                 if (!by_frame && fabs (t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate)) > 0.00001) {
1956                                         std::cerr << "beat precision too low for bpm: " << t->beats_per_minute() << std::endl <<
1957                                                 " |error          :" << t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << std::endl <<
1958                                                 "|frame at beat   :" << prev_ts->frame_at_pulse (t->pulse(), _frame_rate) << std::endl <<
1959                                                 " |frame at tempo : " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
1960                                         return false;
1961                                 }
1962                                 */
1963                         }
1964                         prev_ts = t;
1965                 }
1966         }
1967
1968         return true;
1969 }
1970
1971 bool
1972 TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const Tempo& bpm, const framepos_t& frame)
1973 {
1974         TempoSection* prev_ts = 0;
1975         TempoSection* section_prev = 0;
1976         MetricSectionFrameSorter fcmp;
1977         MetricSectionSorter cmp;
1978
1979         section->set_frame (frame);
1980
1981         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
1982                 TempoSection* t;
1983                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1984                         if (prev_ts) {
1985                                 if (t == section) {
1986                                         section_prev = prev_ts;
1987                                         continue;
1988                                 }
1989                                 if (t->position_lock_style() == MusicTime) {
1990                                         prev_ts->set_c_func (prev_ts->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
1991                                         t->set_frame (prev_ts->frame_at_pulse (t->pulse(), _frame_rate));
1992                                 } else {
1993                                         prev_ts->set_c_func (prev_ts->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
1994                                         t->set_pulse (prev_ts->pulse_at_frame (t->frame(), _frame_rate));
1995                                 }
1996                         }
1997                         prev_ts = t;
1998                 }
1999         }
2000
2001         if (section_prev) {
2002                 section_prev->set_c_func (section_prev->compute_c_func_frame (bpm.pulses_per_minute(), frame, _frame_rate));
2003                 section->set_pulse (section_prev->pulse_at_frame (frame, _frame_rate));
2004         }
2005
2006         if (section->position_lock_style() == MusicTime) {
2007                 /* we're setting the frame */
2008                 section->set_position_lock_style (AudioTime);
2009                 recompute_tempos (imaginary);
2010                 section->set_position_lock_style (MusicTime);
2011         } else {
2012                 recompute_tempos (imaginary);
2013         }
2014
2015         if (check_solved (imaginary, true)) {
2016                 recompute_meters (imaginary);
2017                 return true;
2018         }
2019
2020         imaginary.sort (fcmp);
2021         if (section->position_lock_style() == MusicTime) {
2022                 /* we're setting the frame */
2023                 section->set_position_lock_style (AudioTime);
2024                 recompute_tempos (imaginary);
2025                 section->set_position_lock_style (MusicTime);
2026         } else {
2027                 recompute_tempos (imaginary);
2028         }
2029         if (check_solved (imaginary, true)) {
2030                 recompute_meters (imaginary);
2031                 return true;
2032         }
2033
2034         imaginary.sort (cmp);
2035         if (section->position_lock_style() == MusicTime) {
2036                 /* we're setting the frame */
2037                 section->set_position_lock_style (AudioTime);
2038                 recompute_tempos (imaginary);
2039                 section->set_position_lock_style (MusicTime);
2040         } else {
2041                 recompute_tempos (imaginary);
2042         }
2043         if (check_solved (imaginary, true)) {
2044                 recompute_meters (imaginary);
2045                 return true;
2046         }
2047         //dump (imaginary, std::cerr);
2048
2049         return false;
2050 }
2051
2052 bool
2053 TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const Tempo& bpm, const double& pulse)
2054 {
2055         MetricSectionSorter cmp;
2056         MetricSectionFrameSorter fcmp;
2057         TempoSection* prev_ts = 0;
2058         TempoSection* section_prev = 0;
2059
2060         section->set_pulse (pulse);
2061         section->set_beats_per_minute (bpm.beats_per_minute());
2062
2063         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2064                 TempoSection* t;
2065                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2066                         if (prev_ts) {
2067                                 if (t == section) {
2068                                         section_prev = prev_ts;
2069                                         continue;
2070                                 }
2071                                 if (t->position_lock_style() == MusicTime) {
2072                                         prev_ts->set_c_func (prev_ts->compute_c_func_pulse (t->pulses_per_minute(), t->pulse(), _frame_rate));
2073                                         t->set_frame (prev_ts->frame_at_pulse (t->pulse(), _frame_rate));
2074                                 } else {
2075                                         prev_ts->set_c_func (prev_ts->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
2076                                         t->set_pulse (prev_ts->pulse_at_frame (t->frame(), _frame_rate));
2077                                 }
2078                         }
2079                         prev_ts = t;
2080                 }
2081         }
2082         if (section_prev) {
2083                 section_prev->set_c_func (section_prev->compute_c_func_pulse (bpm.pulses_per_minute(), pulse, _frame_rate));
2084                 section->set_frame (section_prev->frame_at_pulse (pulse, _frame_rate));
2085         }
2086
2087         if (section->position_lock_style() == AudioTime) {
2088                 /* we're setting the pulse */
2089                 section->set_position_lock_style (MusicTime);
2090                 recompute_tempos (imaginary);
2091                 section->set_position_lock_style (AudioTime);
2092         } else {
2093                 recompute_tempos (imaginary);
2094         }
2095         if (check_solved (imaginary, false)) {
2096                 recompute_meters (imaginary);
2097                 return true;
2098         }
2099
2100         imaginary.sort (cmp);
2101         if (section->position_lock_style() == AudioTime) {
2102                 /* we're setting the pulse */
2103                 section->set_position_lock_style (MusicTime);
2104                 recompute_tempos (imaginary);
2105                 section->set_position_lock_style (AudioTime);
2106         } else {
2107                 recompute_tempos (imaginary);
2108         }
2109
2110         if (check_solved (imaginary, false)) {
2111                 recompute_meters (imaginary);
2112                 return true;
2113         }
2114
2115         imaginary.sort (fcmp);
2116         if (section->position_lock_style() == AudioTime) {
2117                 /* we're setting the pulse */
2118                 section->set_position_lock_style (MusicTime);
2119                 recompute_tempos (imaginary);
2120                 section->set_position_lock_style (AudioTime);
2121         } else {
2122                 recompute_tempos (imaginary);
2123         }
2124
2125         if (check_solved (imaginary, false)) {
2126                 recompute_meters (imaginary);
2127                 return true;
2128         }
2129
2130         //dump (imaginary, std::cerr);
2131
2132         return false;
2133 }
2134
2135 void
2136 TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const Meter& mt, const double& pulse)
2137 {
2138         MeterSection* prev_ms = 0;
2139
2140         double accumulated_beats = 0.0;
2141         uint32_t accumulated_bars = 0;
2142
2143         section->set_pulse (pulse);
2144
2145         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2146                 MeterSection* m;
2147                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2148                         if (prev_ms) {
2149                                 double const beats_in_m = (m->pulse() - prev_ms->pulse()) * prev_ms->note_divisor();
2150                                 accumulated_beats += beats_in_m;
2151                                 accumulated_bars += (beats_in_m + 1) / prev_ms->divisions_per_bar();
2152                         }
2153                         if (m == section){
2154                                 section->set_frame (frame_at_pulse_locked (imaginary, pulse));
2155                                 pair<double, BBT_Time> b_bbt = make_pair (accumulated_beats, BBT_Time (accumulated_bars + 1, 1, 0));
2156                                 section->set_beat (b_bbt);
2157                                 prev_ms = section;
2158                                 continue;
2159                         }
2160                         if (prev_ms) {
2161                                 if (m->position_lock_style() == MusicTime) {
2162                                         const double pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2163                                         m->set_frame (frame_at_pulse_locked (imaginary, pulse));
2164                                         m->set_pulse (pulse);
2165                                 } else {
2166                                         pair<double, BBT_Time> b_bbt = make_pair (accumulated_beats, BBT_Time (accumulated_bars + 1, 1, 0));
2167                                         m->set_beat (b_bbt);
2168                                         const double pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2169                                         m->set_pulse (pulse);
2170                                 }
2171                         }
2172                         prev_ms = m;
2173                 }
2174         }
2175
2176         if (section->position_lock_style() == AudioTime) {
2177                 /* we're setting the pulse */
2178                 section->set_position_lock_style (MusicTime);
2179                 recompute_meters (imaginary);
2180                 section->set_position_lock_style (AudioTime);
2181         } else {
2182                 recompute_meters (imaginary);
2183         }
2184 }
2185
2186 void
2187 TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const Meter& mt, const framepos_t& frame)
2188 {
2189         MeterSection* prev_ms = 0;
2190         double accumulated_beats = 0.0;
2191         uint32_t accumulated_bars = 0;
2192
2193         section->set_frame (frame);
2194
2195         for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
2196                 MeterSection* m;
2197                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
2198                         if (prev_ms) {
2199                                 const double beats_in_m = (m->pulse() - prev_ms->pulse()) * prev_ms->note_divisor();
2200                                 accumulated_beats += beats_in_m;
2201                                 accumulated_bars += (beats_in_m + 1) / prev_ms->divisions_per_bar();
2202                         }
2203                         if (m == section){
2204                                 /*
2205                                   here we define the pulse for this frame.
2206                                   we're going to set it 'incorrectly' to the next integer and use this 'error'
2207                                   as an offset to the map as far as users of the public methods are concerned.
2208                                   (meters should go on absolute pulses to keep us sane)
2209                                 */
2210                                 pair<double, BBT_Time> b_bbt = make_pair (accumulated_beats, BBT_Time (accumulated_bars + 1, 1, 0));
2211                                 m->set_pulse (pulse_at_frame_locked (imaginary, frame));
2212                                 m->set_beat (b_bbt);
2213                                 prev_ms = m;
2214                                 continue;
2215                         }
2216                         if (prev_ms) {
2217                                 if (m->position_lock_style() == MusicTime) {
2218                                         const double pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2219                                         m->set_frame (frame_at_pulse_locked (imaginary, pulse));
2220                                         m->set_pulse (pulse);
2221                                 } else {
2222                                         pair<double, BBT_Time> b_bbt = make_pair (accumulated_beats, BBT_Time (accumulated_bars + 1, 1, 0));
2223                                         m->set_beat (b_bbt);
2224                                         const double pulse = prev_ms->pulse() + (m->beat() - prev_ms->beat()) / prev_ms->note_divisor();
2225                                         m->set_pulse (pulse);
2226                                 }
2227                         }
2228                         prev_ms = m;
2229                 }
2230         }
2231
2232         if (section->position_lock_style() == MusicTime) {
2233                 /* we're setting the frame */
2234                 section->set_position_lock_style (AudioTime);
2235                 recompute_meters (imaginary);
2236                 section->set_position_lock_style (MusicTime);
2237         } else {
2238                 recompute_meters (imaginary);
2239         }
2240         //dump (imaginary, std::cerr);
2241 }
2242
2243 framecnt_t
2244 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
2245 {
2246         Glib::Threads::RWLock::ReaderLock lm (lock);
2247
2248         double const tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
2249         double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
2250         double const total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
2251         framecnt_t const time_at_bbt = frame_at_beat_locked (_metrics, total_beats);
2252         framecnt_t const ret = time_at_bbt;
2253
2254         return ret;
2255 }
2256
2257 framepos_t
2258 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
2259 {
2260         return round_to_type (fr, dir, Bar);
2261 }
2262
2263 framepos_t
2264 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
2265 {
2266         return round_to_type (fr, dir, Beat);
2267 }
2268
2269 framepos_t
2270 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
2271 {
2272         Glib::Threads::RWLock::ReaderLock lm (lock);
2273         uint32_t ticks = (uint32_t) floor (beat_at_frame_locked (_metrics, fr) * BBT_Time::ticks_per_beat);
2274         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
2275         uint32_t ticks_one_subdivisions_worth = (uint32_t) BBT_Time::ticks_per_beat / sub_num;
2276
2277         ticks -= beats * BBT_Time::ticks_per_beat;
2278
2279         if (dir > 0) {
2280                 /* round to next (or same iff dir == RoundUpMaybe) */
2281
2282                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
2283
2284                 if (mod == 0 && dir == RoundUpMaybe) {
2285                         /* right on the subdivision, which is fine, so do nothing */
2286
2287                 } else if (mod == 0) {
2288                         /* right on the subdivision, so the difference is just the subdivision ticks */
2289                         ticks += ticks_one_subdivisions_worth;
2290
2291                 } else {
2292                         /* not on subdivision, compute distance to next subdivision */
2293
2294                         ticks += ticks_one_subdivisions_worth - mod;
2295                 }
2296
2297                 if (ticks >= BBT_Time::ticks_per_beat) {
2298                         ticks -= BBT_Time::ticks_per_beat;
2299                 }
2300         } else if (dir < 0) {
2301
2302                 /* round to previous (or same iff dir == RoundDownMaybe) */
2303
2304                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
2305
2306                 if (difference == 0 && dir == RoundDownAlways) {
2307                         /* right on the subdivision, but force-rounding down,
2308                            so the difference is just the subdivision ticks */
2309                         difference = ticks_one_subdivisions_worth;
2310                 }
2311
2312                 if (ticks < difference) {
2313                         ticks = BBT_Time::ticks_per_beat - ticks;
2314                 } else {
2315                         ticks -= difference;
2316                 }
2317
2318         } else {
2319                 /* round to nearest */
2320                 double rem;
2321
2322                 /* compute the distance to the previous and next subdivision */
2323
2324                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
2325
2326                         /* closer to the next subdivision, so shift forward */
2327
2328                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
2329
2330                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
2331
2332                         if (ticks > BBT_Time::ticks_per_beat) {
2333                                 ++beats;
2334                                 ticks -= BBT_Time::ticks_per_beat;
2335                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
2336                         }
2337
2338                 } else if (rem > 0) {
2339
2340                         /* closer to previous subdivision, so shift backward */
2341
2342                         if (rem > ticks) {
2343                                 if (beats == 0) {
2344                                         /* can't go backwards past zero, so ... */
2345                                         return 0;
2346                                 }
2347                                 /* step back to previous beat */
2348                                 --beats;
2349                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
2350                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
2351                         } else {
2352                                 ticks = lrint (ticks - rem);
2353                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
2354                         }
2355                 } else {
2356                         /* on the subdivision, do nothing */
2357                 }
2358         }
2359
2360         framepos_t const ret_frame = frame_at_beat_locked (_metrics, beats + (ticks / BBT_Time::ticks_per_beat));
2361
2362         return ret_frame;
2363 }
2364
2365 framepos_t
2366 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
2367 {
2368         Glib::Threads::RWLock::ReaderLock lm (lock);
2369
2370         double const beat_at_framepos = beat_at_frame_locked (_metrics, frame);
2371         BBT_Time bbt (beats_to_bbt_locked (_metrics, beat_at_framepos));
2372
2373         switch (type) {
2374         case Bar:
2375                 if (dir < 0) {
2376                         /* find bar previous to 'frame' */
2377                         bbt.beats = 1;
2378                         bbt.ticks = 0;
2379                         return frame_time (bbt);
2380
2381                 } else if (dir > 0) {
2382                         /* find bar following 'frame' */
2383                         ++bbt.bars;
2384                         bbt.beats = 1;
2385                         bbt.ticks = 0;
2386                         return frame_time (bbt);
2387                 } else {
2388                         /* true rounding: find nearest bar */
2389                         framepos_t raw_ft = frame_time (bbt);
2390                         bbt.beats = 1;
2391                         bbt.ticks = 0;
2392                         framepos_t prev_ft = frame_time (bbt);
2393                         ++bbt.bars;
2394                         framepos_t next_ft = frame_time (bbt);
2395
2396                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
2397                                 return next_ft;
2398                         } else {
2399                                 return prev_ft;
2400                         }
2401                 }
2402
2403                 break;
2404
2405         case Beat:
2406                 if (dir < 0) {
2407                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos));
2408                 } else if (dir > 0) {
2409                         return frame_at_beat_locked (_metrics, ceil (beat_at_framepos));
2410                 } else {
2411                         return frame_at_beat_locked (_metrics, floor (beat_at_framepos + 0.5));
2412                 }
2413                 break;
2414         }
2415
2416         return 0;
2417 }
2418
2419 void
2420 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
2421                     framepos_t lower, framepos_t upper)
2422 {
2423         Glib::Threads::RWLock::ReaderLock lm (lock);
2424         int32_t const upper_beat = (int32_t) ceil (beat_at_frame_locked (_metrics, upper));
2425         int32_t cnt = floor (beat_at_frame_locked (_metrics, lower));
2426         /* although the map handles negative beats, bbt doesn't. */
2427         if (cnt < 0.0) {
2428                 cnt = 0.0;
2429         }
2430         while (cnt <= upper_beat) {
2431                 framecnt_t pos = frame_at_beat_locked (_metrics, cnt);
2432                 TempoSection const tempo = tempo_section_at_locked (pos);
2433                 MeterSection const meter = meter_section_at_locked (pos);
2434                 BBT_Time const bbt = beats_to_bbt (cnt);
2435
2436                 points.push_back (BBTPoint (meter, Tempo (tempo.beats_per_minute(), tempo.note_type()), pos, bbt.bars, bbt.beats));
2437                 ++cnt;
2438         }
2439 }
2440
2441 const TempoSection&
2442 TempoMap::tempo_section_at (framepos_t frame) const
2443 {
2444         Glib::Threads::RWLock::ReaderLock lm (lock);
2445         return tempo_section_at_locked (frame);
2446 }
2447
2448 const TempoSection&
2449 TempoMap::tempo_section_at_locked (framepos_t frame) const
2450 {
2451         Metrics::const_iterator i;
2452         TempoSection* prev = 0;
2453
2454         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2455                 TempoSection* t;
2456
2457                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2458
2459                         if (t->frame() > frame) {
2460                                 break;
2461                         }
2462
2463                         prev = t;
2464                 }
2465         }
2466
2467         if (prev == 0) {
2468                 fatal << endmsg;
2469                 abort(); /*NOTREACHED*/
2470         }
2471
2472         return *prev;
2473 }
2474
2475
2476 /* don't use this to calculate length (the tempo is only correct for this frame).
2477    do that stuff based on the beat_at_frame and frame_at_beat api
2478 */
2479 double
2480 TempoMap::frames_per_beat_at (const framepos_t& frame, const framecnt_t& sr) const
2481 {
2482         Glib::Threads::RWLock::ReaderLock lm (lock);
2483
2484         const TempoSection* ts_at = &tempo_section_at_locked (frame);
2485         const TempoSection* ts_after = 0;
2486         Metrics::const_iterator i;
2487
2488         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2489                 TempoSection* t;
2490
2491                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2492
2493                         if ((*i)->frame() > frame) {
2494                                 ts_after = t;
2495                                 break;
2496                         }
2497                 }
2498         }
2499
2500         if (ts_after) {
2501                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame, _frame_rate));
2502         }
2503         /* must be treated as constant tempo */
2504         return ts_at->frames_per_beat (_frame_rate);
2505 }
2506
2507 const Tempo
2508 TempoMap::tempo_at (const framepos_t& frame) const
2509 {
2510         Glib::Threads::RWLock::ReaderLock lm (lock);
2511         //frameoffset_t const frame_off = frame_offset_at (_metrics, frame);
2512         TempoSection* prev_ts = 0;
2513
2514         Metrics::const_iterator i;
2515
2516         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2517                 TempoSection* t;
2518                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
2519                         if ((prev_ts) && t->frame() > frame) {
2520                                 /* t is the section past frame */
2521                                 double const ret = prev_ts->tempo_at_frame (frame, _frame_rate) * prev_ts->note_type();
2522                                 Tempo const ret_tempo (ret, prev_ts->note_type());
2523                                 return ret_tempo;
2524                         }
2525                         prev_ts = t;
2526                 }
2527         }
2528
2529         double const ret = prev_ts->beats_per_minute();
2530         Tempo const ret_tempo (ret, prev_ts->note_type ());
2531
2532         return ret_tempo;
2533 }
2534
2535 const MeterSection&
2536 TempoMap::meter_section_at (framepos_t frame) const
2537 {
2538         Glib::Threads::RWLock::ReaderLock lm (lock);
2539         return meter_section_at_locked (frame);
2540 }
2541
2542 const MeterSection&
2543 TempoMap::meter_section_at_locked (framepos_t frame) const
2544 {
2545         //framepos_t const frame_off = frame + frame_offset_at (_metrics, frame);
2546         Metrics::const_iterator i;
2547         MeterSection* prev = 0;
2548
2549         for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2550                 MeterSection* t;
2551
2552                 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
2553
2554                         if (prev && (*i)->frame() > frame) {
2555                                 break;
2556                         }
2557
2558                         prev = t;
2559                 }
2560         }
2561
2562         if (prev == 0) {
2563                 fatal << endmsg;
2564                 abort(); /*NOTREACHED*/
2565         }
2566
2567         return *prev;
2568 }
2569
2570 const Meter&
2571 TempoMap::meter_at (framepos_t frame) const
2572 {
2573         TempoMetric m (metric_at (frame));
2574         return m.meter();
2575 }
2576
2577 XMLNode&
2578 TempoMap::get_state ()
2579 {
2580         Metrics::const_iterator i;
2581         XMLNode *root = new XMLNode ("TempoMap");
2582
2583         {
2584                 Glib::Threads::RWLock::ReaderLock lm (lock);
2585                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2586                         root->add_child_nocopy ((*i)->get_state());
2587                 }
2588         }
2589
2590         return *root;
2591 }
2592
2593 int
2594 TempoMap::set_state (const XMLNode& node, int /*version*/)
2595 {
2596         {
2597                 Glib::Threads::RWLock::WriterLock lm (lock);
2598
2599                 XMLNodeList nlist;
2600                 XMLNodeConstIterator niter;
2601                 Metrics old_metrics (_metrics);
2602                 MeterSection* last_meter = 0;
2603                 _metrics.clear();
2604
2605                 nlist = node.children();
2606
2607                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2608                         XMLNode* child = *niter;
2609
2610                         if (child->name() == TempoSection::xml_state_node_name) {
2611
2612                                 try {
2613                                         TempoSection* ts = new TempoSection (*child);
2614                                         _metrics.push_back (ts);
2615
2616                                         if (ts->bar_offset() < 0.0) {
2617                                                 if (last_meter) {
2618                                                         //ts->update_bar_offset_from_bbt (*last_meter);
2619                                                 }
2620                                         }
2621                                 }
2622
2623                                 catch (failed_constructor& err){
2624                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2625                                         _metrics = old_metrics;
2626                                         break;
2627                                 }
2628
2629                         } else if (child->name() == MeterSection::xml_state_node_name) {
2630
2631                                 try {
2632                                         MeterSection* ms = new MeterSection (*child);
2633                                         _metrics.push_back (ms);
2634                                         last_meter = ms;
2635                                 }
2636
2637                                 catch (failed_constructor& err) {
2638                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2639                                         _metrics = old_metrics;
2640                                         break;
2641                                 }
2642                         }
2643                 }
2644
2645                 if (niter == nlist.end()) {
2646                         MetricSectionSorter cmp;
2647                         _metrics.sort (cmp);
2648                 }
2649                 /* check for legacy sessions where bbt was the base musical unit for tempo */
2650                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2651                         MeterSection* m;
2652                         TempoSection* t;
2653                         MeterSection* prev_ms = 0;
2654                         TempoSection* prev_ts = 0;
2655                         if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2656                                 if (prev_ms && prev_ms->pulse() < 0.0) {
2657                                         /*XX we cannot possibly make this work??. */
2658                                         pair<double, BBT_Time> start = make_pair (((prev_ms->bbt().bars - 1) * prev_ms->note_divisor()) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat), prev_ms->bbt());
2659                                         prev_ms->set_beat (start);
2660                                         const double start_pulse = ((prev_ms->bbt().bars - 1) * prev_ms->note_divisor()) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat);
2661                                         prev_ms->set_pulse (start_pulse);
2662                                 }
2663                                 prev_ms = m;
2664                         } else if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2665                                 if (prev_ts && prev_ts->pulse() < 0.0) {
2666                                         double const start = ((prev_ts->legacy_bbt().bars - 1) * prev_ms->note_divisor()) + (prev_ts->legacy_bbt().beats - 1) + (prev_ts->legacy_bbt().ticks / BBT_Time::ticks_per_beat);
2667                                         prev_ts->set_pulse (start);
2668                                 }
2669                                 prev_ts = t;
2670                         }
2671                 }
2672                 /* check for multiple tempo/meters at the same location, which
2673                    ardour2 somehow allowed.
2674                 */
2675
2676                 Metrics::iterator prev = _metrics.end();
2677                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2678                         if (prev != _metrics.end()) {
2679                                 MeterSection* ms;
2680                                 MeterSection* prev_ms;
2681                                 TempoSection* ts;
2682                                 TempoSection* prev_ts;
2683                                 if ((prev_ms = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) {
2684                                         if (prev_ms->pulse() == ms->pulse()) {
2685                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), prev_ms->pulse()) << endmsg;
2686                                                 error << string_compose (_("Multiple meter definitions found at %1"), prev_ms->pulse()) << endmsg;
2687                                                 return -1;
2688                                         }
2689                                 } else if ((prev_ts = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) {
2690                                         if (prev_ts->pulse() == ts->pulse()) {
2691                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->pulse()) << endmsg;
2692                                                 error << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->pulse()) << endmsg;
2693                                                 return -1;
2694                                         }
2695                                 }
2696                         }
2697                         prev = i;
2698                 }
2699
2700                 recompute_map (_metrics);
2701         }
2702
2703         PropertyChanged (PropertyChange ());
2704
2705         return 0;
2706 }
2707
2708 void
2709 TempoMap::dump (const Metrics& metrics, std::ostream& o) const
2710 {
2711         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2712         const MeterSection* m;
2713         const TempoSection* t;
2714         const TempoSection* prev_ts = 0;
2715
2716         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2717
2718                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2719                         o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->pulse() << " frame= " << t->frame() << " (movable? "
2720                           << t->movable() << ')' << " pos lock: " << enum_2_string (t->position_lock_style()) << std::endl;
2721                         o << "current      : " << t->beats_per_minute() << " | " << t->pulse() << " | " << t->frame() << std::endl;
2722                         if (prev_ts) {
2723                                 o << "previous     : " << prev_ts->beats_per_minute() << " | " << prev_ts->pulse() << " | " << prev_ts->frame() << std::endl;
2724                                 o << "calculated   : " << prev_ts->tempo_at_pulse (t->pulse()) *  prev_ts->note_type() << " | " << prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) <<  " | " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl;
2725                         }
2726                         prev_ts = t;
2727                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2728                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame()
2729                           << " pulse: " << m->pulse() <<  " beat : " << m->beat() << " pos lock: " << enum_2_string (m->position_lock_style()) << " (movable? " << m->movable() << ')' << endl;
2730                 }
2731         }
2732         o << "------" << std::endl;
2733 }
2734
2735 int
2736 TempoMap::n_tempos() const
2737 {
2738         Glib::Threads::RWLock::ReaderLock lm (lock);
2739         int cnt = 0;
2740
2741         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2742                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
2743                         cnt++;
2744                 }
2745         }
2746
2747         return cnt;
2748 }
2749
2750 int
2751 TempoMap::n_meters() const
2752 {
2753         Glib::Threads::RWLock::ReaderLock lm (lock);
2754         int cnt = 0;
2755
2756         for (Metrics::const_iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2757                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
2758                         cnt++;
2759                 }
2760         }
2761
2762         return cnt;
2763 }
2764
2765 void
2766 TempoMap::insert_time (framepos_t where, framecnt_t amount)
2767 {
2768         {
2769                 Glib::Threads::RWLock::WriterLock lm (lock);
2770                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2771                         if ((*i)->frame() >= where && (*i)->movable ()) {
2772                                 (*i)->set_frame ((*i)->frame() + amount);
2773                         }
2774                 }
2775
2776                 /* now reset the BBT time of all metrics, based on their new
2777                  * audio time. This is the only place where we do this reverse
2778                  * timestamp.
2779                  */
2780
2781                 Metrics::iterator i;
2782                 const MeterSection* meter;
2783                 const TempoSection* tempo;
2784                 MeterSection *m;
2785                 TempoSection *t;
2786
2787                 meter = &first_meter ();
2788                 tempo = &first_tempo ();
2789
2790                 BBT_Time start;
2791                 BBT_Time end;
2792
2793                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
2794
2795                 bool first = true;
2796                 MetricSection* prev = 0;
2797
2798                 for (i = _metrics.begin(); i != _metrics.end(); ++i) {
2799
2800                         BBT_Time bbt;
2801                         //TempoMetric metric (*meter, *tempo);
2802                         MeterSection* ms = const_cast<MeterSection*>(meter);
2803                         TempoSection* ts = const_cast<TempoSection*>(tempo);
2804                         if (prev) {
2805                                 if (ts){
2806                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
2807                                                 ts->set_pulse (t->pulse());
2808                                         }
2809                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
2810                                                 ts->set_pulse (m->pulse());
2811                                         }
2812                                         ts->set_frame (prev->frame());
2813
2814                                 }
2815                                 if (ms) {
2816                                         if ((m = dynamic_cast<MeterSection*>(prev)) != 0) {
2817                                                 pair<double, BBT_Time> start = make_pair (m->beat(), m->bbt());
2818                                                 ms->set_beat (start);
2819                                                 ms->set_pulse (m->pulse());
2820                                         }
2821                                         if ((t = dynamic_cast<TempoSection*>(prev)) != 0) {
2822                                                 const double beat = beat_at_pulse_locked (_metrics, t->pulse());
2823                                                 pair<double, BBT_Time> start = make_pair (beat, beats_to_bbt_locked (_metrics, beat));
2824                                                 ms->set_beat (start);
2825                                                 ms->set_pulse (t->pulse());
2826                                         }
2827                                         ms->set_frame (prev->frame());
2828                                 }
2829
2830                         } else {
2831                                 // metric will be at frames=0 bbt=1|1|0 by default
2832                                 // which is correct for our purpose
2833                         }
2834
2835                         // cerr << bbt << endl;
2836
2837                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2838                                 t->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
2839                                 tempo = t;
2840                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
2841                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2842                                 bbt_time (m->frame(), bbt);
2843
2844                                 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
2845
2846                                 if (first) {
2847                                         first = false;
2848                                 } else {
2849
2850                                         if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
2851                                                 /* round up to next beat */
2852                                                 bbt.beats += 1;
2853                                         }
2854
2855                                         bbt.ticks = 0;
2856
2857                                         if (bbt.beats != 1) {
2858                                                 /* round up to next bar */
2859                                                 bbt.bars += 1;
2860                                                 bbt.beats = 1;
2861                                         }
2862                                 }
2863                                 pair<double, BBT_Time> start = make_pair (beat_at_frame_locked (_metrics, m->frame()), bbt);
2864                                 m->set_beat (start);
2865                                 m->set_pulse (pulse_at_frame_locked (_metrics, m->frame()));
2866                                 meter = m;
2867                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " beat = " << (*i)->pulse() <<endl;
2868                         } else {
2869                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
2870                                 abort(); /*NOTREACHED*/
2871                         }
2872
2873                         prev = (*i);
2874                 }
2875
2876                 recompute_map (_metrics);
2877         }
2878
2879
2880         PropertyChanged (PropertyChange ());
2881 }
2882 bool
2883 TempoMap::remove_time (framepos_t where, framecnt_t amount)
2884 {
2885         bool moved = false;
2886
2887         std::list<MetricSection*> metric_kill_list;
2888
2889         TempoSection* last_tempo = NULL;
2890         MeterSection* last_meter = NULL;
2891         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
2892         bool meter_after = false; // is there a meter marker likewise?
2893         {
2894                 Glib::Threads::RWLock::WriterLock lm (lock);
2895                 for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
2896                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
2897                                 metric_kill_list.push_back(*i);
2898                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
2899                                 if (lt)
2900                                         last_tempo = lt;
2901                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
2902                                 if (lm)
2903                                         last_meter = lm;
2904                         }
2905                         else if ((*i)->frame() >= where) {
2906                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
2907                                 (*i)->set_frame ((*i)->frame() - amount);
2908                                 if ((*i)->frame() == where) {
2909                                         // marker was immediately after end of range
2910                                         tempo_after = dynamic_cast<TempoSection*> (*i);
2911                                         meter_after = dynamic_cast<MeterSection*> (*i);
2912                                 }
2913                                 moved = true;
2914                         }
2915                 }
2916
2917                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
2918                 if (last_tempo && !tempo_after) {
2919                         metric_kill_list.remove(last_tempo);
2920                         last_tempo->set_frame(where);
2921                         moved = true;
2922                 }
2923                 if (last_meter && !meter_after) {
2924                         metric_kill_list.remove(last_meter);
2925                         last_meter->set_frame(where);
2926                         moved = true;
2927                 }
2928
2929                 //remove all the remaining metrics
2930                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
2931                         _metrics.remove(*i);
2932                         moved = true;
2933                 }
2934
2935                 if (moved) {
2936                         recompute_map (_metrics);
2937                 }
2938         }
2939         PropertyChanged (PropertyChange ());
2940         return moved;
2941 }
2942
2943 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2944  *  pos can be -ve, if required.
2945  */
2946 framepos_t
2947 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
2948 {
2949         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
2950 }
2951
2952 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2953 framepos_t
2954 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2955 {
2956         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
2957 }
2958
2959 /** Add the BBT interval op to pos and return the result */
2960 framepos_t
2961 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2962 {
2963         Glib::Threads::RWLock::ReaderLock lm (lock);
2964
2965         BBT_Time pos_bbt = beats_to_bbt_locked (_metrics, beat_at_frame_locked (_metrics, pos));
2966         pos_bbt.ticks += op.ticks;
2967         if (pos_bbt.ticks >= BBT_Time::ticks_per_beat) {
2968                 ++pos_bbt.beats;
2969                 pos_bbt.ticks -= BBT_Time::ticks_per_beat;
2970         }
2971         pos_bbt.beats += op.beats;
2972         /* the meter in effect will start on the bar */
2973         double divisions_per_bar = meter_section_at (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
2974         while (pos_bbt.beats >= divisions_per_bar + 1) {
2975                 ++pos_bbt.bars;
2976                 divisions_per_bar = meter_section_at (bbt_to_beats_locked (_metrics, BBT_Time (pos_bbt.bars + op.bars, 1, 0))).divisions_per_bar();
2977                 pos_bbt.beats -= divisions_per_bar;
2978         }
2979         pos_bbt.bars += op.bars;
2980
2981         return frame_time_locked (_metrics, pos_bbt);
2982 }
2983
2984 /** Count the number of beats that are equivalent to distance when going forward,
2985     starting at pos.
2986 */
2987 Evoral::Beats
2988 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2989 {
2990         return Evoral::Beats (beat_at_frame (pos + distance) - beat_at_frame (pos));
2991 }
2992
2993 struct bbtcmp {
2994     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2995             return a < b;
2996     }
2997 };
2998
2999 std::ostream&
3000 operator<< (std::ostream& o, const Meter& m) {
3001         return o << m.divisions_per_bar() << '/' << m.note_divisor();
3002 }
3003
3004 std::ostream&
3005 operator<< (std::ostream& o, const Tempo& t) {
3006         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
3007 }
3008
3009 std::ostream&
3010 operator<< (std::ostream& o, const MetricSection& section) {
3011
3012         o << "MetricSection @ " << section.frame() << ' ';
3013
3014         const TempoSection* ts;
3015         const MeterSection* ms;
3016
3017         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
3018                 o << *((const Tempo*) ts);
3019         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
3020                 //o << *((const Meter*) ms);
3021         }
3022
3023         return o;
3024 }