Tempo ramps - allow live updating of tempo markers.
[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         assert (section->start().ticks == 0);
537
538         /* we only allow new meters to be inserted on beat 1 of an existing
539          * measure.
540          */
541
542         if (dynamic_cast<MeterSection*>(section)) {
543
544                 /* we need to (potentially) update the BBT times of tempo
545                    sections based on this new meter.
546                 */
547
548                 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
549
550                         BBT_Time corrected = section->start();
551                         corrected.beats = 1;
552                         corrected.ticks = 0;
553
554                         warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
555                                                    section->start(), corrected) << endmsg;
556
557                         section->set_start (corrected);
558                 }
559         }
560
561
562
563         /* Look for any existing MetricSection that is of the same type and
564            in the same bar as the new one, and remove it before adding
565            the new one. Note that this means that if we find a matching,
566            existing section, we can break out of the loop since we're
567            guaranteed that there is only one such match.
568         */
569
570         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
571
572                 bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0;
573                 bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0;
574
575                 if (iter_is_tempo && insert_is_tempo) {
576
577                         /* Tempo sections */
578
579                         if ((*i)->start().bars == section->start().bars &&
580                             (*i)->start().beats == section->start().beats) {
581
582                                 if (!(*i)->movable()) {
583
584                                         /* can't (re)move this section, so overwrite
585                                          * its data content (but not its properties as
586                                          * a section).
587                                          */
588
589                                         *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section));
590                                         need_add = false;
591                                 } else {
592                                         metrics.erase (i);
593                                 }
594                                 break;
595                         }
596
597                 } else if (!iter_is_tempo && !insert_is_tempo) {
598
599                         /* Meter Sections */
600
601                         if ((*i)->start().bars == section->start().bars) {
602
603                                 if (!(*i)->movable()) {
604
605                                         /* can't (re)move this section, so overwrite
606                                          * its data content (but not its properties as
607                                          * a section
608                                          */
609
610                                         *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section));
611                                         need_add = false;
612                                 } else {
613                                         metrics.erase (i);
614
615                                 }
616
617                                 break;
618                         }
619                 } else {
620                         /* non-matching types, so we don't care */
621                 }
622         }
623
624         /* Add the given MetricSection, if we didn't just reset an existing
625          * one above
626          */
627
628         if (need_add) {
629
630                 Metrics::iterator i;
631
632                 for (i = metrics.begin(); i != metrics.end(); ++i) {
633                         if ((*i)->start() > section->start()) {
634                                 break;
635                         }
636                 }
637
638                 metrics.insert (i, section);
639         }
640 }
641
642 void
643 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where, TempoSection::Type type)
644 {
645         {
646                 Glib::Threads::RWLock::WriterLock lm (lock);
647                 TempoSection& first (first_tempo());
648
649                 if (ts.start() != first.start()) {
650                         remove_tempo_locked (ts);
651                         add_tempo_locked (tempo, where, true, type);
652                 } else {
653                         first.set_type (type);
654                         {
655                                 /* cannot move the first tempo section */
656                                 *static_cast<Tempo*>(&first) = tempo;
657                                 recompute_map (false);
658                         }
659                 }
660         }
661
662         PropertyChanged (PropertyChange ());
663 }
664
665 void
666 TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame)
667 {
668         {
669                 TempoSection& first (first_tempo());
670
671                 if (ts.start() != first.start()) {
672                         BBT_Time bbt;
673                         bbt_time (frame, bbt);
674                         {
675                                 Glib::Threads::RWLock::WriterLock lm (lock);
676                                 ts.set_frame (frame);
677                                 ts.set_start (bbt);
678
679                                 recompute_map (false);
680                         }
681                 }
682         }
683
684         MetricPositionChanged (); // Emit Signal
685 }
686
687 void
688 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type)
689 {
690         {
691                 Glib::Threads::RWLock::WriterLock lm (lock);
692                 add_tempo_locked (tempo, where, true, type);
693         }
694
695
696         PropertyChanged (PropertyChange ());
697 }
698
699 void
700 TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, ARDOUR::TempoSection::Type type)
701 {
702         /* new tempos always start on a beat */
703         where.ticks = 0;
704         TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
705
706         /* find the meter to use to set the bar offset of this
707          * tempo section.
708          */
709
710         const Meter* meter = &first_meter();
711
712         /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
713            at something, because we insert the default tempo and meter during
714            TempoMap construction.
715
716            now see if we can find better candidates.
717         */
718
719         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
720
721                 const MeterSection* m;
722
723                 if (where < (*i)->start()) {
724                         break;
725                 }
726
727                 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
728                         meter = m;
729                 }
730         }
731
732         ts->update_bar_offset_from_bbt (*meter);
733
734         /* and insert it */
735
736         do_insert (ts);
737
738         if (recompute) {
739                 recompute_map (false);
740         }
741 }
742
743 void
744 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
745 {
746         {
747                 Glib::Threads::RWLock::WriterLock lm (lock);
748                 MeterSection& first (first_meter());
749
750                 if (ms.start() != first.start()) {
751                         remove_meter_locked (ms);
752                         add_meter_locked (meter, where, true);
753                 } else {
754                         /* cannot move the first meter section */
755                         *static_cast<Meter*>(&first) = meter;
756                         recompute_map (true);
757                 }
758         }
759
760         PropertyChanged (PropertyChange ());
761 }
762
763 void
764 TempoMap::add_meter (const Meter& meter, BBT_Time where)
765 {
766         {
767                 Glib::Threads::RWLock::WriterLock lm (lock);
768                 add_meter_locked (meter, where, true);
769         }
770
771
772 #ifndef NDEBUG
773         if (DEBUG_ENABLED(DEBUG::TempoMap)) {
774                 dump (std::cerr);
775         }
776 #endif
777
778         PropertyChanged (PropertyChange ());
779 }
780
781 void
782 TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
783 {
784         /* a new meter always starts a new bar on the first beat. so
785            round the start time appropriately. remember that
786            `where' is based on the existing tempo map, not
787            the result after we insert the new meter.
788
789         */
790
791         if (where.beats != 1) {
792                 where.beats = 1;
793                 where.bars++;
794         }
795
796         /* new meters *always* start on a beat. */
797         where.ticks = 0;
798
799         do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
800
801         if (recompute) {
802                 recompute_map (true);
803         }
804
805 }
806
807 void
808 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
809 {
810         Tempo newtempo (beats_per_minute, note_type);
811         TempoSection* t;
812
813         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
814                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
815                         {
816                                 Glib::Threads::RWLock::WriterLock lm (lock);
817                                 *((Tempo*) t) = newtempo;
818                                 recompute_map (false);
819                         }
820                         PropertyChanged (PropertyChange ());
821                         break;
822                 }
823         }
824 }
825
826 void
827 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
828 {
829         Tempo newtempo (beats_per_minute, note_type);
830
831         TempoSection* prev;
832         TempoSection* first;
833         Metrics::iterator i;
834
835         /* find the TempoSection immediately preceding "where"
836          */
837
838         for (first = 0, i = metrics.begin(), prev = 0; i != metrics.end(); ++i) {
839
840                 if ((*i)->frame() > where) {
841                         break;
842                 }
843
844                 TempoSection* t;
845
846                 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
847                         if (!first) {
848                                 first = t;
849                         }
850                         prev = t;
851                 }
852         }
853
854         if (!prev) {
855                 if (!first) {
856                         error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
857                         return;
858                 }
859
860                 prev = first;
861         }
862
863         /* reset */
864
865         {
866                 Glib::Threads::RWLock::WriterLock lm (lock);
867                 /* cannot move the first tempo section */
868                 *((Tempo*)prev) = newtempo;
869                 recompute_map (false);
870         }
871
872         PropertyChanged (PropertyChange ());
873 }
874
875 const MeterSection&
876 TempoMap::first_meter () const
877 {
878         const MeterSection *m = 0;
879
880         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
881                 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
882                         return *m;
883                 }
884         }
885
886         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
887         abort(); /*NOTREACHED*/
888         return *m;
889 }
890
891 MeterSection&
892 TempoMap::first_meter ()
893 {
894         MeterSection *m = 0;
895
896         /* CALLER MUST HOLD LOCK */
897
898         for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
899                 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
900                         return *m;
901                 }
902         }
903
904         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
905         abort(); /*NOTREACHED*/
906         return *m;
907 }
908
909 const TempoSection&
910 TempoMap::first_tempo () const
911 {
912         const TempoSection *t = 0;
913
914         /* CALLER MUST HOLD LOCK */
915
916         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
917                 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
918                         return *t;
919                 }
920         }
921
922         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
923         abort(); /*NOTREACHED*/
924         return *t;
925 }
926
927 TempoSection&
928 TempoMap::first_tempo ()
929 {
930         TempoSection *t = 0;
931
932         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
933                 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
934                         return *t;
935                 }
936         }
937
938         fatal << _("programming error: no tempo section in tempo map!") << endmsg;
939         abort(); /*NOTREACHED*/
940         return *t;
941 }
942
943 void
944 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
945 {
946         /* CALLER MUST HOLD WRITE LOCK */
947
948         MeterSection* meter = 0;
949         TempoSection* tempo = 0;
950         double current_frame;
951         BBT_Time current;
952         Metrics::iterator next_metric;
953
954         if (end < 0) {
955
956                 /* we will actually stop once we hit
957                    the last metric.
958                 */
959                 end = max_framepos;
960
961         }
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 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 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 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 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 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 << "setting m 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
1224         if (n_meters() < 2) {
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         Glib::Threads::RWLock::ReaderLock lm (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 - tick_at_frame (prev_ts->frame());
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         return tick_at_frame (frame) / BBT_Time::ticks_per_beat;
1439 }
1440
1441 framecnt_t
1442 TempoMap::frame_at_beat (double beat) const
1443 {
1444         return frame_at_tick (beat * BBT_Time::ticks_per_beat);
1445 }
1446
1447 framepos_t
1448 TempoMap::frame_time (const BBT_Time& bbt)
1449 {
1450         if (bbt.bars < 1) {
1451                 warning << string_compose (_("tempo map asked for frame time at bar < 1  (%1)\n"), bbt) << endmsg;
1452                 return 0;
1453         }
1454
1455         if (bbt.beats < 1) {
1456                 throw std::logic_error ("beats are counted from one");
1457         }
1458
1459         Glib::Threads::RWLock::ReaderLock lm (lock);
1460
1461         Metrics::const_iterator i;
1462         uint32_t accumulated_bars = 0;
1463
1464         MeterSection* prev_ms = &first_meter();
1465
1466         for (i = metrics.begin(); i != metrics.end(); ++i) {
1467                 MeterSection* m;
1468                 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1469                         int32_t const bims = bars_in_meter_section (m);
1470
1471                         if (bims < 0 || bbt.bars <= (accumulated_bars + bims)) {
1472                                 break;
1473                         }
1474                         if (bims > 0 ) {
1475                                 accumulated_bars += bims;
1476                         }
1477                         prev_ms = m;
1478                 }
1479         }
1480
1481         uint32_t remaining_bars = bbt.bars - accumulated_bars - 1; // back to zero - based bars
1482         double const ticks_within_prev_taken_by_remaining_bars = remaining_bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat;
1483         double const ticks_after_space_used_by_bars = ((bbt.beats - 1) * BBT_Time::ticks_per_beat) + bbt.ticks; // back to zero - based beats
1484         double const ticks_target = ticks_within_prev_taken_by_remaining_bars + ticks_after_space_used_by_bars;
1485
1486         TempoSection* prev_ts = &first_tempo();
1487         double accumulated_ticks = 0.0;
1488         uint32_t cnt = 0;
1489
1490         for (i = metrics.begin(); i != metrics.end(); ++i) {
1491                 TempoSection* t;
1492                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1493                         if (t->frame() < prev_ms->frame()) {
1494                                 continue;
1495                         }
1496
1497                         if (cnt > 0 && t->frame() > prev_ts->frame()) {
1498                                 /*find the number of ticke in this section */
1499                                 framepos_t const time = t->frame() - prev_ts->frame();
1500                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1501                                 double const last_beats_per_minute = t->beats_per_minute();
1502                                 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1503                         }
1504
1505                         if (ticks_target < accumulated_ticks) {
1506                                 double const ticks_in_section = ticks_target - tick_at_frame (prev_ts->frame());
1507                                 framepos_t const section_start_time = prev_ts->frame();
1508                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1509                                 double const last_beats_per_minute = t->beats_per_minute();
1510                                 framepos_t const ret = prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start_time;
1511                                 return ret;
1512                         }
1513
1514                         prev_ts = t;
1515                         ++cnt;
1516                 }
1517         }
1518
1519         /*treat this ts as constant tempo */
1520         double const ticks_in_this_ts = ticks_target - tick_at_frame (prev_ts->frame());
1521         double const dtime = (ticks_in_this_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1522         framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1523         return ret;
1524 }
1525
1526
1527 framecnt_t
1528 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1529 {
1530
1531         Glib::Threads::RWLock::ReaderLock lm (lock);
1532
1533         Metrics::const_iterator i;
1534         TempoSection* first = 0;
1535         TempoSection* second = 0;
1536
1537         for (i = metrics.begin(); i != metrics.end(); ++i) {
1538                 TempoSection* t;
1539
1540                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1541
1542                         if ((*i)->frame() > pos) {
1543                                 second = t;
1544                                 break;
1545                         }
1546
1547                         first = t;
1548                 }
1549         }
1550         if (first && second) {
1551                 framepos_t const last_time = second->frame() - first->frame();
1552                 double const last_beats_per_minute = second->beats_per_minute();
1553
1554                 framepos_t const time = pos - first->frame();
1555                 double const tick_at_time = first->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1556                 double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1557
1558                 double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, last_beats_per_minute, last_time, _frame_rate);
1559
1560                 return time_at_bbt - time;
1561         }
1562
1563         double const ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1564         return (framecnt_t) floor ((ticks / BBT_Time::ticks_per_beat) * first->frames_per_beat(_frame_rate));
1565 }
1566
1567 framepos_t
1568 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
1569 {
1570         return round_to_type (fr, dir, Bar);
1571 }
1572
1573 framepos_t
1574 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
1575 {
1576         return round_to_type (fr, dir, Beat);
1577 }
1578
1579 framepos_t
1580 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
1581 {
1582         Glib::Threads::RWLock::ReaderLock lm (lock);
1583
1584         uint32_t ticks = (uint32_t) floor (tick_at_frame (fr) + 0.5);
1585         uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
1586         uint32_t ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1587
1588         ticks -= beats * BBT_Time::ticks_per_beat;
1589
1590         if (dir > 0) {
1591                 /* round to next (or same iff dir == RoundUpMaybe) */
1592
1593                 uint32_t mod = ticks % ticks_one_subdivisions_worth;
1594
1595                 if (mod == 0 && dir == RoundUpMaybe) {
1596                         /* right on the subdivision, which is fine, so do nothing */
1597
1598                 } else if (mod == 0) {
1599                         /* right on the subdivision, so the difference is just the subdivision ticks */
1600                         ticks += ticks_one_subdivisions_worth;
1601
1602                 } else {
1603                         /* not on subdivision, compute distance to next subdivision */
1604
1605                         ticks += ticks_one_subdivisions_worth - mod;
1606                 }
1607
1608                 if (ticks >= BBT_Time::ticks_per_beat) {
1609                         ticks -= BBT_Time::ticks_per_beat;
1610                 }
1611         } else if (dir < 0) {
1612
1613                 /* round to previous (or same iff dir == RoundDownMaybe) */
1614
1615                 uint32_t difference = ticks % ticks_one_subdivisions_worth;
1616
1617                 if (difference == 0 && dir == RoundDownAlways) {
1618                         /* right on the subdivision, but force-rounding down,
1619                            so the difference is just the subdivision ticks */
1620                         difference = ticks_one_subdivisions_worth;
1621                 }
1622
1623                 if (ticks < difference) {
1624                         ticks = BBT_Time::ticks_per_beat - ticks;
1625                 } else {
1626                         ticks -= difference;
1627                 }
1628
1629         } else {
1630                 /* round to nearest */
1631                 double rem;
1632
1633                 /* compute the distance to the previous and next subdivision */
1634
1635                 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1636
1637                         /* closer to the next subdivision, so shift forward */
1638
1639                         ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
1640
1641                         DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
1642
1643                         if (ticks > BBT_Time::ticks_per_beat) {
1644                                 ++beats;
1645                                 ticks -= BBT_Time::ticks_per_beat;
1646                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
1647                         }
1648
1649                 } else if (rem > 0) {
1650
1651                         /* closer to previous subdivision, so shift backward */
1652
1653                         if (rem > ticks) {
1654                                 if (beats == 0) {
1655                                         /* can't go backwards past zero, so ... */
1656                                         return 0;
1657                                 }
1658                                 /* step back to previous beat */
1659                                 --beats;
1660                                 ticks = lrint (BBT_Time::ticks_per_beat - rem);
1661                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
1662                         } else {
1663                                 ticks = lrint (ticks - rem);
1664                                 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
1665                         }
1666                 } else {
1667                         /* on the subdivision, do nothing */
1668                 }
1669         }
1670         return frame_at_tick ((beats * BBT_Time::ticks_per_beat) + ticks);
1671 }
1672
1673 framepos_t
1674 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
1675 {
1676         Glib::Threads::RWLock::ReaderLock lm (lock);
1677
1678         double const beat_at_framepos = beat_at_frame (frame);
1679
1680         BBT_Time bbt (beats_to_bbt (beat_at_framepos));
1681
1682         switch (type) {
1683         case Bar:
1684                 if (dir < 0) {
1685                         /* find bar previous to 'frame' */
1686                         bbt.beats = 1;
1687                         bbt.ticks = 0;
1688                         return frame_time (bbt);
1689
1690                 } else if (dir > 0) {
1691                         /* find bar following 'frame' */
1692                         ++bbt.bars;
1693                         bbt.beats = 1;
1694                         bbt.ticks = 0;
1695                         return frame_time (bbt);
1696                 } else {
1697                         /* true rounding: find nearest bar */
1698                         framepos_t raw_ft = frame_time (bbt);
1699                         bbt.beats = 1;
1700                         bbt.ticks = 0;
1701                         framepos_t prev_ft = frame_time (bbt);
1702                         ++bbt.bars;
1703                         framepos_t next_ft = frame_time (bbt);
1704
1705                         if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) { 
1706                                 return next_ft;
1707                         } else {
1708                                 return prev_ft;
1709                         }
1710                 }
1711
1712                 break;
1713
1714         case Beat:
1715                 if (dir < 0) {
1716                         return frame_at_beat (floor (beat_at_framepos));
1717                 } else if (dir > 0) {
1718                         return frame_at_beat (ceil (beat_at_framepos));
1719                 } else {
1720                         return frame_at_beat (floor (beat_at_framepos + 0.5));
1721                 }
1722                 break;
1723         }
1724
1725         return 0;
1726 }
1727
1728 void
1729 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
1730                     framepos_t lower, framepos_t upper)
1731 {
1732         Glib::Threads::RWLock::ReaderLock lm (lock);
1733         uint32_t const upper_beat = (uint32_t) floor (beat_at_frame (upper));
1734         uint32_t cnt = (uint32_t) ceil (beat_at_frame (lower));
1735
1736         while (cnt <= upper_beat) {
1737                 framecnt_t const pos = frame_at_beat (cnt);
1738                 MeterSection const meter = meter_section_at (pos);
1739                 Tempo const tempo = tempo_at (pos);
1740                 BBT_Time const bbt = beats_to_bbt ((double) cnt);
1741
1742                 points.push_back (BBTPoint (meter, tempo, pos, bbt.bars, bbt.beats));
1743                 ++cnt;
1744         }
1745 }
1746
1747 TempoSection*
1748 TempoMap::tempo_section_after (framepos_t frame) const
1749 {
1750         Glib::Threads::RWLock::ReaderLock lm (lock);
1751
1752         Metrics::const_iterator i;
1753         TempoSection* next = 0;
1754
1755         for (i = metrics.begin(); i != metrics.end(); ++i) {
1756                 TempoSection* t;
1757
1758                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1759
1760                         if ((*i)->frame() > frame) {
1761                                 next = t;
1762                                 break;
1763                         }
1764                 }
1765         }
1766
1767         return next;
1768 }
1769
1770
1771 const TempoSection&
1772 TempoMap::tempo_section_at (framepos_t frame) const
1773 {
1774         Glib::Threads::RWLock::ReaderLock lm (lock);
1775
1776         Metrics::const_iterator i;
1777         TempoSection* prev = 0;
1778
1779         for (i = metrics.begin(); i != metrics.end(); ++i) {
1780                 TempoSection* t;
1781
1782                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1783
1784                         if ((*i)->frame() > frame) {
1785                                 break;
1786                         }
1787
1788                         prev = t;
1789                 }
1790         }
1791
1792         if (prev == 0) {
1793                 fatal << endmsg;
1794                 abort(); /*NOTREACHED*/
1795         }
1796
1797         return *prev;
1798 }
1799
1800 /* don't use this to calculate length (the tempo is only correct for this frame).
1801    do that stuff based on the beat_at_frame and frame_at_beat api
1802 */
1803 double
1804 TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const
1805 {
1806         Glib::Threads::RWLock::ReaderLock lm (lock);
1807
1808         const TempoSection* ts_at = &tempo_section_at (frame);
1809         const TempoSection* ts_after = tempo_section_after (frame);
1810
1811         if (ts_after) {
1812                 return  (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate));
1813         }
1814         /* must be treated as constant tempo */
1815         return ts_at->frames_per_beat (_frame_rate);
1816 }
1817
1818 const Tempo
1819 TempoMap::tempo_at (framepos_t frame) const
1820 {
1821         Glib::Threads::RWLock::ReaderLock lm (lock);
1822
1823         TempoMetric m (metric_at (frame));
1824         TempoSection* prev_ts = 0;
1825
1826         Metrics::const_iterator i;
1827
1828         for (i = metrics.begin(); i != metrics.end(); ++i) {
1829                 TempoSection* t;
1830                 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1831                         if ((prev_ts) && t->frame() > frame) {
1832                                 /* this is the one past frame */
1833                                 framepos_t const time = frame - prev_ts->frame();
1834                                 framepos_t const last_time = t->frame() - prev_ts->frame();
1835                                 double const last_beats_per_minute = t->beats_per_minute();
1836                                 double const ret = prev_ts->tempo_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1837                                 Tempo const ret_tempo (ret, m.tempo().note_type ());
1838                                 return ret_tempo;
1839                         }
1840                         prev_ts = t;
1841                 }
1842         }
1843
1844         return m.tempo();
1845
1846 }
1847
1848 const MeterSection&
1849 TempoMap::meter_section_at (framepos_t frame) const
1850 {
1851         Glib::Threads::RWLock::ReaderLock lm (lock);
1852         Metrics::const_iterator i;
1853         MeterSection* prev = 0;
1854
1855         for (i = metrics.begin(); i != metrics.end(); ++i) {
1856                 MeterSection* t;
1857
1858                 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1859
1860                         if ((*i)->frame() > frame) {
1861                                 break;
1862                         }
1863
1864                         prev = t;
1865                 }
1866         }
1867
1868         if (prev == 0) {
1869                 fatal << endmsg;
1870                 abort(); /*NOTREACHED*/
1871         }
1872
1873         return *prev;
1874 }
1875
1876 const Meter&
1877 TempoMap::meter_at (framepos_t frame) const
1878 {
1879         TempoMetric m (metric_at (frame));
1880         return m.meter();
1881 }
1882
1883 XMLNode&
1884 TempoMap::get_state ()
1885 {
1886         Metrics::const_iterator i;
1887         XMLNode *root = new XMLNode ("TempoMap");
1888
1889         {
1890                 Glib::Threads::RWLock::ReaderLock lm (lock);
1891                 for (i = metrics.begin(); i != metrics.end(); ++i) {
1892                         root->add_child_nocopy ((*i)->get_state());
1893                 }
1894         }
1895
1896         return *root;
1897 }
1898
1899 int
1900 TempoMap::set_state (const XMLNode& node, int /*version*/)
1901 {
1902         {
1903                 Glib::Threads::RWLock::WriterLock lm (lock);
1904
1905                 XMLNodeList nlist;
1906                 XMLNodeConstIterator niter;
1907                 Metrics old_metrics (metrics);
1908                 MeterSection* last_meter = 0;
1909                 metrics.clear();
1910
1911                 nlist = node.children();
1912
1913                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1914                         XMLNode* child = *niter;
1915
1916                         if (child->name() == TempoSection::xml_state_node_name) {
1917
1918                                 try {
1919                                         TempoSection* ts = new TempoSection (*child);
1920                                         metrics.push_back (ts);
1921
1922                                         if (ts->bar_offset() < 0.0) {
1923                                                 if (last_meter) {
1924                                                         ts->update_bar_offset_from_bbt (*last_meter);
1925                                                 }
1926                                         }
1927                                 }
1928
1929                                 catch (failed_constructor& err){
1930                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1931                                         metrics = old_metrics;
1932                                         break;
1933                                 }
1934
1935                         } else if (child->name() == MeterSection::xml_state_node_name) {
1936
1937                                 try {
1938                                         MeterSection* ms = new MeterSection (*child);
1939                                         metrics.push_back (ms);
1940                                         last_meter = ms;
1941                                 }
1942
1943                                 catch (failed_constructor& err) {
1944                                         error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1945                                         metrics = old_metrics;
1946                                         break;
1947                                 }
1948                         }
1949                 }
1950
1951                 if (niter == nlist.end()) {
1952                         MetricSectionSorter cmp;
1953                         metrics.sort (cmp);
1954                 }
1955
1956                 /* check for multiple tempo/meters at the same location, which
1957                    ardour2 somehow allowed.
1958                 */
1959
1960                 Metrics::iterator prev = metrics.end();
1961                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1962                         if (prev != metrics.end()) {
1963                                 if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
1964                                         if ((*prev)->start() == (*i)->start()) {
1965                                                 cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
1966                                                 error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
1967                                                 return -1;
1968                                         }
1969                                 } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
1970                                         if ((*prev)->start() == (*i)->start()) {
1971                                                 cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
1972                                                 error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
1973                                                 return -1;
1974                                         }
1975                                 }
1976                         }
1977                         prev = i;
1978                 }
1979
1980                 recompute_map (true, -1);
1981         }
1982
1983         PropertyChanged (PropertyChange ());
1984
1985         return 0;
1986 }
1987
1988 void
1989 TempoMap::dump (std::ostream& o) const
1990 {
1991         Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
1992         const MeterSection* m;
1993         const TempoSection* t;
1994
1995         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1996
1997                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1998                         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? "
1999                           << t->movable() << ')' << endl;
2000                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2001                         o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
2002                           << " (movable? " << m->movable() << ')' << endl;
2003                 }
2004         }
2005 }
2006
2007 int
2008 TempoMap::n_tempos() const
2009 {
2010         Glib::Threads::RWLock::ReaderLock lm (lock);
2011         int cnt = 0;
2012
2013         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2014                 if (dynamic_cast<const TempoSection*>(*i) != 0) {
2015                         cnt++;
2016                 }
2017         }
2018
2019         return cnt;
2020 }
2021
2022 int
2023 TempoMap::n_meters() const
2024 {
2025         Glib::Threads::RWLock::ReaderLock lm (lock);
2026         int cnt = 0;
2027
2028         for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2029                 if (dynamic_cast<const MeterSection*>(*i) != 0) {
2030                         cnt++;
2031                 }
2032         }
2033
2034         return cnt;
2035 }
2036
2037 void
2038 TempoMap::insert_time (framepos_t where, framecnt_t amount)
2039 {
2040         {
2041                 Glib::Threads::RWLock::WriterLock lm (lock);
2042                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2043                         if ((*i)->frame() >= where && (*i)->movable ()) {
2044                                 (*i)->set_frame ((*i)->frame() + amount);
2045                         }
2046                 }
2047
2048                 /* now reset the BBT time of all metrics, based on their new
2049                  * audio time. This is the only place where we do this reverse
2050                  * timestamp.
2051                  */
2052
2053                 Metrics::iterator i;
2054                 const MeterSection* meter;
2055                 const TempoSection* tempo;
2056                 MeterSection *m;
2057                 TempoSection *t;
2058
2059                 meter = &first_meter ();
2060                 tempo = &first_tempo ();
2061
2062                 BBT_Time start;
2063                 BBT_Time end;
2064
2065                 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
2066
2067                 bool first = true;
2068                 MetricSection* prev = 0;
2069
2070                 for (i = metrics.begin(); i != metrics.end(); ++i) {
2071
2072                         BBT_Time bbt;
2073                         TempoMetric metric (*meter, *tempo);
2074
2075                         if (prev) {
2076                                 metric.set_start (prev->start());
2077                                 metric.set_frame (prev->frame());
2078                         } else {
2079                                 // metric will be at frames=0 bbt=1|1|0 by default
2080                                 // which is correct for our purpose
2081                         }
2082
2083                         bbt_time ((*i)->frame(), bbt);
2084
2085                         // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
2086
2087                         if (first) {
2088                                 first = false;
2089                         } else {
2090
2091                                 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
2092                                         /* round up to next beat */
2093                                         bbt.beats += 1;
2094                                 }
2095
2096                                 bbt.ticks = 0;
2097
2098                                 if (bbt.beats != 1) {
2099                                         /* round up to next bar */
2100                                         bbt.bars += 1;
2101                                         bbt.beats = 1;
2102                                 }
2103                         }
2104
2105                         // cerr << bbt << endl;
2106
2107                         (*i)->set_start (bbt);
2108
2109                         if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2110                                 tempo = t;
2111                                 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2112                         } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2113                                 meter = m;
2114                                 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2115                         } else {
2116                                 fatal << _("programming error: unhandled MetricSection type") << endmsg;
2117                                 abort(); /*NOTREACHED*/
2118                         }
2119
2120                         prev = (*i);
2121                 }
2122
2123                 recompute_map (true);
2124         }
2125
2126
2127         PropertyChanged (PropertyChange ());
2128 }
2129 bool
2130 TempoMap::remove_time (framepos_t where, framecnt_t amount)
2131 {
2132         bool moved = false;
2133
2134         std::list<MetricSection*> metric_kill_list;
2135
2136         TempoSection* last_tempo = NULL;
2137         MeterSection* last_meter = NULL;
2138         bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
2139         bool meter_after = false; // is there a meter marker likewise?
2140         {
2141                 Glib::Threads::RWLock::WriterLock lm (lock);
2142                 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2143                         if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
2144                                 metric_kill_list.push_back(*i);
2145                                 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
2146                                 if (lt)
2147                                         last_tempo = lt;
2148                                 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
2149                                 if (lm)
2150                                         last_meter = lm;
2151                         }
2152                         else if ((*i)->frame() >= where) {
2153                                 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
2154                                 (*i)->set_frame ((*i)->frame() - amount);
2155                                 if ((*i)->frame() == where) {
2156                                         // marker was immediately after end of range
2157                                         tempo_after = dynamic_cast<TempoSection*> (*i);
2158                                         meter_after = dynamic_cast<MeterSection*> (*i);
2159                                 }
2160                                 moved = true;
2161                         }
2162                 }
2163
2164                 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
2165                 if (last_tempo && !tempo_after) {
2166                         metric_kill_list.remove(last_tempo);
2167                         last_tempo->set_frame(where);
2168                         moved = true;
2169                 }
2170                 if (last_meter && !meter_after) {
2171                         metric_kill_list.remove(last_meter);
2172                         last_meter->set_frame(where);
2173                         moved = true;
2174                 }
2175
2176                 //remove all the remaining metrics
2177                 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
2178                         metrics.remove(*i);
2179                         moved = true;
2180                 }
2181
2182                 if (moved) {
2183                         recompute_map (true);
2184                 }
2185         }
2186         PropertyChanged (PropertyChange ());
2187         return moved;
2188 }
2189
2190 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2191  *  pos can be -ve, if required.
2192  */
2193 framepos_t
2194 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
2195 {
2196         return frame_at_beat (beat_at_frame (pos) + beats.to_double());
2197 }
2198
2199 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2200 framepos_t
2201 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2202 {
2203         return frame_at_beat (beat_at_frame (pos) - beats.to_double());
2204 }
2205
2206 /** Add the BBT interval op to pos and return the result */
2207 framepos_t
2208 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2209 {
2210         cerr << "framepos_plus_bbt - untested" << endl;
2211         Glib::Threads::RWLock::ReaderLock lm (lock);
2212
2213         Metrics::const_iterator i;
2214         const MeterSection* meter;
2215         const MeterSection* m;
2216         const TempoSection* tempo;
2217         const TempoSection* next_tempo = 0;
2218         const TempoSection* t;
2219         double frames_per_beat;
2220         framepos_t effective_pos = max (pos, (framepos_t) 0);
2221
2222         meter = &first_meter ();
2223         tempo = &first_tempo ();
2224
2225         assert (meter);
2226         assert (tempo);
2227
2228         /* find the starting metrics for tempo & meter */
2229
2230         for (i = metrics.begin(); i != metrics.end(); ++i) {
2231
2232                 if ((*i)->frame() > effective_pos) {
2233                         break;
2234                 }
2235
2236                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2237                         tempo = t;
2238                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2239                         meter = m;
2240                 }
2241         }
2242
2243         for (i = metrics.begin(); i != metrics.end(); ++i) {
2244                 if ((*i)->frame() > effective_pos) {
2245                         if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2246                                 next_tempo = t;
2247                         }
2248                         break;
2249                 }
2250         }
2251
2252         /* We now have:
2253
2254            meter -> the Meter for "pos"
2255            tempo -> the Tempo for "pos"
2256            next_tempo -> the Tempo after "pos" or 0
2257            i     -> for first new metric after "pos", possibly metrics.end()
2258         */
2259
2260         /* now comes the complicated part. we have to add one beat a time,
2261            checking for a new metric on every beat.
2262         */
2263
2264         uint64_t bars = 0;
2265         /* fpb is used for constant tempo */
2266         frames_per_beat = tempo->frames_per_beat (_frame_rate);
2267
2268         while (op.bars) {
2269
2270                 bars++;
2271                 op.bars--;
2272
2273                 /* check if we need to use a new metric section: has adding frames moved us
2274                    to or after the start of the next metric section? in which case, use it.
2275                 */
2276
2277                 if (i != metrics.end()) {
2278                         if ((*i)->frame() <= pos) {
2279
2280                                 /* about to change tempo or meter, so add the
2281                                  * number of frames for the bars we've just
2282                                  * traversed before we change the
2283                                  * frames_per_beat value.
2284                                  */
2285
2286                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2287                                         next_tempo = t;
2288                                 }
2289
2290                                 if (next_tempo) {
2291                                         pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2292                                 } else {
2293                                         pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2294                                 }
2295
2296                                 bars = 0;
2297
2298                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2299                                         tempo = t;
2300                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2301                                         meter = m;
2302                                 }
2303                                 ++i;
2304                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2305                         }
2306                 }
2307
2308         }
2309
2310         if (next_tempo) {
2311                 pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2312         } else {
2313                 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2314         }
2315
2316         uint64_t beats = 0;
2317
2318         while (op.beats) {
2319
2320                 /* given the current meter, have we gone past the end of the bar ? */
2321
2322                 beats++;
2323                 op.beats--;
2324
2325                 /* check if we need to use a new metric section: has adding frames moved us
2326                    to or after the start of the next metric section? in which case, use it.
2327                 */
2328
2329                 if (i != metrics.end()) {
2330                         if ((*i)->frame() <= pos) {
2331
2332                                 /* about to change tempo or meter, so add the
2333                                  * number of frames for the beats we've just
2334                                  * traversed before we change the
2335                                  * frames_per_beat value.
2336                                  */
2337
2338                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2339                                         next_tempo = t;
2340                                 }
2341
2342                                 if (next_tempo) {
2343                                         pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2344                                 } else {
2345                                         pos += llrint (beats * frames_per_beat);
2346                                 }
2347
2348                                 beats = 0;
2349
2350                                 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2351                                         tempo = t;
2352                                 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2353                                         meter = m;
2354                                 }
2355                                 ++i;
2356                                 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2357                         }
2358                 }
2359         }
2360
2361         if (next_tempo) {
2362                 pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2363         } else {
2364                 pos += llrint (beats * frames_per_beat);
2365         }
2366
2367         if (op.ticks) {
2368                 pos += tempo->frame_at_tick (op.ticks, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2369         }
2370
2371         return pos;
2372
2373 }
2374
2375 /** Count the number of beats that are equivalent to distance when going forward,
2376     starting at pos.
2377 */
2378 Evoral::Beats
2379 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2380 {
2381         return Evoral::Beats(beat_at_frame (pos + distance) - beat_at_frame (pos));
2382 }
2383
2384 struct bbtcmp {
2385     bool operator() (const BBT_Time& a, const BBT_Time& b) {
2386             return a < b;
2387     }
2388 };
2389
2390 std::ostream&
2391 operator<< (std::ostream& o, const Meter& m) {
2392         return o << m.divisions_per_bar() << '/' << m.note_divisor();
2393 }
2394
2395 std::ostream&
2396 operator<< (std::ostream& o, const Tempo& t) {
2397         return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2398 }
2399
2400 std::ostream&
2401 operator<< (std::ostream& o, const MetricSection& section) {
2402
2403         o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2404
2405         const TempoSection* ts;
2406         const MeterSection* ms;
2407
2408         if ((ts = dynamic_cast<const TempoSection*> (&section)) != 0) {
2409                 o << *((const Tempo*) ts);
2410         } else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 0) {
2411                 o << *((const Meter*) ms);
2412         }
2413
2414         return o;
2415 }