Tempo ramps - fix odd display when dragging one tempo past another.
[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 #include "pbd/xml++.h"
28 #include "evoral/Beats.hpp"
29 #include "ardour/debug.h"
30 #include "ardour/lmath.h"
31 #include "ardour/tempo.h"
32
33 #include "i18n.h"
34 #include <locale.h>
35
36 using namespace std;
37 using namespace ARDOUR;
38 using namespace PBD;
39
40 using Timecode::BBT_Time;
41
42 /* _default tempo is 4/4 qtr=120 */
43
44 Meter    TempoMap::_default_meter (4.0, 4.0);
45 Tempo    TempoMap::_default_tempo (120.0);
46
47 /***********************************************************************/
48
49 double
50 Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
51 {
52         /* This is tempo- and meter-sensitive. The number it returns
53            is based on the interval between any two lines in the
54            grid that is constructed from tempo and meter sections.
55
56            The return value IS NOT interpretable in terms of "beats".
57         */
58
59         return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
60 }
61
62 double
63 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
64 {
65         return frames_per_grid (tempo, sr) * _divisions_per_bar;
66 }
67
68
69 /***********************************************************************/
70
71 const string TempoSection::xml_state_node_name = "Tempo";
72
73 TempoSection::TempoSection (const XMLNode& node)
74         : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
75 {
76         const XMLProperty *prop;
77         BBT_Time start;
78         LocaleGuard lg;
79
80         if ((prop = node.property ("start")) == 0) {
81                 error << _("TempoSection XML node has no \"start\" property") << endmsg;
82                 throw failed_constructor();
83         }
84
85         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
86                     &start.bars,
87                     &start.beats,
88                     &start.ticks) < 3) {
89                 error << _("TempoSection XML node has an illegal \"start\" value") << endmsg;
90                 throw failed_constructor();
91         }
92
93         set_start (start);
94
95         if ((prop = node.property ("beats-per-minute")) == 0) {
96                 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
97                 throw failed_constructor();
98         }
99
100         if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
101                 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
102                 throw failed_constructor();
103         }
104
105         if ((prop = node.property ("note-type")) == 0) {
106                 /* older session, make note type be quarter by default */
107                 _note_type = 4.0;
108         } else {
109                 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
110                         error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
111                         throw failed_constructor();
112                 }
113         }
114
115         if ((prop = node.property ("movable")) == 0) {
116                 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
117                 throw failed_constructor();
118         }
119
120         set_movable (string_is_affirmative (prop->value()));
121
122         if ((prop = node.property ("bar-offset")) == 0) {
123                 _bar_offset = -1.0;
124         } else {
125                 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
126                         error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
127                         throw failed_constructor();
128                 }
129         }
130
131         if ((prop = node.property ("tempo-type")) == 0) {
132                 _type = Type::Constant;
133         } else {
134                 if (strstr(prop->value().c_str(),"Constant")) {
135                         _type = Type::Constant;
136                 } else {
137                         _type = Type::Ramp;
138                 }
139         }
140 }
141
142 XMLNode&
143 TempoSection::get_state() const
144 {
145         XMLNode *root = new XMLNode (xml_state_node_name);
146         char buf[256];
147         LocaleGuard lg;
148
149         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
150                   start().bars,
151                   start().beats,
152                   start().ticks);
153         root->add_property ("start", buf);
154         snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
155         root->add_property ("beats-per-minute", buf);
156         snprintf (buf, sizeof (buf), "%f", _note_type);
157         root->add_property ("note-type", buf);
158         // snprintf (buf, sizeof (buf), "%f", _bar_offset);
159         // root->add_property ("bar-offset", buf);
160         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
161         root->add_property ("movable", buf);
162
163         snprintf (buf, sizeof (buf), "%s", _type == Constant?"Constant":"Ramp");
164         root->add_property ("tempo-type", buf);
165
166         return *root;
167 }
168
169 void
170
171 TempoSection::update_bar_offset_from_bbt (const Meter& m)
172 {
173         _bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_beat + start().ticks) /
174                 (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
175
176         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar()));
177 }
178
179 void
180 TempoSection::set_type (Type type)
181 {
182         _type = type;
183 }
184
185 double
186 TempoSection::tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
187 {
188
189         if (_type == Constant) {
190                 return beats_per_minute();
191         }
192
193         return tick_tempo_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)) / BBT_Time::ticks_per_beat;
194 }
195
196 framepos_t
197 TempoSection::frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
198 {
199         if (_type == Constant) {
200                 return 0;
201         }
202
203         return minute_to_frame (time_at_tick_tempo (tempo *  BBT_Time::ticks_per_beat,  end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
204 }
205
206 double
207 TempoSection::tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
208 {
209         if (_type == Constant) {
210                 return (frame / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat;
211         }
212
213         return tick_at_time (frame_to_minute (frame, frame_rate), end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate));
214 }
215
216 framepos_t
217 TempoSection::frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
218 {
219         if (_type == Constant) {
220                 return (framepos_t) floor ((tick  / BBT_Time::ticks_per_beat) * frames_per_beat (frame_rate));
221         }
222
223         return minute_to_frame (time_at_tick (tick, end_bpm *  BBT_Time::ticks_per_beat, frame_to_minute (end_frame, frame_rate)), frame_rate);
224 }
225
226 double TempoSection::beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
227 {
228         return tick_at_frame (frame, end_bpm, end_frame, frame_rate) / BBT_Time::ticks_per_beat;
229 }
230
231 framepos_t TempoSection::frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
232 {
233         return frame_at_tick (beat * BBT_Time::ticks_per_beat, end_bpm, end_frame, frame_rate);
234 }
235
236 framecnt_t
237 TempoSection::minute_to_frame (double time, framecnt_t frame_rate) const
238 {
239         return time * 60.0 * frame_rate;
240 }
241
242 double
243 TempoSection::frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const
244 {
245         return (frame / (double) frame_rate) / 60.0;
246 }
247
248 /* constant for exp */
249 double
250 TempoSection::a_func (double begin_tpm, double end_tpm, double end_time) const
251 {
252         return log (end_tpm / ticks_per_minute()) /  c_func (end_tpm, end_time);
253 }
254 double
255 TempoSection::c_func (double end_tpm, double end_time) const
256 {
257         return log (end_tpm / ticks_per_minute()) /  end_time;
258 }
259
260 /* tempo in tpm at time in minutes */
261 double
262 TempoSection::tick_tempo_at_time (double time, double end_tpm, double end_time) const
263 {
264         return exp (c_func (end_tpm, end_time) * time) * ticks_per_minute();
265 }
266
267 /* time in minutes at tempo in tpm */
268 double
269 TempoSection::time_at_tick_tempo (double tick_tempo, double end_tpm, double end_time) const
270 {
271         return log (tick_tempo / ticks_per_minute()) / c_func (end_tpm, end_time);
272 }
273
274 /* tempo in bpm at time in minutes */
275 double
276 TempoSection::tempo_at_time (double time, double end_bpm, double end_time) const
277 {
278         return tick_tempo_at_time (time, end_bpm *  BBT_Time::ticks_per_beat, end_time) / BBT_Time::ticks_per_beat;
279 }
280
281 /* time in minutes at tempo in bpm */
282 double
283 TempoSection::time_at_tempo (double tempo, double end_bpm, double end_time) const
284 {
285         return time_at_tick_tempo (tempo * BBT_Time::ticks_per_beat, end_bpm * BBT_Time::ticks_per_beat, end_time);
286 }
287
288 /* tick at time in minutes */
289 double
290 TempoSection::tick_at_time (double time, double end_tpm, double end_time) const
291 {
292         return ((exp (c_func (end_tpm, end_time) * time)) - 1) * ticks_per_minute() / c_func (end_tpm, end_time);
293 }
294
295 /* time in minutes at tick */
296 double
297 TempoSection::time_at_tick (double tick, double end_tpm, double end_time) const
298 {
299         return log (((c_func (end_tpm, end_time) * tick) / ticks_per_minute()) + 1) / c_func (end_tpm, end_time);
300 }
301
302 /* beat at time in minutes */
303 double
304 TempoSection::beat_at_time (double time, double end_tpm, double end_time) const
305 {
306         return tick_at_time (time, end_tpm, end_time) / BBT_Time::ticks_per_beat;
307 }
308
309 /* time in munutes at beat */
310 double
311 TempoSection::time_at_beat (double beat, double end_tpm, double end_time) const
312 {
313         return time_at_tick (beat * BBT_Time::ticks_per_beat, end_tpm, end_time);
314 }
315
316 void
317 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
318 {
319         BBT_Time new_start;
320
321         if (_bar_offset < 0.0) {
322                 /* not set yet */
323                 return;
324         }
325
326         new_start.bars = start().bars;
327
328         double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
329         new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
330         //new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
331         new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat);
332
333         /* remember the 1-based counting properties of beats */
334         new_start.beats += 1;
335         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
336                                                        _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
337
338         set_start (new_start);
339 }
340
341 /***********************************************************************/
342
343 const string MeterSection::xml_state_node_name = "Meter";
344
345 MeterSection::MeterSection (const XMLNode& node)
346         : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
347 {
348         XMLProperty const * prop;
349         BBT_Time start;
350         LocaleGuard lg;
351
352         if ((prop = node.property ("start")) == 0) {
353                 error << _("MeterSection XML node has no \"start\" property") << endmsg;
354                 throw failed_constructor();
355         }
356
357         if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
358                     &start.bars,
359                     &start.beats,
360                     &start.ticks) < 3) {
361                 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
362                 throw failed_constructor();
363         }
364
365         set_start (start);
366
367         /* beats-per-bar is old; divisions-per-bar is new */
368
369         if ((prop = node.property ("divisions-per-bar")) == 0) {
370                 if ((prop = node.property ("beats-per-bar")) == 0) {
371                         error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
372                         throw failed_constructor();
373                 }
374         }
375
376         if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
377                 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
378                 throw failed_constructor();
379         }
380
381         if ((prop = node.property ("note-type")) == 0) {
382                 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
383                 throw failed_constructor();
384         }
385
386         if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
387                 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
388                 throw failed_constructor();
389         }
390
391         if ((prop = node.property ("movable")) == 0) {
392                 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
393                 throw failed_constructor();
394         }
395
396         set_movable (string_is_affirmative (prop->value()));
397 }
398
399 XMLNode&
400 MeterSection::get_state() const
401 {
402         XMLNode *root = new XMLNode (xml_state_node_name);
403         char buf[256];
404         LocaleGuard lg;
405
406         snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
407                   start().bars,
408                   start().beats,
409                   start().ticks);
410         root->add_property ("start", buf);
411         snprintf (buf, sizeof (buf), "%f", _note_type);
412         root->add_property ("note-type", buf);
413         snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
414         root->add_property ("divisions-per-bar", buf);
415         snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
416         root->add_property ("movable", buf);
417
418         return *root;
419 }
420
421 /***********************************************************************/
422
423 struct MetricSectionSorter {
424     bool operator() (const MetricSection* a, const MetricSection* b) {
425             return a->start() < b->start();
426     }
427 };
428
429 TempoMap::TempoMap (framecnt_t fr)
430 {
431         _frame_rate = fr;
432         BBT_Time start;
433
434         start.bars = 1;
435         start.beats = 1;
436         start.ticks = 0;
437
438         TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Type::Ramp);
439         MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
440
441         t->set_movable (false);
442         m->set_movable (false);
443
444         /* note: frame time is correct (zero) for both of these */
445
446         metrics.push_back (t);
447         metrics.push_back (m);
448
449 }
450
451 TempoMap::~TempoMap ()
452 {
453 }
454
455 void
456 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
457 {
458         bool removed = false;
459
460         {
461                 Glib::Threads::RWLock::WriterLock lm (lock);
462                 if ((removed = remove_tempo_locked (tempo))) {
463                         if (complete_operation) {
464                                 recompute_map (true);
465                         }
466                 }
467         }
468
469         if (removed && complete_operation) {
470                 PropertyChanged (PropertyChange ());
471         }
472 }
473
474 bool
475 TempoMap::remove_tempo_locked (const TempoSection& tempo)
476 {
477         Metrics::iterator i;
478
479         for (i = metrics.begin(); i != metrics.end(); ++i) {
480                 if (dynamic_cast<TempoSection*> (*i) != 0) {
481                         if (tempo.frame() == (*i)->frame()) {
482                                 if ((*i)->movable()) {
483                                         metrics.erase (i);
484                                         return true;
485                                 }
486                         }
487                 }
488         }
489
490         return false;
491 }
492
493 void
494 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
495 {
496         bool removed = false;
497
498         {
499                 Glib::Threads::RWLock::WriterLock lm (lock);
500                 if ((removed = remove_meter_locked (tempo))) {
501                         if (complete_operation) {
502                                 recompute_map (true);
503                         }
504                 }
505         }
506
507         if (removed && complete_operation) {
508                 PropertyChanged (PropertyChange ());
509         }
510 }
511
512 bool
513 TempoMap::remove_meter_locked (const MeterSection& tempo)
514 {
515         Metrics::iterator i;
516
517         for (i = metrics.begin(); i != metrics.end(); ++i) {
518                 if (dynamic_cast<MeterSection*> (*i) != 0) {
519                         if (tempo.frame() == (*i)->frame()) {
520                                 if ((*i)->movable()) {
521                                         metrics.erase (i);
522                                         return true;
523                                 }
524                         }
525                 }
526         }
527
528         return false;
529 }
530
531 void
532 TempoMap::do_insert (MetricSection* section)
533 {
534         bool need_add = true;
535
536         /* we only allow new meters to be inserted on beat 1 of an existing
537          * measure.
538          */
539
540         if (dynamic_cast<MeterSection*>(section)) {
541                 assert (section->start().ticks == 0);
542
543                 /* we need to (potentially) update the BBT times of tempo
544                    sections based on this new meter.
545                 */
546
547                 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
548
549                         BBT_Time corrected = section->start();
550                         corrected.beats = 1;
551                         corrected.ticks = 0;
552
553                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
554                                                    section->start(), corrected) << endmsg;
555
556                         section->set_start (corrected);
557                 }
558         }
559
560
561
562         /* Look for any existing MetricSection that is of the same type and
563            in the same bar as the new one, and remove it before adding
564            the new one. Note that this means that if we find a matching,
565            existing section, we can break out of the loop since we're
566            guaranteed that there is only one such match.
567         */
568
569         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
570
571                 bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0;
572                 bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0;
573
574                 if (iter_is_tempo && insert_is_tempo) {
575
576                         /* Tempo sections */
577
578                         if ((*i)->start().bars == section->start().bars &&
579                             (*i)->start().beats == section->start().beats) {
580
581                                 if (!(*i)->movable()) {
582
583                                         /* can't (re)move this section, so overwrite
584                                          * its data content (but not its properties as
585                                          * a section).
586                                          */
587
588                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section));
589                                         need_add = false;
590                                 } else {
591                                         metrics.erase (i);
592                                 }
593                                 break;
594                         }
595
596                 } else if (!iter_is_tempo && !insert_is_tempo) {
597
598                         /* Meter Sections */
599
600                         if ((*i)->start().bars == section->start().bars) {
601
602                                 if (!(*i)->movable()) {
603
604                                         /* can't (re)move this section, so overwrite
605                                          * its data content (but not its properties as
606                                          * a section
607                                          */
608
609                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section));
610                                         need_add = false;
611                                 } else {
612                                         metrics.erase (i);
613
614                                 }
615
616                                 break;
617                         }
618                 } else {
619                         /* non-matching types, so we don't care */
620                 }
621         }
622
623         /* Add the given MetricSection, if we didn't just reset an existing
624          * one above
625          */
626
627         if (need_add) {
628
629                 Metrics::iterator i;
630
631                 for (i = metrics.begin(); i != metrics.end(); ++i) {
632                         if ((*i)->start() > section->start()) {
633                                 break;
634                         }
635                 }
636
637                 metrics.insert (i, section);
638         }
639 }
640
641 void
642 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where, TempoSection::Type type)
643 {
644         {
645                 Glib::Threads::RWLock::WriterLock lm (lock);
646                 TempoSection& first (first_tempo());
647
648                 if (ts.start() != first.start()) {
649                         remove_tempo_locked (ts);
650                         add_tempo_locked (tempo, where, true, type);
651                 } else {
652                         first.set_type (type);
653                         {
654                                 /* cannot move the first tempo section */
655                                 *static_cast<Tempo*>(&first) = tempo;
656                                 recompute_map (false);
657                         }
658                 }
659         }
660
661         PropertyChanged (PropertyChange ());
662 }
663
664 void
665 TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame)
666 {
667         {
668                 TempoSection& first (first_tempo());
669
670                 if (ts.start() != first.start()) {
671                         BBT_Time bbt;
672                         bbt_time (frame, bbt);
673                         {
674                                 Glib::Threads::RWLock::WriterLock lm (lock);
675                                 ts.set_frame (frame);
676                                 ts.set_start (bbt);
677
678                                 recompute_map (false);
679                         }
680                 }
681         }
682
683         MetricPositionChanged (); // Emit Signal
684 }
685
686 void
687 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type)
688 {
689         {
690                 Glib::Threads::RWLock::WriterLock lm (lock);
691                 add_tempo_locked (tempo, where, true, type);
692         }
693
694
695         PropertyChanged (PropertyChange ());
696 }
697
698 void
699 TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, ARDOUR::TempoSection::Type type)
700 {
701         TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
702
703         /* find the meter to use to set the bar offset of this
704          * tempo section.
705          */
706
707         const Meter* meter = &first_meter();
708
709         /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
710            at something, because we insert the default tempo and meter during
711            TempoMap construction.
712
713            now see if we can find better candidates.
714         */
715
716         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
717
718                 const MeterSection* m;
719
720                 if (where < (*i)->start()) {
721                         break;
722                 }
723
724                 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
725                         meter = m;
726                 }
727         }
728
729         ts->update_bar_offset_from_bbt (*meter);
730
731         /* and insert it */
732
733         do_insert (ts);
734
735         if (recompute) {
736                 recompute_map (false);
737         }
738 }
739
740 void
741 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
742 {
743         {
744                 Glib::Threads::RWLock::WriterLock lm (lock);
745                 MeterSection& first (first_meter());
746
747                 if (ms.start() != first.start()) {
748                         remove_meter_locked (ms);
749                         add_meter_locked (meter, where, true);
750                 } else {
751                         /* cannot move the first meter section */
752                         *static_cast<Meter*>(&first) = meter;
753                         recompute_map (true);
754                 }
755         }
756
757         PropertyChanged (PropertyChange ());
758 }
759
760 void
761 TempoMap::add_meter (const Meter& meter, BBT_Time where)
762 {
763         {
764                 Glib::Threads::RWLock::WriterLock lm (lock);
765                 add_meter_locked (meter, where, true);
766         }
767
768
769 #ifndef NDEBUG
770         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
771                 dump (std::cerr);
772         }
773 #endif
774
775         PropertyChanged (PropertyChange ());
776 }
777
778 void
779 TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
780 {
781         /* a new meter always starts a new bar on the first beat. so
782            round the start time appropriately. remember that
783            `where' is based on the existing tempo map, not
784            the result after we insert the new meter.
785
786         */
787
788         if (where.beats != 1) {
789                 where.beats = 1;
790                 where.bars++;
791         }
792
793         /* new meters *always* start on a beat. */
794         where.ticks = 0;
795
796         do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
797
798         if (recompute) {
799                 recompute_map (true);
800         }
801
802 }
803
804 void
805 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
806 {
807         Tempo newtempo (beats_per_minute, note_type);
808         TempoSection* t;
809
810         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
811                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
812                         {
813                                 Glib::Threads::RWLock::WriterLock lm (lock);
814                                 *((Tempo*) t) = newtempo;
815                                 recompute_map (false);
816                         }
817                         PropertyChanged (PropertyChange ());
818                         break;
819                 }
820         }
821 }
822
823 void
824 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
825 {
826         Tempo newtempo (beats_per_minute, note_type);
827
828         TempoSection* prev;
829         TempoSection* first;
830         Metrics::iterator i;
831
832         /* find the TempoSection immediately preceding "where"
833          */
834
835         for (first = 0, i = metrics.begin(), prev = 0; i != metrics.end(); ++i) {
836
837                 if ((*i)->frame() > where) {
838                         break;
839                 }
840
841                 TempoSection* t;
842
843                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
844                         if (!first) {
845                                 first = t;
846                         }
847                         prev = t;
848                 }
849         }
850
851         if (!prev) {
852                 if (!first) {
853                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
854                         return;
855                 }
856
857                 prev = first;
858         }
859
860         /* reset */
861
862         {
863                 Glib::Threads::RWLock::WriterLock lm (lock);
864                 /* cannot move the first tempo section */
865                 *((Tempo*)prev) = newtempo;
866                 recompute_map (false);
867         }
868
869         PropertyChanged (PropertyChange ());
870 }
871
872 const MeterSection&
873 TempoMap::first_meter () const
874 {
875         const MeterSection *m = 0;
876
877         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
878                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
879                         return *m;
880                 }
881         }
882
883         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
884         abort(); /*NOTREACHED*/
885         return *m;
886 }
887
888 MeterSection&
889 TempoMap::first_meter ()
890 {
891         MeterSection *m = 0;
892
893         /* CALLER MUST HOLD LOCK */
894
895         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
896                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
897                         return *m;
898                 }
899         }
900
901         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
902         abort(); /*NOTREACHED*/
903         return *m;
904 }
905
906 const TempoSection&
907 TempoMap::first_tempo () const
908 {
909         const TempoSection *t = 0;
910
911         /* CALLER MUST HOLD LOCK */
912
913         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
914                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
915                         return *t;
916                 }
917         }
918
919         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
920         abort(); /*NOTREACHED*/
921         return *t;
922 }
923
924 TempoSection&
925 TempoMap::first_tempo ()
926 {
927         TempoSection *t = 0;
928
929         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
930                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
931                         return *t;
932                 }
933         }
934
935         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
936         abort(); /*NOTREACHED*/
937         return *t;
938 }
939
940 void
941 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
942 {
943         /* CALLER MUST HOLD WRITE LOCK */
944
945         MeterSection* meter = 0;
946         TempoSection* tempo = 0;
947         double current_frame;
948         BBT_Time current;
949         Metrics::iterator next_metric;
950
951         if (end < 0) {
952
953                 /* we will actually stop once we hit
954                    the last metric.
955                 */
956                 end = max_framepos;
957
958         }
959
960         MetricSectionSorter cmp;
961         metrics.sort (cmp);
962
963         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
964
965         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
966                 MeterSection* ms;
967
968                 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
969                         meter = ms;
970                         break;
971                 }
972         }
973
974         assert(meter);
975
976         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
977                 TempoSection* ts;
978
979                 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
980                         tempo = ts;
981                         break;
982                 }
983         }
984
985         assert(tempo);
986
987         /* assumes that the first meter & tempo are at frame zero */
988         current_frame = 0;
989         meter->set_frame (0);
990         tempo->set_frame (0);
991
992         /* assumes that the first meter & tempo are at 1|1|0 */
993         current.bars = 1;
994         current.beats = 1;
995         current.ticks = 0;
996         if (reassign_tempo_bbt) {
997
998                 MeterSection* rmeter = meter;
999
1000                 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
1001
1002                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1003
1004                         TempoSection* ts;
1005                         MeterSection* ms;
1006
1007                         if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
1008
1009                                 /* reassign the BBT time of this tempo section
1010                                  * based on its bar offset position.
1011                                  */
1012
1013                                 ts->update_bbt_time_from_bar_offset (*rmeter);
1014
1015                         } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
1016                                 rmeter = ms;
1017                         } else {
1018                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
1019                                 abort(); /*NOTREACHED*/
1020                         }
1021                 }
1022         }
1023
1024         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
1025
1026         next_metric = metrics.begin();
1027         ++next_metric; // skip meter (or tempo)
1028         ++next_metric; // skip tempo (or meter)
1029
1030         DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
1031
1032         if (end == 0) {
1033                 /* silly call from Session::process() during startup
1034                  */
1035                 return;
1036         }
1037
1038         _extend_map (tempo, meter, next_metric, current, current_frame, end);
1039 }
1040
1041 void
1042 TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
1043                        Metrics::iterator next_metric,
1044                        BBT_Time current, framepos_t current_frame, framepos_t end)
1045 {
1046         /* CALLER MUST HOLD WRITE LOCK */
1047
1048         uint32_t first_tick_in_new_meter = 0;
1049         Metrics::const_iterator i;
1050         Metrics::const_iterator mi;
1051
1052         TempoSection* prev_ts = tempo;
1053
1054         for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
1055                 MeterSection* m = 0;
1056
1057                 if ((m = dynamic_cast<MeterSection*> (*mi)) != 0) {
1058
1059                         if (m->start() >= prev_ts->start()) {
1060                                 first_tick_in_new_meter = ((((m->start().bars - 1) * meter->divisions_per_bar()) + (m->start().beats - 1)) * BBT_Time::ticks_per_beat) + m->start().ticks; // expressed in ticks from the previous meter
1061                                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1062                                         TempoSection* t;
1063
1064                                         if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1065
1066                                                 if (t->start() >= m->start() && t->start() > prev_ts->start()) {
1067                                                         //cerr << "new ts start bars = " << t->start().bars << " beats = " << t->start().beats << " ticks = " << t->start().ticks << endl;
1068                                                         //cerr << "prev ts start bars = " << prev_ts->start().bars << " beats = " << prev_ts->start().beats << " ticks = " << prev_ts->start().ticks << endl;
1069
1070                                                         /*tempo section (t) lies in the previous meter */
1071                                                         double const ticks_at_ts = ((((t->start().bars - 1 ) * meter->divisions_per_bar()) + (t->start().beats - 1) )  * BBT_Time::ticks_per_beat) + t->start().ticks;
1072                                                         double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1))  * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
1073                                                         double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
1074                                                         /* assume (falsely) that the target tempo is constant */
1075                                                         double length_estimate = (ticks_relative_to_prev_ts /  BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
1076                                                         if (prev_ts->type() == TempoSection::Type::Constant) {
1077                                                                 length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
1078                                                         }
1079                                                         cerr<< "initial length extimate = " << length_estimate << " ticks_relative_to_prev_ts " << ticks_relative_to_prev_ts << endl;
1080                                                         double const system_precision_at_target_tempo =  (_frame_rate / t->ticks_per_minute());
1081                                                         cerr << " system_precision_at_target_tempo = " << system_precision_at_target_tempo << endl;
1082                                                         double tick_error = system_precision_at_target_tempo + 1.0; // sorry for the wtf
1083
1084                                                         while (fabs (tick_error) >= system_precision_at_target_tempo) {
1085
1086                                                                 double const actual_ticks = prev_ts->tick_at_frame (length_estimate, t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate);
1087                                                                 tick_error = ticks_relative_to_prev_ts - actual_ticks;
1088                                                                 length_estimate += (tick_error / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
1089                                                                 //cerr << "actual ticks = " << actual_ticks << endl;
1090
1091                                                                 //cerr << "tick error  = " << tick_error << endl;
1092                                                         }
1093                                                         cerr << "setting t frame to " << length_estimate + prev_ts->frame() << " tick error  = " << tick_error << endl;
1094                                                         t->set_frame (length_estimate + prev_ts->frame());
1095
1096                                                         if (m->start() < t->start() && m->start() == prev_ts->start()) {
1097                                                                 m->set_frame (prev_ts->frame());
1098                                                         } else if (m->start() < t->start() && m->start() > prev_ts->start()) {
1099                                                                 cerr << "recompute map - setting meter frame to " << prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) << " ticks = " << first_tick_in_new_meter - ticks_at_prev_ts  << endl;
1100
1101                                                                 m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate));
1102                                                         }
1103                                                 }
1104                                                 prev_ts = t;
1105                                         }
1106                                 }
1107                         }
1108                         meter = m;
1109                 }
1110         }
1111 }
1112
1113
1114 TempoMetric
1115 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1116 {
1117         Glib::Threads::RWLock::ReaderLock lm (lock);
1118         TempoMetric m (first_meter(), first_tempo());
1119
1120         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1121            at something, because we insert the default tempo and meter during
1122            TempoMap construction.
1123
1124            now see if we can find better candidates.
1125         */
1126
1127         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1128
1129                 if ((*i)->frame() > frame) {
1130                         break;
1131                 }
1132
1133                 m.set_metric(*i);
1134
1135                 if (last) {
1136                         *last = i;
1137                 }
1138         }
1139
1140         return m;
1141 }
1142
1143 TempoMetric
1144 TempoMap::metric_at (BBT_Time bbt) const
1145 {
1146         Glib::Threads::RWLock::ReaderLock lm (lock);
1147         TempoMetric m (first_meter(), first_tempo());
1148
1149         /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1150            at something, because we insert the default tempo and meter during
1151            TempoMap construction.
1152
1153            now see if we can find better candidates.
1154         */
1155
1156         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1157
1158                 BBT_Time section_start ((*i)->start());
1159
1160                 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1161                         break;
1162                 }
1163
1164                 m.set_metric (*i);
1165         }
1166
1167         return m;
1168 }
1169
1170 void
1171 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1172 {
1173         Glib::Threads::RWLock::ReaderLock lm (lock);
1174
1175         if (frame < 0) {
1176                 bbt.bars = 1;
1177                 bbt.beats = 1;
1178                 bbt.ticks = 0;
1179                 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1180                 return;
1181         }
1182         bbt = beats_to_bbt (beat_at_frame (frame));
1183 }
1184
1185 int32_t
1186 TempoMap::bars_in_meter_section (MeterSection* ms) const
1187 {
1188         /* YOU MUST HAVE THE READ LOCK */
1189         Metrics::const_iterator i;
1190
1191         MeterSection* next_ms = 0;
1192         const MeterSection* prev_ms = &first_meter();
1193
1194         for (i = metrics.begin(); i != metrics.end(); ++i) {
1195                 MeterSection* m;
1196                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1197                         if (ms->frame() < m->frame()) {
1198                                 next_ms = m;
1199                                 break;
1200                         }
1201                         prev_ms = m;
1202                 }
1203         }
1204         if (next_ms) {
1205                 double ticks_at_next = tick_at_frame (next_ms->frame());
1206                 double ticks_at_prev = tick_at_frame (prev_ms->frame());
1207                 double ticks_in_meter = ticks_at_next - ticks_at_prev;
1208
1209                 return (int32_t) floor ((ticks_in_meter / BBT_Time::ticks_per_beat) / prev_ms->note_divisor());
1210         }
1211         return -1;
1212 }
1213
1214 Timecode::BBT_Time
1215 TempoMap::beats_to_bbt (double beats)
1216 {
1217         /* CALLER HOLDS READ LOCK */
1218         BBT_Time ret;
1219         MeterSection* prev_ms = &first_meter();
1220
1221         framecnt_t frame = frame_at_beat (beats);
1222         uint32_t cnt = 0;
1223         /* XX most of this is utter crap */
1224         if (n_meters() == 1) {
1225                 uint32_t bars = (uint32_t) floor (beats / prev_ms->note_divisor());
1226                 double remaining_beats = beats - (bars *  prev_ms->note_divisor());
1227                 double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1228
1229                 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1230                 ret.beats = (uint32_t) floor (remaining_beats);
1231                 ret.bars = bars;
1232
1233                 /* 0 0 0 to 1 1 0 - based mapping*/
1234                 ++ret.bars;
1235                 ++ret.beats;
1236
1237                 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1238                         ++ret.beats;
1239                         ret.ticks -= BBT_Time::ticks_per_beat;
1240                 }
1241
1242                 if (ret.beats > prev_ms->note_divisor()) {
1243                         ++ret.bars;
1244                         ret.beats = 1;
1245                 }
1246
1247                 return ret;
1248         }
1249
1250         uint32_t first_beat_in_meter = 0;
1251         uint32_t accumulated_bars = 0;
1252         Metrics::const_iterator i;
1253
1254         for (i = metrics.begin(); i != metrics.end(); ++i) {
1255                 MeterSection* m = 0;
1256
1257                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1258                         first_beat_in_meter = beat_at_frame (m->frame());
1259
1260                         if (beats < first_beat_in_meter) {
1261                                 /* this is the meter after the one our beat is on*/
1262                                 break;
1263                         }
1264                         int32_t const bars_in_ms = bars_in_meter_section (m);
1265
1266                         if (bars_in_ms > 0) {
1267                                 accumulated_bars += bars_in_ms;
1268                         }
1269
1270                         prev_ms = m;
1271                         ++cnt;
1272                 }
1273         }
1274         //cerr << "beats to bbr with beats = " << beats << " first_beat_in_meter =  " << first_beat_in_meter << " accumulated_bars = " << accumulated_bars <<  endl;
1275
1276         if (beats > first_beat_in_meter) {
1277                 /* prev_ms is the relevant one here */
1278
1279                 /* now get the ticks at frame */
1280                 double ticks_at_frame = tick_at_frame (frame);
1281
1282                 /* find the number of ticks at the beginning of the meter section (bar 1)*/
1283                 double ticks_at_ms = tick_at_frame (prev_ms->frame());
1284
1285                 double beats_used_by_ms = (ticks_at_frame - ticks_at_ms) / BBT_Time::ticks_per_beat;
1286
1287                 uint32_t bars = (uint32_t) floor (beats_used_by_ms / prev_ms->note_divisor());
1288                 double remaining_beats = beats_used_by_ms - (bars *  prev_ms->note_divisor());
1289                 double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1290
1291                 ret.bars = bars + accumulated_bars;
1292                 ret.beats = (uint32_t) floor (remaining_beats);
1293                 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1294
1295                 /* now ensure we srtart at 1 1 0 */
1296                 ++ret.bars;
1297                 ++ret.beats;
1298                 //cerr << "part 1 ret bars = " << ret.bars << " ret beats = " << ret.beats << " ret ticks = " << ret.ticks << endl;
1299                 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1300                         ++ret.beats;
1301                         ret.ticks -= BBT_Time::ticks_per_beat;
1302                 }
1303
1304                 if (ret.beats > prev_ms->note_divisor()) {
1305                         ++ret.bars;
1306                         ret.beats = 1;
1307                 }
1308
1309                 return ret;
1310         }
1311
1312         /* find the number of ticks at the beginning of the meter section (bar 1)*/
1313         double ticks_at_ms = tick_at_frame (prev_ms->frame());
1314
1315         /* now get the ticks at frame */
1316         double ticks_at_frame = tick_at_frame (frame);
1317
1318         double ticks_within_ms = ticks_at_frame - ticks_at_ms;
1319
1320         ret.bars = (uint32_t) floor (((ticks_within_ms / BBT_Time::ticks_per_beat) / prev_ms->note_divisor())) + accumulated_bars;
1321         uint32_t remaining_ticks = ticks_within_ms - (ret.bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat);
1322         ret.beats = (uint32_t) floor (remaining_ticks);
1323         remaining_ticks -= ret.beats * BBT_Time::ticks_per_beat;
1324
1325         /* only round ticks */
1326         ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1327
1328         /* now ensure we srtart at 1 1 0 */
1329         ++ret.bars;
1330         ++ret.beats;
1331         if (ret.ticks >= BBT_Time::ticks_per_beat) {
1332                 ++ret.beats;
1333                 ret.ticks -= BBT_Time::ticks_per_beat;
1334         }
1335
1336         if (ret.beats > prev_ms->note_divisor()) {
1337                 ++ret.bars;
1338                 ret.beats = 1;
1339         }
1340
1341         return ret;
1342 }
1343
1344 double
1345 TempoMap::tick_at_frame (framecnt_t frame) const
1346 {
1347         Glib::Threads::RWLock::ReaderLock lm (lock);
1348
1349         Metrics::const_iterator i;
1350         const TempoSection* prev_ts = &first_tempo();
1351         double accumulated_ticks = 0.0;
1352         uint32_t cnt = 0;
1353
1354         for (i = metrics.begin(); i != metrics.end(); ++i) {
1355                 TempoSection* t;
1356
1357                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1358
1359                         if (frame < t->frame()) {
1360                                 /*the previous ts is the one containing the frame */
1361
1362                                 framepos_t time = frame - prev_ts->frame();
1363                                 framepos_t last_frame = t->frame() - prev_ts->frame();
1364                                 double last_beats_per_minute = t->beats_per_minute();
1365
1366                                 return prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate) + accumulated_ticks;
1367                         }
1368
1369                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1370                                 framepos_t time = t->frame() - prev_ts->frame();
1371                                 framepos_t last_frame = t->frame() - prev_ts->frame();
1372                                 double last_beats_per_minute = t->beats_per_minute();
1373                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate);
1374                         }
1375
1376                         prev_ts = t;
1377                         ++cnt;
1378                 }
1379         }
1380
1381         /* treated s linear for this ts */
1382         framecnt_t frames_in_section = frame - prev_ts->frame();
1383         double ticks_in_section = (frames_in_section / prev_ts->frames_per_beat (_frame_rate)) * Timecode::BBT_Time::ticks_per_beat;
1384
1385         return ticks_in_section + accumulated_ticks;
1386
1387 }
1388
1389 framecnt_t
1390 TempoMap::frame_at_tick (double tick) const
1391 {
1392         /* HOLD THE READER LOCK */
1393
1394         double accumulated_ticks = 0.0;
1395         double accumulated_ticks_to_prev = 0.0;
1396
1397         const TempoSection* prev_ts =  &first_tempo();
1398         uint32_t cnt = 0;
1399
1400         Metrics::const_iterator i;
1401
1402         for (i = metrics.begin(); i != metrics.end(); ++i) {
1403                 TempoSection* t;
1404                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1405
1406                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1407                                 framepos_t time = t->frame() - prev_ts->frame();
1408                                 framepos_t last_time = t->frame() - prev_ts->frame();
1409                                 double last_beats_per_minute = t->beats_per_minute();
1410                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1411                         }
1412
1413                         if (tick < accumulated_ticks) {
1414                                 /* prev_ts is the one affecting us. */
1415
1416                                 double ticks_in_section = tick - accumulated_ticks_to_prev;
1417                                 framepos_t section_start = prev_ts->frame();
1418                                 framepos_t last_time = t->frame() - prev_ts->frame();
1419                                 double last_beats_per_minute = t->beats_per_minute();
1420                                 return prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start;
1421                         }
1422                         accumulated_ticks_to_prev = accumulated_ticks;
1423
1424                         prev_ts = t;
1425                         ++cnt;
1426                 }
1427         }
1428         double ticks_in_section = tick - accumulated_ticks_to_prev;
1429         double dtime = (ticks_in_section / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1430         framecnt_t ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1431
1432         return ret;
1433 }
1434
1435 double
1436 TempoMap::beat_at_frame (framecnt_t frame) const
1437 {
1438         Glib::Threads::RWLock::ReaderLock lm (lock);
1439
1440         return tick_at_frame (frame) / BBT_Time::ticks_per_beat;
1441 }
1442
1443 framecnt_t
1444 TempoMap::frame_at_beat (double beat) const
1445 {
1446         Glib::Threads::RWLock::ReaderLock lm (lock);
1447
1448         return frame_at_tick (beat * BBT_Time::ticks_per_beat);
1449 }
1450
1451 framepos_t
1452 TempoMap::frame_time (const BBT_Time& bbt)
1453 {
1454         if (bbt.bars < 1) {
1455                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1456                 return 0;
1457         }
1458
1459         if (bbt.beats < 1) {
1460                 throw std::logic_error ("beats are counted from one");
1461         }
1462
1463         Glib::Threads::RWLock::ReaderLock lm (lock);
1464
1465         Metrics::const_iterator i;
1466         uint32_t accumulated_bars = 0;
1467
1468         MeterSection* prev_ms = &first_meter();
1469
1470         for (i = metrics.begin(); i != metrics.end(); ++i) {
1471                 MeterSection* m;
1472                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1473                         int32_t const bims = bars_in_meter_section (m);
1474
1475                         if (bims < 0 || bbt.bars <= (accumulated_bars + bims)) {
1476                                 break;
1477                         }
1478                         if (bims > 0 ) {
1479                                 accumulated_bars += bims;
1480                         }
1481                         prev_ms = m;
1482                 }
1483         }
1484
1485         uint32_t remaining_bars = bbt.bars - accumulated_bars - 1; // back to zero - based bars
1486         double const ticks_within_prev_taken_by_remaining_bars = remaining_bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat;
1487         double const ticks_after_space_used_by_bars = ((bbt.beats - 1) * BBT_Time::ticks_per_beat) + bbt.ticks; // back to zero - based beats
1488         double const ticks_target = ticks_within_prev_taken_by_remaining_bars + ticks_after_space_used_by_bars;
1489
1490         TempoSection* prev_ts = &first_tempo();
1491         double accumulated_ticks = 0.0;
1492         double accumulated_ticks_to_prev = 0.0;
1493
1494         uint32_t cnt = 0;
1495
1496         for (i = metrics.begin(); i != metrics.end(); ++i) {
1497                 TempoSection* t;
1498                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1499                         if (t->frame() < prev_ms->frame()) {
1500                                 continue;
1501                         }
1502
1503                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1504                                 /*find the number of ticke in this section */
1505                                 framepos_t const time = t->frame() - prev_ts->frame();
1506                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1507                                 double const last_beats_per_minute = t->beats_per_minute();
1508                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1509                         }
1510
1511                         if (ticks_target < accumulated_ticks) {
1512                                 double const ticks_in_section = ticks_target - accumulated_ticks_to_prev;
1513                                 framepos_t const section_start_time = prev_ts->frame();
1514                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1515                                 double const last_beats_per_minute = t->beats_per_minute();
1516                                 framepos_t const ret = prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start_time;
1517                                 return ret;
1518                         }
1519                         accumulated_ticks_to_prev = accumulated_ticks;
1520                         prev_ts = t;
1521                         ++cnt;
1522                 }
1523         }
1524
1525         /*treat this ts as constant tempo */
1526         double const ticks_in_this_ts = ticks_target - accumulated_ticks_to_prev;
1527         double const dtime = (ticks_in_this_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1528         framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1529         return ret;
1530 }
1531
1532
1533 framecnt_t
1534 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1535 {
1536
1537         Glib::Threads::RWLock::ReaderLock lm (lock);
1538
1539         Metrics::const_iterator i;
1540         TempoSection* first = 0;
1541         TempoSection* second = 0;
1542
1543         for (i = metrics.begin(); i != metrics.end(); ++i) {
1544                 TempoSection* t;
1545
1546                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1547
1548                         if ((*i)->frame() > pos) {
1549                                 second = t;
1550                                 break;
1551                         }
1552
1553                         first = t;
1554                 }
1555         }
1556         if (first && second) {
1557                 framepos_t const last_time = second->frame() - first->frame();
1558                 double const last_beats_per_minute = second->beats_per_minute();
1559
1560                 framepos_t const time = pos - first->frame();
1561                 double const tick_at_time = first->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1562                 double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1563
1564                 double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, last_beats_per_minute, last_time, _frame_rate);
1565
1566                 return time_at_bbt - time;
1567         }
1568
1569         double const ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1570         return (framecnt_t) floor ((ticks / BBT_Time::ticks_per_beat) * first->frames_per_beat(_frame_rate));
1571 }
1572
1573 framepos_t
1574 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
1575 {
1576         return round_to_type (fr, dir, Bar);
1577 }
1578
1579 framepos_t
1580 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
1581 {
1582         return round_to_type (fr, dir, Beat);
1583 }
1584
1585 framepos_t
1586 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
1587 {
1588         Glib::Threads::RWLock::ReaderLock lm (lock);
1589
1590         uint32_t ticks = (uint32_t) floor (tick_at_frame (fr) + 0.5);
1591         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
1592         uint32_t ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1593
1594         ticks -= beats * BBT_Time::ticks_per_beat;
1595
1596         if (dir > 0) {
1597                 /* round to next (or same iff dir == RoundUpMaybe) */
1598
1599                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
1600
1601                 if (mod == 0 && dir == RoundUpMaybe) {
1602                         /* right on the subdivision, which is fine, so do nothing */
1603
1604                 } else if (mod == 0) {
1605                         /* right on the subdivision, so the difference is just the subdivision ticks */
1606                         ticks += ticks_one_subdivisions_worth;
1607
1608                 } else {
1609                         /* not on subdivision, compute distance to next subdivision */
1610
1611                         ticks += ticks_one_subdivisions_worth - mod;
1612                 }
1613
1614                 if (ticks >= BBT_Time::ticks_per_beat) {
1615                         ticks -= BBT_Time::ticks_per_beat;
1616                 }
1617         } else if (dir < 0) {
1618
1619                 /* round to previous (or same iff dir == RoundDownMaybe) */
1620
1621                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
1622
1623                 if (difference == 0 && dir == RoundDownAlways) {
1624                         /* right on the subdivision, but force-rounding down,
1625                            so the difference is just the subdivision ticks */
1626                         difference = ticks_one_subdivisions_worth;
1627                 }
1628
1629                 if (ticks < difference) {
1630                         ticks = BBT_Time::ticks_per_beat - ticks;
1631                 } else {
1632                         ticks -= difference;
1633                 }
1634
1635         } else {
1636                 /* round to nearest */
1637                 double rem;
1638
1639                 /* compute the distance to the previous and next subdivision */
1640
1641                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1642
1643                         /* closer to the next subdivision, so shift forward */
1644
1645                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
1646
1647                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
1648
1649                         if (ticks > BBT_Time::ticks_per_beat) {
1650                                 ++beats;
1651                                 ticks -= BBT_Time::ticks_per_beat;
1652                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
1653                         }
1654
1655                 } else if (rem > 0) {
1656
1657                         /* closer to previous subdivision, so shift backward */
1658
1659                         if (rem > ticks) {
1660                                 if (beats == 0) {
1661                                         /* can't go backwards past zero, so ... */
1662                                         return 0;
1663                                 }
1664                                 /* step back to previous beat */
1665                                 --beats;
1666                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
1667                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
1668                         } else {
1669                                 ticks = lrint (ticks - rem);
1670                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
1671                         }
1672                 } else {
1673                         /* on the subdivision, do nothing */
1674                 }
1675         }
1676         return frame_at_tick ((beats * BBT_Time::ticks_per_beat) + ticks);
1677 }
1678
1679 framepos_t
1680 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
1681 {
1682         Glib::Threads::RWLock::ReaderLock lm (lock);
1683
1684         double const beat_at_framepos = beat_at_frame (frame);
1685
1686         BBT_Time bbt (beats_to_bbt (beat_at_framepos));
1687
1688         switch (type) {
1689         case Bar:
1690                 if (dir < 0) {
1691                         /* find bar previous to 'frame' */
1692                         bbt.beats = 1;
1693                         bbt.ticks = 0;
1694                         return frame_time (bbt);
1695
1696                 } else if (dir > 0) {
1697                         /* find bar following 'frame' */
1698                         ++bbt.bars;
1699                         bbt.beats = 1;
1700                         bbt.ticks = 0;
1701                         return frame_time (bbt);
1702                 } else {
1703                         /* true rounding: find nearest bar */
1704                         framepos_t raw_ft = frame_time (bbt);
1705                         bbt.beats = 1;
1706                         bbt.ticks = 0;
1707                         framepos_t prev_ft = frame_time (bbt);
1708                         ++bbt.bars;
1709                         framepos_t next_ft = frame_time (bbt);
1710
1711                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
1712                                 return next_ft;
1713                         } else {
1714                                 return prev_ft;
1715                         }
1716                 }
1717
1718                 break;
1719
1720         case Beat:
1721                 if (dir < 0) {
1722                         return frame_at_beat (floor (beat_at_framepos));
1723                 } else if (dir > 0) {
1724                         return frame_at_beat (ceil (beat_at_framepos));
1725                 } else {
1726                         return frame_at_beat (floor (beat_at_framepos + 0.5));
1727                 }
1728                 break;
1729         }
1730
1731         return 0;
1732 }
1733
1734 void
1735 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
1736                     framepos_t lower, framepos_t upper)
1737 {
1738         Glib::Threads::RWLock::ReaderLock lm (lock);
1739         uint32_t const upper_beat = (uint32_t) floor (beat_at_frame (upper));
1740         uint32_t cnt = (uint32_t) ceil (beat_at_frame (lower));
1741
1742         while (cnt <= upper_beat) {
1743                 framecnt_t const pos = frame_at_beat (cnt);
1744                 MeterSection const meter = meter_section_at (pos);
1745                 Tempo const tempo = tempo_at (pos);
1746                 BBT_Time const bbt = beats_to_bbt ((double) cnt);
1747
1748                 points.push_back (BBTPoint (meter, tempo, pos, bbt.bars, bbt.beats));
1749                 ++cnt;
1750         }
1751 }
1752
1753 TempoSection*
1754 TempoMap::tempo_section_after (framepos_t frame) const
1755 {
1756         Glib::Threads::RWLock::ReaderLock lm (lock);
1757
1758         Metrics::const_iterator i;
1759         TempoSection* next = 0;
1760
1761         for (i = metrics.begin(); i != metrics.end(); ++i) {
1762                 TempoSection* t;
1763
1764                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1765
1766                         if ((*i)->frame() > frame) {
1767                                 next = t;
1768                                 break;
1769                         }
1770                 }
1771         }
1772
1773         return next;
1774 }
1775
1776
1777 const TempoSection&
1778 TempoMap::tempo_section_at (framepos_t frame) const
1779 {
1780         Glib::Threads::RWLock::ReaderLock lm (lock);
1781
1782         Metrics::const_iterator i;
1783         TempoSection* prev = 0;
1784
1785         for (i = metrics.begin(); i != metrics.end(); ++i) {
1786                 TempoSection* t;
1787
1788                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1789
1790                         if ((*i)->frame() > frame) {
1791                                 break;
1792                         }
1793
1794                         prev = t;
1795                 }
1796         }
1797
1798         if (prev == 0) {
1799                 fatal << endmsg;
1800                 abort(); /*NOTREACHED*/
1801         }
1802
1803         return *prev;
1804 }
1805
1806 /* don't use this to calculate length (the tempo is only correct for this frame).
1807    do that stuff based on the beat_at_frame and frame_at_beat api
1808 */
1809 double
1810 TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const
1811 {
1812         Glib::Threads::RWLock::ReaderLock lm (lock);
1813
1814         const TempoSection* ts_at = &tempo_section_at (frame);
1815         const TempoSection* ts_after = tempo_section_after (frame);
1816
1817         if (ts_after) {
1818                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate));
1819         }
1820         /* must be treated as constant tempo */
1821         return ts_at->frames_per_beat (_frame_rate);
1822 }
1823
1824 const Tempo
1825 TempoMap::tempo_at (framepos_t frame) const
1826 {
1827         Glib::Threads::RWLock::ReaderLock lm (lock);
1828
1829         TempoMetric m (metric_at (frame));
1830         TempoSection* prev_ts = 0;
1831
1832         Metrics::const_iterator i;
1833
1834         for (i = metrics.begin(); i != metrics.end(); ++i) {
1835                 TempoSection* t;
1836                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1837                         if ((prev_ts) && t->frame() > frame) {
1838                                 /* this is the one past frame */
1839                                 framepos_t const time = frame - prev_ts->frame();
1840                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1841                                 double const last_beats_per_minute = t->beats_per_minute();
1842                                 double const ret = prev_ts->tempo_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1843                                 Tempo const ret_tempo (ret, m.tempo().note_type ());
1844                                 return ret_tempo;
1845                         }
1846                         prev_ts = t;
1847                 }
1848         }
1849
1850         return m.tempo();
1851
1852 }
1853
1854 const MeterSection&
1855 TempoMap::meter_section_at (framepos_t frame) const
1856 {
1857         Glib::Threads::RWLock::ReaderLock lm (lock);
1858         Metrics::const_iterator i;
1859         MeterSection* prev = 0;
1860
1861         for (i = metrics.begin(); i != metrics.end(); ++i) {
1862                 MeterSection* t;
1863
1864                 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1865
1866                         if ((*i)->frame() > frame) {
1867                                 break;
1868                         }
1869
1870                         prev = t;
1871                 }
1872         }
1873
1874         if (prev == 0) {
1875                 fatal << endmsg;
1876                 abort(); /*NOTREACHED*/
1877         }
1878
1879         return *prev;
1880 }
1881
1882 const Meter&
1883 TempoMap::meter_at (framepos_t frame) const
1884 {
1885         TempoMetric m (metric_at (frame));
1886         return m.meter();
1887 }
1888
1889 XMLNode&
1890 TempoMap::get_state ()
1891 {
1892         Metrics::const_iterator i;
1893         XMLNode *root = new XMLNode ("TempoMap");
1894
1895         {
1896                 Glib::Threads::RWLock::ReaderLock lm (lock);
1897                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1898                         root->add_child_nocopy ((*i)->get_state());
1899                 }
1900         }
1901
1902         return *root;
1903 }
1904
1905 int
1906 TempoMap::set_state (const XMLNode& node, int /*version*/)
1907 {
1908         {
1909                 Glib::Threads::RWLock::WriterLock lm (lock);
1910
1911                 XMLNodeList nlist;
1912                 XMLNodeConstIterator niter;
1913                 Metrics old_metrics (metrics);
1914                 MeterSection* last_meter = 0;
1915                 metrics.clear();
1916
1917                 nlist = node.children();
1918
1919                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1920                         XMLNode* child = *niter;
1921
1922                         if (child->name() == TempoSection::xml_state_node_name) {
1923
1924                                 try {
1925                                         TempoSection* ts = new TempoSection (*child);
1926                                         metrics.push_back (ts);
1927
1928                                         if (ts->bar_offset() < 0.0) {
1929                                                 if (last_meter) {
1930                                                         ts->update_bar_offset_from_bbt (*last_meter);
1931                                                 }
1932                                         }
1933                                 }
1934
1935                                 catch (failed_constructor& err){
1936                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1937                                         metrics = old_metrics;
1938                                         break;
1939                                 }
1940
1941                         } else if (child->name() == MeterSection::xml_state_node_name) {
1942
1943                                 try {
1944                                         MeterSection* ms = new MeterSection (*child);
1945                                         metrics.push_back (ms);
1946                                         last_meter = ms;
1947                                 }
1948
1949                                 catch (failed_constructor& err) {
1950                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1951                                         metrics = old_metrics;
1952                                         break;
1953                                 }
1954                         }
1955                 }
1956
1957                 if (niter == nlist.end()) {
1958                         MetricSectionSorter cmp;
1959                         metrics.sort (cmp);
1960                 }
1961
1962                 /* check for multiple tempo/meters at the same location, which
1963                    ardour2 somehow allowed.
1964                 */
1965
1966                 Metrics::iterator prev = metrics.end();
1967                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1968                         if (prev != metrics.end()) {
1969                                 if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
1970                                         if ((*prev)->start() == (*i)->start()) {
1971                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
1972                                                 error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
1973                                                 return -1;
1974                                         }
1975                                 } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
1976                                         if ((*prev)->start() == (*i)->start()) {
1977                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
1978                                                 error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
1979                                                 return -1;
1980                                         }
1981                                 }
1982                         }
1983                         prev = i;
1984                 }
1985
1986                 recompute_map (true, -1);
1987         }
1988
1989         PropertyChanged (PropertyChange ());
1990
1991         return 0;
1992 }
1993
1994 void
1995 TempoMap::dump (std::ostream& o) const
1996 {
1997         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1998         const MeterSection* m;
1999         const TempoSection* t;
2000
2001         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2002
2003                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2004                         o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (movable? "
2005                           << t->movable() << ')' << endl;
2006                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2007                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
2008                           << " (movable? " << m->movable() << ')' << endl;
2009                 }
2010         }
2011 }
2012
2013 int
2014 TempoMap::n_tempos() const
2015 {
2016         Glib::Threads::RWLock::ReaderLock lm (lock);
2017         int cnt = 0;
2018
2019         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2020                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
2021                         cnt++;
2022                 }
2023         }
2024
2025         return cnt;
2026 }
2027
2028 int
2029 TempoMap::n_meters() const
2030 {
2031         Glib::Threads::RWLock::ReaderLock lm (lock);
2032         int cnt = 0;
2033
2034         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2035                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
2036                         cnt++;
2037                 }
2038         }
2039
2040         return cnt;
2041 }
2042
2043 void
2044 TempoMap::insert_time (framepos_t where, framecnt_t amount)
2045 {
2046         {
2047                 Glib::Threads::RWLock::WriterLock lm (lock);
2048                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2049                         if ((*i)->frame() >= where && (*i)->movable ()) {
2050                                 (*i)->set_frame ((*i)->frame() + amount);
2051                         }
2052                 }
2053
2054                 /* now reset the BBT time of all metrics, based on their new
2055                  * audio time. This is the only place where we do this reverse
2056                  * timestamp.
2057                  */
2058
2059                 Metrics::iterator i;
2060                 const MeterSection* meter;
2061                 const TempoSection* tempo;
2062                 MeterSection *m;
2063                 TempoSection *t;
2064
2065                 meter = &first_meter ();
2066                 tempo = &first_tempo ();
2067
2068                 BBT_Time start;
2069                 BBT_Time end;
2070
2071                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
2072
2073                 bool first = true;
2074                 MetricSection* prev = 0;
2075
2076                 for (i = metrics.begin(); i != metrics.end(); ++i) {
2077
2078                         BBT_Time bbt;
2079                         TempoMetric metric (*meter, *tempo);
2080
2081                         if (prev) {
2082                                 metric.set_start (prev->start());
2083                                 metric.set_frame (prev->frame());
2084                         } else {
2085                                 // metric will be at frames=0 bbt=1|1|0 by default
2086                                 // which is correct for our purpose
2087                         }
2088
2089                         bbt_time ((*i)->frame(), bbt);
2090
2091                         // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
2092
2093                         if (first) {
2094                                 first = false;
2095                         } else {
2096
2097                                 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
2098                                         /* round up to next beat */
2099                                         bbt.beats += 1;
2100                                 }
2101
2102                                 bbt.ticks = 0;
2103
2104                                 if (bbt.beats != 1) {
2105                                         /* round up to next bar */
2106                                         bbt.bars += 1;
2107                                         bbt.beats = 1;
2108                                 }
2109                         }
2110
2111                         // cerr << bbt << endl;
2112
2113                         (*i)->set_start (bbt);
2114
2115                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2116                                 tempo = t;
2117                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2118                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2119                                 meter = m;
2120                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2121                         } else {
2122                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
2123                                 abort(); /*NOTREACHED*/
2124                         }
2125
2126                         prev = (*i);
2127                 }
2128
2129                 recompute_map (true);
2130         }
2131
2132
2133         PropertyChanged (PropertyChange ());
2134 }
2135 bool
2136 TempoMap::remove_time (framepos_t where, framecnt_t amount)
2137 {
2138         bool moved = false;
2139
2140         std::list<MetricSection*> metric_kill_list;
2141
2142         TempoSection* last_tempo = NULL;
2143         MeterSection* last_meter = NULL;
2144         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
2145         bool meter_after = false; // is there a meter marker likewise?
2146         {
2147                 Glib::Threads::RWLock::WriterLock lm (lock);
2148                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2149                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
2150                                 metric_kill_list.push_back(*i);
2151                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
2152                                 if (lt)
2153                                         last_tempo = lt;
2154                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
2155                                 if (lm)
2156                                         last_meter = lm;
2157                         }
2158                         else if ((*i)->frame() >= where) {
2159                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
2160                                 (*i)->set_frame ((*i)->frame() - amount);
2161                                 if ((*i)->frame() == where) {
2162                                         // marker was immediately after end of range
2163                                         tempo_after = dynamic_cast<TempoSection*> (*i);
2164                                         meter_after = dynamic_cast<MeterSection*> (*i);
2165                                 }
2166                                 moved = true;
2167                         }
2168                 }
2169
2170                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
2171                 if (last_tempo && !tempo_after) {
2172                         metric_kill_list.remove(last_tempo);
2173                         last_tempo->set_frame(where);
2174                         moved = true;
2175                 }
2176                 if (last_meter && !meter_after) {
2177                         metric_kill_list.remove(last_meter);
2178                         last_meter->set_frame(where);
2179                         moved = true;
2180                 }
2181
2182                 //remove all the remaining metrics
2183                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
2184                         metrics.remove(*i);
2185                         moved = true;
2186                 }
2187
2188                 if (moved) {
2189                         recompute_map (true);
2190                 }
2191         }
2192         PropertyChanged (PropertyChange ());
2193         return moved;
2194 }
2195
2196 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2197  *  pos can be -ve, if required.
2198  */
2199 framepos_t
2200 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
2201 {
2202         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
2203 }
2204
2205 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2206 framepos_t
2207 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2208 {
2209         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
2210 }
2211
2212 /** Add the BBT interval op to pos and return the result */
2213 framepos_t
2214 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2215 {
2216         cerr << "framepos_plus_bbt - untested" << endl;
2217         Glib::Threads::RWLock::ReaderLock lm (lock);
2218
2219         Metrics::const_iterator i;
2220         const MeterSection* meter;
2221         const MeterSection* m;
2222         const TempoSection* tempo;
2223         const TempoSection* next_tempo = 0;
2224         const TempoSection* t;
2225         double frames_per_beat;
2226         framepos_t effective_pos = max (pos, (framepos_t) 0);
2227
2228         meter = &first_meter ();
2229         tempo = &first_tempo ();
2230
2231         assert (meter);
2232         assert (tempo);
2233
2234         /* find the starting metrics for tempo & meter */
2235
2236         for (i = metrics.begin(); i != metrics.end(); ++i) {
2237
2238                 if ((*i)->frame() > effective_pos) {
2239                         break;
2240                 }
2241
2242                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2243                         tempo = t;
2244                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2245                         meter = m;
2246                 }
2247         }
2248
2249         for (i = metrics.begin(); i != metrics.end(); ++i) {
2250                 if ((*i)->frame() > effective_pos) {
2251                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2252                                 next_tempo = t;
2253                         }
2254                         break;
2255                 }
2256         }
2257
2258         /* We now have:
2259
2260            meter -> the Meter for "pos"
2261            tempo -> the Tempo for "pos"
2262            next_tempo -> the Tempo after "pos" or 0
2263            i     -> for first new metric after "pos", possibly metrics.end()
2264         */
2265
2266         /* now comes the complicated part. we have to add one beat a time,
2267            checking for a new metric on every beat.
2268         */
2269
2270         uint64_t bars = 0;
2271         /* fpb is used for constant tempo */
2272         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2273
2274         while (op.bars) {
2275
2276                 bars++;
2277                 op.bars--;
2278
2279                 /* check if we need to use a new metric section: has adding frames moved us
2280                    to or after the start of the next metric section? in which case, use it.
2281                 */
2282
2283                 if (i != metrics.end()) {
2284                         if ((*i)->frame() <= pos) {
2285
2286                                 /* about to change tempo or meter, so add the
2287                                  * number of frames for the bars we've just
2288                                  * traversed before we change the
2289                                  * frames_per_beat value.
2290                                  */
2291
2292                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2293                                         next_tempo = t;
2294                                 }
2295
2296                                 if (next_tempo) {
2297                                         pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2298                                 } else {
2299                                         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2300                                 }
2301
2302                                 bars = 0;
2303
2304                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2305                                         tempo = t;
2306                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2307                                         meter = m;
2308                                 }
2309                                 ++i;
2310                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2311                         }
2312                 }
2313
2314         }
2315
2316         if (next_tempo) {
2317                 pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2318         } else {
2319                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2320         }
2321
2322         uint64_t beats = 0;
2323
2324         while (op.beats) {
2325
2326                 /* given the current meter, have we gone past the end of the bar ? */
2327
2328                 beats++;
2329                 op.beats--;
2330
2331                 /* check if we need to use a new metric section: has adding frames moved us
2332                    to or after the start of the next metric section? in which case, use it.
2333                 */
2334
2335                 if (i != metrics.end()) {
2336                         if ((*i)->frame() <= pos) {
2337
2338                                 /* about to change tempo or meter, so add the
2339                                  * number of frames for the beats we've just
2340                                  * traversed before we change the
2341                                  * frames_per_beat value.
2342                                  */
2343
2344                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2345                                         next_tempo = t;
2346                                 }
2347
2348                                 if (next_tempo) {
2349                                         pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2350                                 } else {
2351                                         pos += llrint (beats * frames_per_beat);
2352                                 }
2353
2354                                 beats = 0;
2355
2356                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2357                                         tempo = t;
2358                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2359                                         meter = m;
2360                                 }
2361                                 ++i;
2362                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2363                         }
2364                 }
2365         }
2366
2367         if (next_tempo) {
2368                 pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2369         } else {
2370                 pos += llrint (beats * frames_per_beat);
2371         }
2372
2373         if (op.ticks) {
2374                 pos += tempo->frame_at_tick (op.ticks, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2375         }
2376
2377         return pos;
2378
2379 }
2380
2381 /** Count the number of beats that are equivalent to distance when going forward,
2382     starting at pos.
2383 */
2384 Evoral::Beats
2385 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2386 {
2387         return Evoral::Beats(beat_at_frame (pos + distance) - beat_at_frame (pos));
2388 }
2389
2390 struct bbtcmp {
2391     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2392             return a < b;
2393     }
2394 };
2395
2396 std::ostream&
2397 operator<< (std::ostream& o, const Meter& m) {
2398         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2399 }
2400
2401 std::ostream&
2402 operator<< (std::ostream& o, const Tempo& t) {
2403         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2404 }
2405
2406 std::ostream&
2407 operator<< (std::ostream& o, const MetricSection& section) {
2408
2409         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2410
2411         const TempoSection* ts;
2412         const MeterSection* ms;
2413
2414         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2415                 o << *((const Tempo*) ts);
2416         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2417                 o << *((const Meter*) ms);
2418         }
2419
2420         return o;
2421 }