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