2 Copyright (C) 2000-2002 Paul Davis
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.
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.
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.
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"
37 using namespace ARDOUR;
40 using Timecode::BBT_Time;
42 /* _default tempo is 4/4 qtr=120 */
44 Meter TempoMap::_default_meter (4.0, 4.0);
45 Tempo TempoMap::_default_tempo (120.0);
47 /***********************************************************************/
50 Meter::frames_per_grid (const Tempo& tempo, framecnt_t sr) const
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.
56 The return value IS NOT interpretable in terms of "beats".
59 return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
63 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
65 return frames_per_grid (tempo, sr) * _divisions_per_bar;
69 /***********************************************************************/
71 const string TempoSection::xml_state_node_name = "Tempo";
73 TempoSection::TempoSection (const XMLNode& node)
74 : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
76 const XMLProperty *prop;
80 if ((prop = node.property ("start")) == 0) {
81 error << _("TempoSection XML node has no \"start\" property") << endmsg;
82 throw failed_constructor();
85 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
89 error << _("TempoSection XML node has an illegal \"start\" value") << endmsg;
90 throw failed_constructor();
95 if ((prop = node.property ("beats-per-minute")) == 0) {
96 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
97 throw failed_constructor();
100 if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
101 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
102 throw failed_constructor();
105 if ((prop = node.property ("note-type")) == 0) {
106 /* older session, make note type be quarter by default */
109 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
110 error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
111 throw failed_constructor();
115 if ((prop = node.property ("movable")) == 0) {
116 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
117 throw failed_constructor();
120 set_movable (string_is_affirmative (prop->value()));
122 if ((prop = node.property ("bar-offset")) == 0) {
125 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
126 error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
127 throw failed_constructor();
131 if ((prop = node.property ("tempo-type")) == 0) {
132 _type = Type::Constant;
134 if (strstr(prop->value().c_str(),"Constant")) {
135 _type = Type::Constant;
143 TempoSection::get_state() const
145 XMLNode *root = new XMLNode (xml_state_node_name);
149 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
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);
163 snprintf (buf, sizeof (buf), "%s", _type == Constant?"Constant":"Ramp");
164 root->add_property ("tempo-type", buf);
171 TempoSection::update_bar_offset_from_bbt (const Meter& m)
173 _bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_beat + start().ticks) /
174 (m.divisions_per_bar() * BBT_Time::ticks_per_beat);
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()));
180 TempoSection::set_type (Type type)
186 TempoSection::tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
189 if (_type == Constant) {
190 return beats_per_minute();
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;
197 TempoSection::frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
199 if (_type == Constant) {
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);
207 TempoSection::tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
209 if (_type == Constant) {
210 return (frame / frames_per_beat (frame_rate)) * BBT_Time::ticks_per_beat;
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));
217 TempoSection::frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
219 if (_type == Constant) {
220 return (framepos_t) floor ((tick / BBT_Time::ticks_per_beat) * frames_per_beat (frame_rate));
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);
226 double TempoSection::beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
228 return tick_at_frame (frame, end_bpm, end_frame, frame_rate) / BBT_Time::ticks_per_beat;
231 framepos_t TempoSection::frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const
233 return frame_at_tick (beat * BBT_Time::ticks_per_beat, end_bpm, end_frame, frame_rate);
237 TempoSection::minute_to_frame (double time, framecnt_t frame_rate) const
239 return time * 60.0 * frame_rate;
243 TempoSection::frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const
245 return (frame / (double) frame_rate) / 60.0;
248 /* constant for exp */
250 TempoSection::a_func (double begin_tpm, double end_tpm, double end_time) const
252 return log (end_tpm / ticks_per_minute()) / c_func (end_tpm, end_time);
255 TempoSection::c_func (double end_tpm, double end_time) const
257 return log (end_tpm / ticks_per_minute()) / end_time;
260 /* tempo in tpm at time in minutes */
262 TempoSection::tick_tempo_at_time (double time, double end_tpm, double end_time) const
264 return exp (c_func (end_tpm, end_time) * time) * ticks_per_minute();
267 /* time in minutes at tempo in tpm */
269 TempoSection::time_at_tick_tempo (double tick_tempo, double end_tpm, double end_time) const
271 return log (tick_tempo / ticks_per_minute()) / c_func (end_tpm, end_time);
274 /* tempo in bpm at time in minutes */
276 TempoSection::tempo_at_time (double time, double end_bpm, double end_time) const
278 return tick_tempo_at_time (time, end_bpm * BBT_Time::ticks_per_beat, end_time) / BBT_Time::ticks_per_beat;
281 /* time in minutes at tempo in bpm */
283 TempoSection::time_at_tempo (double tempo, double end_bpm, double end_time) const
285 return time_at_tick_tempo (tempo * BBT_Time::ticks_per_beat, end_bpm * BBT_Time::ticks_per_beat, end_time);
288 /* tick at time in minutes */
290 TempoSection::tick_at_time (double time, double end_tpm, double end_time) const
292 return ((exp (c_func (end_tpm, end_time) * time)) - 1) * ticks_per_minute() / c_func (end_tpm, end_time);
295 /* time in minutes at tick */
297 TempoSection::time_at_tick (double tick, double end_tpm, double end_time) const
299 return log (((c_func (end_tpm, end_time) * tick) / ticks_per_minute()) + 1) / c_func (end_tpm, end_time);
302 /* beat at time in minutes */
304 TempoSection::beat_at_time (double time, double end_tpm, double end_time) const
306 return tick_at_time (time, end_tpm, end_time) / BBT_Time::ticks_per_beat;
309 /* time in munutes at beat */
311 TempoSection::time_at_beat (double beat, double end_tpm, double end_time) const
313 return time_at_tick (beat * BBT_Time::ticks_per_beat, end_tpm, end_time);
317 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
321 if (_bar_offset < 0.0) {
326 new_start.bars = start().bars;
328 double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
329 new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
330 //new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
331 new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat);
333 /* remember the 1-based counting properties of beats */
334 new_start.beats += 1;
335 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
336 _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
338 set_start (new_start);
341 /***********************************************************************/
343 const string MeterSection::xml_state_node_name = "Meter";
345 MeterSection::MeterSection (const XMLNode& node)
346 : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
348 XMLProperty const * prop;
352 if ((prop = node.property ("start")) == 0) {
353 error << _("MeterSection XML node has no \"start\" property") << endmsg;
354 throw failed_constructor();
357 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
361 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
362 throw failed_constructor();
367 /* beats-per-bar is old; divisions-per-bar is new */
369 if ((prop = node.property ("divisions-per-bar")) == 0) {
370 if ((prop = node.property ("beats-per-bar")) == 0) {
371 error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
372 throw failed_constructor();
376 if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
377 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
378 throw failed_constructor();
381 if ((prop = node.property ("note-type")) == 0) {
382 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
383 throw failed_constructor();
386 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
387 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
388 throw failed_constructor();
391 if ((prop = node.property ("movable")) == 0) {
392 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
393 throw failed_constructor();
396 set_movable (string_is_affirmative (prop->value()));
400 MeterSection::get_state() const
402 XMLNode *root = new XMLNode (xml_state_node_name);
406 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
410 root->add_property ("start", buf);
411 snprintf (buf, sizeof (buf), "%f", _note_type);
412 root->add_property ("note-type", buf);
413 snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
414 root->add_property ("divisions-per-bar", buf);
415 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
416 root->add_property ("movable", buf);
421 /***********************************************************************/
423 struct MetricSectionSorter {
424 bool operator() (const MetricSection* a, const MetricSection* b) {
425 return a->start() < b->start();
429 struct MetricSectionFrameSorter {
430 bool operator() (const MetricSection* a, const MetricSection* b) {
431 return a->frame() < b->frame();
435 TempoMap::TempoMap (framecnt_t fr)
444 TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Type::Ramp);
445 MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
447 t->set_movable (false);
448 m->set_movable (false);
450 /* note: frame time is correct (zero) for both of these */
452 metrics.push_back (t);
453 metrics.push_back (m);
457 TempoMap::~TempoMap ()
462 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
464 bool removed = false;
467 Glib::Threads::RWLock::WriterLock lm (lock);
468 if ((removed = remove_tempo_locked (tempo))) {
469 if (complete_operation) {
470 recompute_map (true);
475 if (removed && complete_operation) {
476 PropertyChanged (PropertyChange ());
481 TempoMap::remove_tempo_locked (const TempoSection& tempo)
485 for (i = metrics.begin(); i != metrics.end(); ++i) {
486 if (dynamic_cast<TempoSection*> (*i) != 0) {
487 if (tempo.frame() == (*i)->frame()) {
488 if ((*i)->movable()) {
500 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
502 bool removed = false;
505 Glib::Threads::RWLock::WriterLock lm (lock);
506 if ((removed = remove_meter_locked (tempo))) {
507 if (complete_operation) {
508 recompute_map (true);
513 if (removed && complete_operation) {
514 PropertyChanged (PropertyChange ());
519 TempoMap::remove_meter_locked (const MeterSection& tempo)
523 for (i = metrics.begin(); i != metrics.end(); ++i) {
524 if (dynamic_cast<MeterSection*> (*i) != 0) {
525 if (tempo.frame() == (*i)->frame()) {
526 if ((*i)->movable()) {
538 TempoMap::do_insert (MetricSection* section)
540 bool need_add = true;
542 /* we only allow new meters to be inserted on beat 1 of an existing
546 if (dynamic_cast<MeterSection*>(section)) {
547 assert (section->start().ticks == 0);
549 /* we need to (potentially) update the BBT times of tempo
550 sections based on this new meter.
553 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
555 BBT_Time corrected = section->start();
559 warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
560 section->start(), corrected) << endmsg;
562 section->set_start (corrected);
568 /* Look for any existing MetricSection that is of the same type and
569 in the same bar as the new one, and remove it before adding
570 the new one. Note that this means that if we find a matching,
571 existing section, we can break out of the loop since we're
572 guaranteed that there is only one such match.
575 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
577 bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0;
578 bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0;
580 if (iter_is_tempo && insert_is_tempo) {
584 if ((*i)->start().bars == section->start().bars &&
585 (*i)->start().beats == section->start().beats) {
587 if (!(*i)->movable()) {
589 /* can't (re)move this section, so overwrite
590 * its data content (but not its properties as
594 *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section));
602 } else if (!iter_is_tempo && !insert_is_tempo) {
606 if ((*i)->start().bars == section->start().bars) {
608 if (!(*i)->movable()) {
610 /* can't (re)move this section, so overwrite
611 * its data content (but not its properties as
615 *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section));
625 /* non-matching types, so we don't care */
629 /* Add the given MetricSection, if we didn't just reset an existing
637 for (i = metrics.begin(); i != metrics.end(); ++i) {
638 if ((*i)->start() > section->start()) {
643 metrics.insert (i, section);
648 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where, TempoSection::Type type)
651 Glib::Threads::RWLock::WriterLock lm (lock);
652 TempoSection& first (first_tempo());
654 if (ts.start() != first.start()) {
655 remove_tempo_locked (ts);
656 add_tempo_locked (tempo, where, true, type);
658 first.set_type (type);
660 /* cannot move the first tempo section */
661 *static_cast<Tempo*>(&first) = tempo;
662 recompute_map (false);
667 PropertyChanged (PropertyChange ());
671 TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame)
674 TempoSection& first (first_tempo());
675 if (ts.frame() != first.frame()) {
678 Glib::Threads::RWLock::WriterLock lm (lock);
680 ts.set_frame (frame);
682 MetricSectionFrameSorter fcmp;
685 Metrics::const_iterator i;
686 TempoSection* prev_ts = 0;
687 MeterSection* meter = 0;
689 for (i = metrics.begin(); i != metrics.end(); ++i) {
693 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
695 if ((*i)->frame() > frame - 1) {
702 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
704 if ((*i)->frame() > frame) {
712 if (prev_ts && meter) {
714 /* set the start bbt */
715 double const ticks_to_ts = prev_ts->tick_at_frame (frame - prev_ts->frame(), ts.beats_per_minute(), frame - prev_ts->frame(), _frame_rate);
716 double beats = ticks_to_ts / BBT_Time::ticks_per_beat;
717 Timecode::BBT_Time bbt;
719 bbt.bars = (uint32_t) floor (beats / meter->divisions_per_bar());
720 beats -= bbt.bars * meter->divisions_per_bar();
721 bbt.beats = (uint32_t) floor (beats);
723 bbt.ticks = (uint32_t) floor (beats * BBT_Time::ticks_per_beat);
725 /* now add the prev ts bbt */
726 bbt.bars += prev_ts->start().bars;
727 bbt.beats += prev_ts->start().beats;
729 if (bbt.beats > meter->divisions_per_bar()) {
731 bbt.beats -= meter->divisions_per_bar();
733 bbt.ticks += prev_ts->start().ticks;
734 if (bbt.ticks > BBT_Time::ticks_per_beat) {
736 bbt.ticks -= BBT_Time::ticks_per_beat;
741 MetricSectionSorter cmp;
743 recompute_map (false);
748 MetricPositionChanged (); // Emit Signal
752 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type)
755 Glib::Threads::RWLock::WriterLock lm (lock);
756 add_tempo_locked (tempo, where, true, type);
760 PropertyChanged (PropertyChange ());
764 TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, ARDOUR::TempoSection::Type type)
766 TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type);
768 /* find the meter to use to set the bar offset of this
772 const Meter* meter = &first_meter();
774 /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
775 at something, because we insert the default tempo and meter during
776 TempoMap construction.
778 now see if we can find better candidates.
781 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
783 const MeterSection* m;
785 if (where < (*i)->start()) {
789 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
794 //ts->update_bar_offset_from_bbt (*meter);
801 recompute_map (false);
806 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
809 Glib::Threads::RWLock::WriterLock lm (lock);
810 MeterSection& first (first_meter());
812 if (ms.start() != first.start()) {
813 remove_meter_locked (ms);
814 add_meter_locked (meter, where, true);
816 /* cannot move the first meter section */
817 *static_cast<Meter*>(&first) = meter;
818 recompute_map (true);
822 PropertyChanged (PropertyChange ());
826 TempoMap::add_meter (const Meter& meter, BBT_Time where)
829 Glib::Threads::RWLock::WriterLock lm (lock);
830 add_meter_locked (meter, where, true);
835 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
840 PropertyChanged (PropertyChange ());
844 TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute)
846 /* a new meter always starts a new bar on the first beat. so
847 round the start time appropriately. remember that
848 `where' is based on the existing tempo map, not
849 the result after we insert the new meter.
853 if (where.beats != 1) {
858 /* new meters *always* start on a beat. */
861 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
864 recompute_map (true);
870 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
872 Tempo newtempo (beats_per_minute, note_type);
875 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
876 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
878 Glib::Threads::RWLock::WriterLock lm (lock);
879 *((Tempo*) t) = newtempo;
880 recompute_map (false);
882 PropertyChanged (PropertyChange ());
889 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
891 Tempo newtempo (beats_per_minute, note_type);
897 /* find the TempoSection immediately preceding "where"
900 for (first = 0, i = metrics.begin(), prev = 0; i != metrics.end(); ++i) {
902 if ((*i)->frame() > where) {
908 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
918 error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
928 Glib::Threads::RWLock::WriterLock lm (lock);
929 /* cannot move the first tempo section */
930 *((Tempo*)prev) = newtempo;
931 recompute_map (false);
934 PropertyChanged (PropertyChange ());
938 TempoMap::first_meter () const
940 const MeterSection *m = 0;
942 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
943 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
948 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
949 abort(); /*NOTREACHED*/
954 TempoMap::first_meter ()
958 /* CALLER MUST HOLD LOCK */
960 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
961 if ((m = dynamic_cast<MeterSection *> (*i)) != 0) {
966 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
967 abort(); /*NOTREACHED*/
972 TempoMap::first_tempo () const
974 const TempoSection *t = 0;
976 /* CALLER MUST HOLD LOCK */
978 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
979 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
984 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
985 abort(); /*NOTREACHED*/
990 TempoMap::first_tempo ()
994 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
995 if ((t = dynamic_cast<TempoSection *> (*i)) != 0) {
1000 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
1001 abort(); /*NOTREACHED*/
1006 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
1008 /* CALLER MUST HOLD WRITE LOCK */
1010 MeterSection* meter = 0;
1011 TempoSection* tempo = 0;
1012 double current_frame;
1014 Metrics::iterator next_metric;
1018 /* we will actually stop once we hit
1025 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
1027 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1030 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
1038 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1041 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
1049 /* assumes that the first meter & tempo are at frame zero */
1051 meter->set_frame (0);
1052 tempo->set_frame (0);
1054 /* assumes that the first meter & tempo are at 1|1|0 */
1058 if (reassign_tempo_bbt) {
1060 MeterSection* rmeter = meter;
1062 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
1064 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
1069 if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
1071 /* reassign the BBT time of this tempo section
1072 * based on its bar offset position.
1075 //ts->update_bbt_time_from_bar_offset (*rmeter);
1077 } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
1080 fatal << _("programming error: unhandled MetricSection type") << endmsg;
1081 abort(); /*NOTREACHED*/
1086 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
1088 next_metric = metrics.begin();
1089 ++next_metric; // skip meter (or tempo)
1090 ++next_metric; // skip tempo (or meter)
1092 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
1095 /* silly call from Session::process() during startup
1100 _extend_map (tempo, meter, next_metric, current, current_frame, end);
1104 TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
1105 Metrics::iterator next_metric,
1106 BBT_Time current, framepos_t current_frame, framepos_t end)
1108 /* CALLER MUST HOLD WRITE LOCK */
1110 uint32_t first_tick_in_new_meter = 0;
1111 Metrics::const_iterator i;
1112 Metrics::const_iterator mi;
1114 TempoSection* prev_ts = tempo;
1116 for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
1117 MeterSection* m = 0;
1119 if ((m = dynamic_cast<MeterSection*> (*mi)) != 0) {
1121 if (m->start() >= prev_ts->start()) {
1122 first_tick_in_new_meter = ((((m->start().bars - 1) * meter->divisions_per_bar()) + (m->start().beats - 1)) * BBT_Time::ticks_per_beat) + m->start().ticks; // expressed in ticks from the previous meter
1123 for (i = metrics.begin(); i != metrics.end(); ++i) {
1126 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1127 if (t->position_lock_style() == AudioTime) {
1128 /* set the start bbt */
1129 double const ticks_at_ts = prev_ts->tick_at_frame (t->frame(), t->beats_per_minute(), t->frame(), _frame_rate);
1130 double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1)) * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
1132 double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
1133 double beats = ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat;
1135 Timecode::BBT_Time bbt;
1136 bbt.bars = (uint32_t) floor (beats / meter->divisions_per_bar());
1137 beats -= bbt.bars * meter->divisions_per_bar();
1138 bbt.beats = (uint32_t) floor (beats);
1140 bbt.ticks = (uint32_t) floor (beats * BBT_Time::ticks_per_beat);
1141 /* now add the prev ts bbt */
1142 bbt.bars += prev_ts->start().bars;
1143 bbt.beats += prev_ts->start().beats;
1145 if (bbt.beats > meter->divisions_per_bar()) {
1147 bbt.beats -= meter->divisions_per_bar();
1149 bbt.ticks += prev_ts->start().ticks;
1150 if (bbt.ticks > BBT_Time::ticks_per_beat) {
1152 bbt.ticks -= BBT_Time::ticks_per_beat;
1156 if (m->start() < t->start() && m->start() == prev_ts->start()) {
1157 m->set_frame (prev_ts->frame());
1158 } else if (m->start() < t->start() && m->start() > prev_ts->start()) {
1159 m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), t->frame(), _frame_rate) + prev_ts->frame());
1162 } else if (t->start() >= m->start() && t->start() > prev_ts->start()) {
1163 //cerr << "new ts start bars = " << t->start().bars << " beats = " << t->start().beats << " ticks = " << t->start().ticks << endl;
1164 //cerr << "prev ts start bars = " << prev_ts->start().bars << " beats = " << prev_ts->start().beats << " ticks = " << prev_ts->start().ticks << endl;
1166 /*tempo section (t) lies in the previous meter */
1167 double const ticks_at_ts = ((((t->start().bars - 1 ) * meter->divisions_per_bar()) + (t->start().beats - 1) ) * BBT_Time::ticks_per_beat) + t->start().ticks;
1168 double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1)) * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
1169 double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
1170 /* assume (falsely) that the target tempo is constant */
1171 double length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
1172 if (prev_ts->type() == TempoSection::Type::Constant) {
1173 length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
1175 cerr<< "initial length extimate = " << length_estimate << " ticks_relative_to_prev_ts " << ticks_relative_to_prev_ts << endl;
1176 double const system_precision_at_target_tempo = (_frame_rate / t->ticks_per_minute());
1177 cerr << " system_precision_at_target_tempo = " << system_precision_at_target_tempo << endl;
1178 double tick_error = system_precision_at_target_tempo + 1.0; // sorry for the wtf
1180 while (fabs (tick_error) >= system_precision_at_target_tempo) {
1182 double const actual_ticks = prev_ts->tick_at_frame (length_estimate, t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate);
1183 tick_error = ticks_relative_to_prev_ts - actual_ticks;
1184 length_estimate += (tick_error / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
1186 t->set_frame (length_estimate + prev_ts->frame());
1188 if (m->start() < t->start() && m->start() == prev_ts->start()) {
1189 m->set_frame (prev_ts->frame());
1190 } else if (m->start() < t->start() && m->start() > prev_ts->start()) {
1191 cerr << "recompute map - music lock style setting meter frame to " << prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) << " ticks = " << first_tick_in_new_meter - ticks_at_prev_ts << endl;
1193 m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) + prev_ts->frame());
1207 TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const
1209 Glib::Threads::RWLock::ReaderLock lm (lock);
1210 TempoMetric m (first_meter(), first_tempo());
1212 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1213 at something, because we insert the default tempo and meter during
1214 TempoMap construction.
1216 now see if we can find better candidates.
1219 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1221 if ((*i)->frame() > frame) {
1236 TempoMap::metric_at (BBT_Time bbt) const
1238 Glib::Threads::RWLock::ReaderLock lm (lock);
1239 TempoMetric m (first_meter(), first_tempo());
1241 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1242 at something, because we insert the default tempo and meter during
1243 TempoMap construction.
1245 now see if we can find better candidates.
1248 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
1250 BBT_Time section_start ((*i)->start());
1252 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1263 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1265 Glib::Threads::RWLock::ReaderLock lm (lock);
1271 warning << string_compose (_("tempo map asked for BBT time at frame %1\n"), frame) << endmsg;
1274 bbt = beats_to_bbt (beat_at_frame (frame));
1278 TempoMap::bars_in_meter_section (MeterSection* ms) const
1280 /* YOU MUST HAVE THE READ LOCK */
1281 Metrics::const_iterator i;
1283 MeterSection* next_ms = 0;
1284 const MeterSection* prev_ms = &first_meter();
1286 for (i = metrics.begin(); i != metrics.end(); ++i) {
1288 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1289 if (ms->frame() < m->frame()) {
1297 double ticks_at_next = tick_at_frame (next_ms->frame());
1298 double ticks_at_prev = tick_at_frame (prev_ms->frame());
1299 double ticks_in_meter = ticks_at_next - ticks_at_prev;
1301 return (int32_t) floor ((ticks_in_meter / BBT_Time::ticks_per_beat) / prev_ms->note_divisor());
1307 TempoMap::beats_to_bbt (double beats)
1309 /* CALLER HOLDS READ LOCK */
1311 MeterSection* prev_ms = &first_meter();
1313 framecnt_t frame = frame_at_beat (beats);
1315 /* XX most of this is utter crap */
1316 if (n_meters() == 1) {
1317 uint32_t bars = (uint32_t) floor (beats / prev_ms->note_divisor());
1318 double remaining_beats = beats - (bars * prev_ms->note_divisor());
1319 double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1321 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1322 ret.beats = (uint32_t) floor (remaining_beats);
1325 /* 0 0 0 to 1 1 0 - based mapping*/
1329 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1331 ret.ticks -= BBT_Time::ticks_per_beat;
1334 if (ret.beats > prev_ms->note_divisor()) {
1342 uint32_t first_beat_in_meter = 0;
1343 uint32_t accumulated_bars = 0;
1344 Metrics::const_iterator i;
1346 for (i = metrics.begin(); i != metrics.end(); ++i) {
1347 MeterSection* m = 0;
1349 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1350 first_beat_in_meter = beat_at_frame (m->frame());
1352 if (beats < first_beat_in_meter) {
1353 /* this is the meter after the one our beat is on*/
1356 int32_t const bars_in_ms = bars_in_meter_section (m);
1358 if (bars_in_ms > 0) {
1359 accumulated_bars += bars_in_ms;
1366 //cerr << "beats to bbr with beats = " << beats << " first_beat_in_meter = " << first_beat_in_meter << " accumulated_bars = " << accumulated_bars << endl;
1368 if (beats > first_beat_in_meter) {
1369 /* prev_ms is the relevant one here */
1371 /* now get the ticks at frame */
1372 double ticks_at_frame = tick_at_frame (frame);
1374 /* find the number of ticks at the beginning of the meter section (bar 1)*/
1375 double ticks_at_ms = tick_at_frame (prev_ms->frame());
1377 double beats_used_by_ms = (ticks_at_frame - ticks_at_ms) / BBT_Time::ticks_per_beat;
1379 uint32_t bars = (uint32_t) floor (beats_used_by_ms / prev_ms->note_divisor());
1380 double remaining_beats = beats_used_by_ms - (bars * prev_ms->note_divisor());
1381 double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat;
1383 ret.bars = bars + accumulated_bars;
1384 ret.beats = (uint32_t) floor (remaining_beats);
1385 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1387 /* now ensure we srtart at 1 1 0 */
1390 //cerr << "part 1 ret bars = " << ret.bars << " ret beats = " << ret.beats << " ret ticks = " << ret.ticks << endl;
1391 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1393 ret.ticks -= BBT_Time::ticks_per_beat;
1396 if (ret.beats > prev_ms->note_divisor()) {
1404 /* find the number of ticks at the beginning of the meter section (bar 1)*/
1405 double ticks_at_ms = tick_at_frame (prev_ms->frame());
1407 /* now get the ticks at frame */
1408 double ticks_at_frame = tick_at_frame (frame);
1410 double ticks_within_ms = ticks_at_frame - ticks_at_ms;
1412 ret.bars = (uint32_t) floor (((ticks_within_ms / BBT_Time::ticks_per_beat) / prev_ms->note_divisor())) + accumulated_bars;
1413 uint32_t remaining_ticks = ticks_within_ms - (ret.bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat);
1414 ret.beats = (uint32_t) floor (remaining_ticks);
1415 remaining_ticks -= ret.beats * BBT_Time::ticks_per_beat;
1417 /* only round ticks */
1418 ret.ticks = (uint32_t) floor (remaining_ticks + 0.5);
1420 /* now ensure we srtart at 1 1 0 */
1423 if (ret.ticks >= BBT_Time::ticks_per_beat) {
1425 ret.ticks -= BBT_Time::ticks_per_beat;
1428 if (ret.beats > prev_ms->note_divisor()) {
1437 TempoMap::tick_at_frame (framecnt_t frame) const
1440 Metrics::const_iterator i;
1441 const TempoSection* prev_ts = &first_tempo();
1442 double accumulated_ticks = 0.0;
1445 for (i = metrics.begin(); i != metrics.end(); ++i) {
1448 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1450 if (frame < t->frame()) {
1451 /*the previous ts is the one containing the frame */
1453 framepos_t time = frame - prev_ts->frame();
1454 framepos_t last_frame = t->frame() - prev_ts->frame();
1455 double last_beats_per_minute = t->beats_per_minute();
1457 return prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate) + accumulated_ticks;
1460 if (cnt > 0 && t->frame() > prev_ts->frame()) {
1461 framepos_t time = t->frame() - prev_ts->frame();
1462 framepos_t last_frame = t->frame() - prev_ts->frame();
1463 double last_beats_per_minute = t->beats_per_minute();
1464 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_frame, _frame_rate);
1472 /* treated s linear for this ts */
1473 framecnt_t frames_in_section = frame - prev_ts->frame();
1474 double ticks_in_section = (frames_in_section / prev_ts->frames_per_beat (_frame_rate)) * Timecode::BBT_Time::ticks_per_beat;
1476 return ticks_in_section + accumulated_ticks;
1481 TempoMap::frame_at_tick (double tick) const
1483 /* HOLD THE READER LOCK */
1485 double accumulated_ticks = 0.0;
1486 double accumulated_ticks_to_prev = 0.0;
1488 const TempoSection* prev_ts = &first_tempo();
1491 Metrics::const_iterator i;
1493 for (i = metrics.begin(); i != metrics.end(); ++i) {
1495 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1497 if (cnt > 0 && t->frame() > prev_ts->frame()) {
1498 framepos_t time = t->frame() - prev_ts->frame();
1499 framepos_t last_time = t->frame() - prev_ts->frame();
1500 double last_beats_per_minute = t->beats_per_minute();
1501 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1504 if (tick < accumulated_ticks) {
1505 /* prev_ts is the one affecting us. */
1507 double ticks_in_section = tick - accumulated_ticks_to_prev;
1508 framepos_t section_start = prev_ts->frame();
1509 framepos_t last_time = t->frame() - prev_ts->frame();
1510 double last_beats_per_minute = t->beats_per_minute();
1511 return prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start;
1513 accumulated_ticks_to_prev = accumulated_ticks;
1519 double ticks_in_section = tick - accumulated_ticks_to_prev;
1520 double dtime = (ticks_in_section / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1521 framecnt_t ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1527 TempoMap::beat_at_frame (framecnt_t frame) const
1529 Glib::Threads::RWLock::ReaderLock lm (lock);
1531 return tick_at_frame (frame) / BBT_Time::ticks_per_beat;
1535 TempoMap::frame_at_beat (double beat) const
1537 Glib::Threads::RWLock::ReaderLock lm (lock);
1539 return frame_at_tick (beat * BBT_Time::ticks_per_beat);
1543 TempoMap::frame_time (const BBT_Time& bbt)
1546 warning << string_compose (_("tempo map asked for frame time at bar < 1 (%1)\n"), bbt) << endmsg;
1550 if (bbt.beats < 1) {
1551 throw std::logic_error ("beats are counted from one");
1554 Glib::Threads::RWLock::ReaderLock lm (lock);
1556 Metrics::const_iterator i;
1557 uint32_t accumulated_bars = 0;
1559 MeterSection* prev_ms = &first_meter();
1561 for (i = metrics.begin(); i != metrics.end(); ++i) {
1563 if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
1564 int32_t const bims = bars_in_meter_section (m);
1566 if (bims < 0 || bbt.bars <= (accumulated_bars + bims)) {
1570 accumulated_bars += bims;
1576 uint32_t remaining_bars = bbt.bars - accumulated_bars - 1; // back to zero - based bars
1577 double const ticks_within_prev_taken_by_remaining_bars = remaining_bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat;
1578 double const ticks_after_space_used_by_bars = ((bbt.beats - 1) * BBT_Time::ticks_per_beat) + bbt.ticks; // back to zero - based beats
1579 double const ticks_target = ticks_within_prev_taken_by_remaining_bars + ticks_after_space_used_by_bars;
1581 TempoSection* prev_ts = &first_tempo();
1582 double accumulated_ticks = 0.0;
1583 double accumulated_ticks_to_prev = 0.0;
1587 for (i = metrics.begin(); i != metrics.end(); ++i) {
1589 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1590 if (t->frame() < prev_ms->frame()) {
1594 if (cnt > 0 && t->frame() > prev_ts->frame()) {
1595 /*find the number of ticke in this section */
1596 framepos_t const time = t->frame() - prev_ts->frame();
1597 framepos_t const last_time = t->frame() - prev_ts->frame();
1598 double const last_beats_per_minute = t->beats_per_minute();
1599 accumulated_ticks += prev_ts->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1602 if (ticks_target < accumulated_ticks) {
1603 double const ticks_in_section = ticks_target - accumulated_ticks_to_prev;
1604 framepos_t const section_start_time = prev_ts->frame();
1605 framepos_t const last_time = t->frame() - prev_ts->frame();
1606 double const last_beats_per_minute = t->beats_per_minute();
1607 framepos_t const ret = prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start_time;
1610 accumulated_ticks_to_prev = accumulated_ticks;
1616 /*treat this ts as constant tempo */
1617 double const ticks_in_this_ts = ticks_target - accumulated_ticks_to_prev;
1618 double const dtime = (ticks_in_this_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat(_frame_rate);
1619 framecnt_t const ret = ((framecnt_t) floor (dtime)) + prev_ts->frame();
1625 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1628 Glib::Threads::RWLock::ReaderLock lm (lock);
1630 Metrics::const_iterator i;
1631 TempoSection* first = 0;
1632 TempoSection* second = 0;
1634 for (i = metrics.begin(); i != metrics.end(); ++i) {
1637 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1639 if ((*i)->frame() > pos) {
1647 if (first && second) {
1648 framepos_t const last_time = second->frame() - first->frame();
1649 double const last_beats_per_minute = second->beats_per_minute();
1651 framepos_t const time = pos - first->frame();
1652 double const tick_at_time = first->tick_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1653 double const bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1655 double const time_at_bbt = first->frame_at_tick (tick_at_time + bbt_ticks, last_beats_per_minute, last_time, _frame_rate);
1657 return time_at_bbt - time;
1660 double const ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
1661 return (framecnt_t) floor ((ticks / BBT_Time::ticks_per_beat) * first->frames_per_beat(_frame_rate));
1665 TempoMap::round_to_bar (framepos_t fr, RoundMode dir)
1667 return round_to_type (fr, dir, Bar);
1671 TempoMap::round_to_beat (framepos_t fr, RoundMode dir)
1673 return round_to_type (fr, dir, Beat);
1677 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
1679 Glib::Threads::RWLock::ReaderLock lm (lock);
1681 uint32_t ticks = (uint32_t) floor (tick_at_frame (fr) + 0.5);
1682 uint32_t beats = (uint32_t) floor (ticks / BBT_Time::ticks_per_beat);
1683 uint32_t ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1685 ticks -= beats * BBT_Time::ticks_per_beat;
1688 /* round to next (or same iff dir == RoundUpMaybe) */
1690 uint32_t mod = ticks % ticks_one_subdivisions_worth;
1692 if (mod == 0 && dir == RoundUpMaybe) {
1693 /* right on the subdivision, which is fine, so do nothing */
1695 } else if (mod == 0) {
1696 /* right on the subdivision, so the difference is just the subdivision ticks */
1697 ticks += ticks_one_subdivisions_worth;
1700 /* not on subdivision, compute distance to next subdivision */
1702 ticks += ticks_one_subdivisions_worth - mod;
1705 if (ticks >= BBT_Time::ticks_per_beat) {
1706 ticks -= BBT_Time::ticks_per_beat;
1708 } else if (dir < 0) {
1710 /* round to previous (or same iff dir == RoundDownMaybe) */
1712 uint32_t difference = ticks % ticks_one_subdivisions_worth;
1714 if (difference == 0 && dir == RoundDownAlways) {
1715 /* right on the subdivision, but force-rounding down,
1716 so the difference is just the subdivision ticks */
1717 difference = ticks_one_subdivisions_worth;
1720 if (ticks < difference) {
1721 ticks = BBT_Time::ticks_per_beat - ticks;
1723 ticks -= difference;
1727 /* round to nearest */
1730 /* compute the distance to the previous and next subdivision */
1732 if ((rem = fmod ((double) ticks, (double) ticks_one_subdivisions_worth)) > ticks_one_subdivisions_worth/2.0) {
1734 /* closer to the next subdivision, so shift forward */
1736 ticks = lrint (ticks + (ticks_one_subdivisions_worth - rem));
1738 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved forward to %1\n", ticks));
1740 if (ticks > BBT_Time::ticks_per_beat) {
1742 ticks -= BBT_Time::ticks_per_beat;
1743 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("fold beat to %1\n", beats));
1746 } else if (rem > 0) {
1748 /* closer to previous subdivision, so shift backward */
1752 /* can't go backwards past zero, so ... */
1755 /* step back to previous beat */
1757 ticks = lrint (BBT_Time::ticks_per_beat - rem);
1758 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("step back beat to %1\n", beats));
1760 ticks = lrint (ticks - rem);
1761 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("moved backward to %1\n", ticks));
1764 /* on the subdivision, do nothing */
1767 return frame_at_tick ((beats * BBT_Time::ticks_per_beat) + ticks);
1771 TempoMap::round_to_type (framepos_t frame, RoundMode dir, BBTPointType type)
1773 Glib::Threads::RWLock::ReaderLock lm (lock);
1775 double const beat_at_framepos = beat_at_frame (frame);
1777 BBT_Time bbt (beats_to_bbt (beat_at_framepos));
1782 /* find bar previous to 'frame' */
1785 return frame_time (bbt);
1787 } else if (dir > 0) {
1788 /* find bar following 'frame' */
1792 return frame_time (bbt);
1794 /* true rounding: find nearest bar */
1795 framepos_t raw_ft = frame_time (bbt);
1798 framepos_t prev_ft = frame_time (bbt);
1800 framepos_t next_ft = frame_time (bbt);
1802 if ((raw_ft - prev_ft) > (next_ft - prev_ft) / 2) {
1813 return frame_at_beat (floor (beat_at_framepos));
1814 } else if (dir > 0) {
1815 return frame_at_beat (ceil (beat_at_framepos));
1817 return frame_at_beat (floor (beat_at_framepos + 0.5));
1826 TempoMap::get_grid (vector<TempoMap::BBTPoint>& points,
1827 framepos_t lower, framepos_t upper)
1829 Glib::Threads::RWLock::ReaderLock lm (lock);
1830 uint32_t const upper_beat = (uint32_t) floor (beat_at_frame (upper));
1831 uint32_t cnt = (uint32_t) ceil (beat_at_frame (lower));
1833 while (cnt <= upper_beat) {
1834 framecnt_t const pos = frame_at_beat (cnt);
1835 MeterSection const meter = meter_section_at (pos);
1836 Tempo const tempo = tempo_at (pos);
1837 BBT_Time const bbt = beats_to_bbt ((double) cnt);
1839 points.push_back (BBTPoint (meter, tempo, pos, bbt.bars, bbt.beats));
1845 TempoMap::tempo_section_after (framepos_t frame) const
1847 Glib::Threads::RWLock::ReaderLock lm (lock);
1849 Metrics::const_iterator i;
1850 TempoSection* next = 0;
1852 for (i = metrics.begin(); i != metrics.end(); ++i) {
1855 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1857 if ((*i)->frame() > frame) {
1869 TempoMap::tempo_section_at (framepos_t frame) const
1871 Glib::Threads::RWLock::ReaderLock lm (lock);
1873 Metrics::const_iterator i;
1874 TempoSection* prev = 0;
1876 for (i = metrics.begin(); i != metrics.end(); ++i) {
1879 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1881 if ((*i)->frame() > frame) {
1891 abort(); /*NOTREACHED*/
1897 /* don't use this to calculate length (the tempo is only correct for this frame).
1898 do that stuff based on the beat_at_frame and frame_at_beat api
1901 TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const
1903 Glib::Threads::RWLock::ReaderLock lm (lock);
1905 const TempoSection* ts_at = &tempo_section_at (frame);
1906 const TempoSection* ts_after = tempo_section_after (frame);
1909 return (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate));
1911 /* must be treated as constant tempo */
1912 return ts_at->frames_per_beat (_frame_rate);
1916 TempoMap::tempo_at (framepos_t frame) const
1918 Glib::Threads::RWLock::ReaderLock lm (lock);
1920 TempoMetric m (metric_at (frame));
1921 TempoSection* prev_ts = 0;
1923 Metrics::const_iterator i;
1925 for (i = metrics.begin(); i != metrics.end(); ++i) {
1927 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1928 if ((prev_ts) && t->frame() > frame) {
1929 /* this is the one past frame */
1930 framepos_t const time = frame - prev_ts->frame();
1931 framepos_t const last_time = t->frame() - prev_ts->frame();
1932 double const last_beats_per_minute = t->beats_per_minute();
1933 double const ret = prev_ts->tempo_at_frame (time, last_beats_per_minute, last_time, _frame_rate);
1934 Tempo const ret_tempo (ret, m.tempo().note_type ());
1946 TempoMap::meter_section_at (framepos_t frame) const
1948 Glib::Threads::RWLock::ReaderLock lm (lock);
1949 Metrics::const_iterator i;
1950 MeterSection* prev = 0;
1952 for (i = metrics.begin(); i != metrics.end(); ++i) {
1955 if ((t = dynamic_cast<MeterSection*> (*i)) != 0) {
1957 if ((*i)->frame() > frame) {
1967 abort(); /*NOTREACHED*/
1974 TempoMap::meter_at (framepos_t frame) const
1976 TempoMetric m (metric_at (frame));
1981 TempoMap::get_state ()
1983 Metrics::const_iterator i;
1984 XMLNode *root = new XMLNode ("TempoMap");
1987 Glib::Threads::RWLock::ReaderLock lm (lock);
1988 for (i = metrics.begin(); i != metrics.end(); ++i) {
1989 root->add_child_nocopy ((*i)->get_state());
1997 TempoMap::set_state (const XMLNode& node, int /*version*/)
2000 Glib::Threads::RWLock::WriterLock lm (lock);
2003 XMLNodeConstIterator niter;
2004 Metrics old_metrics (metrics);
2005 MeterSection* last_meter = 0;
2008 nlist = node.children();
2010 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2011 XMLNode* child = *niter;
2013 if (child->name() == TempoSection::xml_state_node_name) {
2016 TempoSection* ts = new TempoSection (*child);
2017 metrics.push_back (ts);
2019 if (ts->bar_offset() < 0.0) {
2021 //ts->update_bar_offset_from_bbt (*last_meter);
2026 catch (failed_constructor& err){
2027 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2028 metrics = old_metrics;
2032 } else if (child->name() == MeterSection::xml_state_node_name) {
2035 MeterSection* ms = new MeterSection (*child);
2036 metrics.push_back (ms);
2040 catch (failed_constructor& err) {
2041 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
2042 metrics = old_metrics;
2048 if (niter == nlist.end()) {
2049 MetricSectionSorter cmp;
2053 /* check for multiple tempo/meters at the same location, which
2054 ardour2 somehow allowed.
2057 Metrics::iterator prev = metrics.end();
2058 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2059 if (prev != metrics.end()) {
2060 if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) {
2061 if ((*prev)->start() == (*i)->start()) {
2062 cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
2063 error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg;
2066 } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) {
2067 if ((*prev)->start() == (*i)->start()) {
2068 cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
2069 error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg;
2077 recompute_map (true, -1);
2080 PropertyChanged (PropertyChange ());
2086 TempoMap::dump (std::ostream& o) const
2088 Glib::Threads::RWLock::ReaderLock lm (lock, Glib::Threads::TRY_LOCK);
2089 const MeterSection* m;
2090 const TempoSection* t;
2092 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2094 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2095 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? "
2096 << t->movable() << ')' << endl;
2097 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2098 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
2099 << " (movable? " << m->movable() << ')' << endl;
2105 TempoMap::n_tempos() const
2107 Glib::Threads::RWLock::ReaderLock lm (lock);
2110 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2111 if (dynamic_cast<const TempoSection*>(*i) != 0) {
2120 TempoMap::n_meters() const
2122 Glib::Threads::RWLock::ReaderLock lm (lock);
2125 for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
2126 if (dynamic_cast<const MeterSection*>(*i) != 0) {
2135 TempoMap::insert_time (framepos_t where, framecnt_t amount)
2138 Glib::Threads::RWLock::WriterLock lm (lock);
2139 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2140 if ((*i)->frame() >= where && (*i)->movable ()) {
2141 (*i)->set_frame ((*i)->frame() + amount);
2145 /* now reset the BBT time of all metrics, based on their new
2146 * audio time. This is the only place where we do this reverse
2150 Metrics::iterator i;
2151 const MeterSection* meter;
2152 const TempoSection* tempo;
2156 meter = &first_meter ();
2157 tempo = &first_tempo ();
2162 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
2165 MetricSection* prev = 0;
2167 for (i = metrics.begin(); i != metrics.end(); ++i) {
2170 TempoMetric metric (*meter, *tempo);
2173 metric.set_start (prev->start());
2174 metric.set_frame (prev->frame());
2176 // metric will be at frames=0 bbt=1|1|0 by default
2177 // which is correct for our purpose
2180 bbt_time ((*i)->frame(), bbt);
2182 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
2188 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
2189 /* round up to next beat */
2195 if (bbt.beats != 1) {
2196 /* round up to next bar */
2202 // cerr << bbt << endl;
2204 (*i)->set_start (bbt);
2206 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
2208 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2209 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
2211 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
2213 fatal << _("programming error: unhandled MetricSection type") << endmsg;
2214 abort(); /*NOTREACHED*/
2220 recompute_map (true);
2224 PropertyChanged (PropertyChange ());
2227 TempoMap::remove_time (framepos_t where, framecnt_t amount)
2231 std::list<MetricSection*> metric_kill_list;
2233 TempoSection* last_tempo = NULL;
2234 MeterSection* last_meter = NULL;
2235 bool tempo_after = false; // is there a tempo marker at the first sample after the removed range?
2236 bool meter_after = false; // is there a meter marker likewise?
2238 Glib::Threads::RWLock::WriterLock lm (lock);
2239 for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
2240 if ((*i)->frame() >= where && (*i)->frame() < where+amount) {
2241 metric_kill_list.push_back(*i);
2242 TempoSection *lt = dynamic_cast<TempoSection*> (*i);
2245 MeterSection *lm = dynamic_cast<MeterSection*> (*i);
2249 else if ((*i)->frame() >= where) {
2250 // TODO: make sure that moved tempo/meter markers are rounded to beat/bar boundaries
2251 (*i)->set_frame ((*i)->frame() - amount);
2252 if ((*i)->frame() == where) {
2253 // marker was immediately after end of range
2254 tempo_after = dynamic_cast<TempoSection*> (*i);
2255 meter_after = dynamic_cast<MeterSection*> (*i);
2261 //find the last TEMPO and METER metric (if any) and move it to the cut point so future stuff is correct
2262 if (last_tempo && !tempo_after) {
2263 metric_kill_list.remove(last_tempo);
2264 last_tempo->set_frame(where);
2267 if (last_meter && !meter_after) {
2268 metric_kill_list.remove(last_meter);
2269 last_meter->set_frame(where);
2273 //remove all the remaining metrics
2274 for (std::list<MetricSection*>::iterator i = metric_kill_list.begin(); i != metric_kill_list.end(); ++i) {
2280 recompute_map (true);
2283 PropertyChanged (PropertyChange ());
2287 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2288 * pos can be -ve, if required.
2291 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::Beats beats) const
2293 return frame_at_beat (beat_at_frame (pos) + beats.to_double());
2296 /** Subtract some (fractional) beats from a frame position, and return the result in frames */
2298 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::Beats beats) const
2300 return frame_at_beat (beat_at_frame (pos) - beats.to_double());
2303 /** Add the BBT interval op to pos and return the result */
2305 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2307 cerr << "framepos_plus_bbt - untested" << endl;
2308 Glib::Threads::RWLock::ReaderLock lm (lock);
2310 Metrics::const_iterator i;
2311 const MeterSection* meter;
2312 const MeterSection* m;
2313 const TempoSection* tempo;
2314 const TempoSection* next_tempo = 0;
2315 const TempoSection* t;
2316 double frames_per_beat;
2317 framepos_t effective_pos = max (pos, (framepos_t) 0);
2319 meter = &first_meter ();
2320 tempo = &first_tempo ();
2325 /* find the starting metrics for tempo & meter */
2327 for (i = metrics.begin(); i != metrics.end(); ++i) {
2329 if ((*i)->frame() > effective_pos) {
2333 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2335 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2340 for (i = metrics.begin(); i != metrics.end(); ++i) {
2341 if ((*i)->frame() > effective_pos) {
2342 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2351 meter -> the Meter for "pos"
2352 tempo -> the Tempo for "pos"
2353 next_tempo -> the Tempo after "pos" or 0
2354 i -> for first new metric after "pos", possibly metrics.end()
2357 /* now comes the complicated part. we have to add one beat a time,
2358 checking for a new metric on every beat.
2362 /* fpb is used for constant tempo */
2363 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2370 /* check if we need to use a new metric section: has adding frames moved us
2371 to or after the start of the next metric section? in which case, use it.
2374 if (i != metrics.end()) {
2375 if ((*i)->frame() <= pos) {
2377 /* about to change tempo or meter, so add the
2378 * number of frames for the bars we've just
2379 * traversed before we change the
2380 * frames_per_beat value.
2383 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2388 pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2390 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2395 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2397 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2401 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2408 pos += tempo->frame_at_beat (bars * meter->divisions_per_bar(), next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2410 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2417 /* given the current meter, have we gone past the end of the bar ? */
2422 /* check if we need to use a new metric section: has adding frames moved us
2423 to or after the start of the next metric section? in which case, use it.
2426 if (i != metrics.end()) {
2427 if ((*i)->frame() <= pos) {
2429 /* about to change tempo or meter, so add the
2430 * number of frames for the beats we've just
2431 * traversed before we change the
2432 * frames_per_beat value.
2435 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2440 pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2442 pos += llrint (beats * frames_per_beat);
2447 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2449 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2453 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2459 pos += tempo->frame_at_beat (beats, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2461 pos += llrint (beats * frames_per_beat);
2465 pos += tempo->frame_at_tick (op.ticks, next_tempo->beats_per_minute(), next_tempo->frame(), _frame_rate);
2472 /** Count the number of beats that are equivalent to distance when going forward,
2476 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2478 return Evoral::Beats(beat_at_frame (pos + distance) - beat_at_frame (pos));
2482 bool operator() (const BBT_Time& a, const BBT_Time& b) {
2488 operator<< (std::ostream& o, const Meter& m) {
2489 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2493 operator<< (std::ostream& o, const Tempo& t) {
2494 return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2498 operator<< (std::ostream& o, const MetricSection& section) {
2500 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2502 const TempoSection* ts;
2503 const MeterSection* ms;
2505 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2506 o << *((const Tempo*) ts);
2507 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2508 o << *((const Meter*) ms);