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