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.
27 #include <glibmm/thread.h>
28 #include "pbd/xml++.h"
29 #include "evoral/types.hpp"
30 #include "ardour/debug.h"
31 #include "ardour/tempo.h"
32 #include "ardour/utils.h"
38 using namespace ARDOUR;
41 using Timecode::BBT_Time;
43 /* _default tempo is 4/4 qtr=120 */
45 Meter TempoMap::_default_meter (4.0, 4.0);
46 Tempo TempoMap::_default_tempo (120.0);
49 Tempo::frames_per_beat (framecnt_t sr) const
51 return (60.0 * sr) / _beats_per_minute;
54 /***********************************************************************/
57 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
59 return (60.0 * sr * _divisions_per_bar) / tempo.beats_per_minute();
63 Meter::frames_per_division (const Tempo& tempo, framecnt_t sr) const
65 return (60.0 * sr) / (tempo.beats_per_minute() * _note_type/tempo.note_type());
68 /***********************************************************************/
70 const string TempoSection::xml_state_node_name = "Tempo";
72 TempoSection::TempoSection (const XMLNode& node)
73 : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
75 const XMLProperty *prop;
77 LocaleGuard lg (X_("POSIX"));
79 if ((prop = node.property ("start")) == 0) {
80 error << _("TempoSection XML node has no \"start\" property") << endmsg;
81 throw failed_constructor();
84 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
88 error << _("TempoSection XML node has an illegal \"start\" value") << endmsg;
89 throw failed_constructor();
94 if ((prop = node.property ("beats-per-minute")) == 0) {
95 error << _("TempoSection XML node has no \"beats-per-minute\" property") << endmsg;
96 throw failed_constructor();
99 if (sscanf (prop->value().c_str(), "%lf", &_beats_per_minute) != 1 || _beats_per_minute < 0.0) {
100 error << _("TempoSection XML node has an illegal \"beats_per_minute\" value") << endmsg;
101 throw failed_constructor();
104 if ((prop = node.property ("note-type")) == 0) {
105 /* older session, make note type be quarter by default */
108 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 1.0) {
109 error << _("TempoSection XML node has an illegal \"note-type\" value") << endmsg;
110 throw failed_constructor();
114 if ((prop = node.property ("movable")) == 0) {
115 error << _("TempoSection XML node has no \"movable\" property") << endmsg;
116 throw failed_constructor();
119 set_movable (string_is_affirmative (prop->value()));
123 TempoSection::get_state() const
125 XMLNode *root = new XMLNode (xml_state_node_name);
127 LocaleGuard lg (X_("POSIX"));
129 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
133 root->add_property ("start", buf);
134 snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
135 root->add_property ("beats-per-minute", buf);
136 snprintf (buf, sizeof (buf), "%f", _note_type);
137 root->add_property ("note-type", buf);
138 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
139 root->add_property ("movable", buf);
144 /***********************************************************************/
146 const string MeterSection::xml_state_node_name = "Meter";
148 MeterSection::MeterSection (const XMLNode& node)
149 : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
151 const XMLProperty *prop;
153 LocaleGuard lg (X_("POSIX"));
155 if ((prop = node.property ("start")) == 0) {
156 error << _("MeterSection XML node has no \"start\" property") << endmsg;
157 throw failed_constructor();
160 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
164 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
165 throw failed_constructor();
170 if ((prop = node.property ("beats-per-bar")) == 0) {
171 error << _("MeterSection XML node has no \"beats-per-bar\" property") << endmsg;
172 throw failed_constructor();
175 if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
176 error << _("MeterSection XML node has an illegal \"beats-per-bar\" value") << endmsg;
177 throw failed_constructor();
180 if ((prop = node.property ("note-type")) == 0) {
181 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
182 throw failed_constructor();
185 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
186 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
187 throw failed_constructor();
190 if ((prop = node.property ("movable")) == 0) {
191 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
192 throw failed_constructor();
195 set_movable (string_is_affirmative (prop->value()));
199 MeterSection::get_state() const
201 XMLNode *root = new XMLNode (xml_state_node_name);
203 LocaleGuard lg (X_("POSIX"));
205 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
209 root->add_property ("start", buf);
210 snprintf (buf, sizeof (buf), "%f", _note_type);
211 root->add_property ("note-type", buf);
212 snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
213 root->add_property ("beats-per-bar", buf);
214 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
215 root->add_property ("movable", buf);
220 /***********************************************************************/
222 struct MetricSectionSorter {
223 bool operator() (const MetricSection* a, const MetricSection* b) {
224 return a->start() < b->start();
228 TempoMap::TempoMap (framecnt_t fr)
230 metrics = new Metrics;
232 last_bbt_valid = false;
239 TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
240 MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
242 t->set_movable (false);
243 m->set_movable (false);
245 /* note: frame time is correct (zero) for both of these */
247 metrics->push_back (t);
248 metrics->push_back (m);
251 TempoMap::~TempoMap ()
256 TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when)
258 if (when == section.start() || !section.movable()) {
262 Glib::RWLock::WriterLock lm (lock);
263 MetricSectionSorter cmp;
265 if (when.beats != 1) {
267 /* position by audio frame, then recompute BBT timestamps from the audio ones */
269 framepos_t frame = frame_time (when);
270 // cerr << "nominal frame time = " << frame << endl;
272 framepos_t prev_frame = round_to_type (frame, -1, Beat);
273 framepos_t next_frame = round_to_type (frame, 1, Beat);
275 // cerr << "previous beat at " << prev_frame << " next at " << next_frame << endl;
277 /* use the closest beat */
279 if ((frame - prev_frame) < (next_frame - frame)) {
285 // cerr << "actual frame time = " << frame << endl;
286 section.set_frame (frame);
287 // cerr << "frame time = " << section.frame() << endl;
288 timestamp_metrics (false);
289 // cerr << "new BBT time = " << section.start() << endl;
294 /* positioned at bar start already, so just put it there */
296 section.set_start (when);
298 timestamp_metrics (true);
306 TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when)
308 if (move_metric_section (tempo, when) == 0) {
309 PropertyChanged (PropertyChange ());
314 TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
316 if (move_metric_section (meter, when) == 0) {
317 PropertyChanged (PropertyChange ());
322 TempoMap::remove_tempo (const TempoSection& tempo)
324 bool removed = false;
327 Glib::RWLock::WriterLock lm (lock);
330 for (i = metrics->begin(); i != metrics->end(); ++i) {
331 if (dynamic_cast<TempoSection*> (*i) != 0) {
332 if (tempo.frame() == (*i)->frame()) {
333 if ((*i)->movable()) {
344 PropertyChanged (PropertyChange ());
349 TempoMap::remove_meter (const MeterSection& tempo)
351 bool removed = false;
354 Glib::RWLock::WriterLock lm (lock);
357 for (i = metrics->begin(); i != metrics->end(); ++i) {
358 if (dynamic_cast<MeterSection*> (*i) != 0) {
359 if (tempo.frame() == (*i)->frame()) {
360 if ((*i)->movable()) {
371 PropertyChanged (PropertyChange ());
376 TempoMap::do_insert (MetricSection* section, bool with_bbt)
378 assert (section->start().ticks == 0);
380 /* we only allow new meters to be inserted on beat 1 of an existing
384 if (dynamic_cast<MeterSection*>(section) &&
385 (section->start().beats != 1 || section->start().ticks != 0)) {
387 BBT_Time corrected = section->start();
391 warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
392 section->start(), corrected) << endmsg;
394 section->set_start (corrected);
399 /* Look for any existing MetricSection that is of the same type and
400 at the same time as the new one, and remove it before adding
404 Metrics::iterator to_remove = metrics->end ();
406 for (i = metrics->begin(); i != metrics->end(); ++i) {
408 int const c = (*i)->compare (section, with_bbt);
411 /* this section is before the one to be added; go back round */
414 /* this section is after the one to be added; there can't be any at the same time */
418 /* hacky comparison of type */
419 bool const a = dynamic_cast<TempoSection*> (*i) != 0;
420 bool const b = dynamic_cast<TempoSection*> (section) != 0;
428 if (to_remove != metrics->end()) {
429 /* remove the MetricSection at the same time as the one we are about to add */
430 metrics->erase (to_remove);
433 /* Add the given MetricSection */
435 for (i = metrics->begin(); i != metrics->end(); ++i) {
437 if ((*i)->compare (section, with_bbt) < 0) {
441 metrics->insert (i, section);
445 if (i == metrics->end()) {
446 metrics->insert (metrics->end(), section);
449 timestamp_metrics (with_bbt);
453 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
456 Glib::RWLock::WriterLock lm (lock);
458 /* new tempos always start on a beat */
461 do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), true);
464 PropertyChanged (PropertyChange ());
468 TempoMap::add_tempo (const Tempo& tempo, framepos_t where)
471 Glib::RWLock::WriterLock lm (lock);
472 do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), false);
475 PropertyChanged (PropertyChange ());
479 TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement)
481 bool replaced = false;
484 Glib::RWLock::WriterLock lm (lock);
487 for (i = metrics->begin(); i != metrics->end(); ++i) {
490 if ((ts = dynamic_cast<TempoSection*>(*i)) != 0 && ts == &existing) {
492 *((Tempo *) ts) = replacement;
495 timestamp_metrics (true);
503 PropertyChanged (PropertyChange ());
508 TempoMap::add_meter (const Meter& meter, BBT_Time where)
511 Glib::RWLock::WriterLock lm (lock);
513 /* a new meter always starts a new bar on the first beat. so
514 round the start time appropriately. remember that
515 `where' is based on the existing tempo map, not
516 the result after we insert the new meter.
520 if (where.beats != 1) {
525 /* new meters *always* start on a beat. */
528 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()), true);
531 PropertyChanged (PropertyChange ());
535 TempoMap::add_meter (const Meter& meter, framepos_t where)
538 Glib::RWLock::WriterLock lm (lock);
539 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()), false);
542 PropertyChanged (PropertyChange ());
546 TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
548 bool replaced = false;
551 Glib::RWLock::WriterLock lm (lock);
554 for (i = metrics->begin(); i != metrics->end(); ++i) {
556 if ((ms = dynamic_cast<MeterSection*>(*i)) != 0 && ms == &existing) {
558 *((Meter*) ms) = replacement;
561 timestamp_metrics (true);
568 PropertyChanged (PropertyChange ());
573 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
575 Tempo newtempo (beats_per_minute, note_type);
578 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
579 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
580 *((Tempo*) t) = newtempo;
581 PropertyChanged (PropertyChange ());
588 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
590 Tempo newtempo (beats_per_minute, note_type);
596 /* find the TempoSection immediately preceding "where"
599 for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
601 if ((*i)->frame() > where) {
607 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
617 error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
626 *((Tempo*)prev) = newtempo;
627 PropertyChanged (PropertyChange ());
631 TempoMap::first_meter () const
633 const MeterSection *m = 0;
635 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
636 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
641 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
647 TempoMap::first_tempo () const
649 const TempoSection *t = 0;
651 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
652 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
657 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
663 TempoMap::timestamp_metrics (bool use_bbt)
671 meter = &first_meter ();
672 tempo = &first_tempo ();
676 // cerr << "\n\n\n ######################\nTIMESTAMP via BBT ##############\n" << endl;
678 framepos_t current = 0;
679 framepos_t section_frames;
683 for (i = metrics->begin(); i != metrics->end(); ++i) {
687 section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
689 current += section_frames;
693 (*i)->set_frame (current);
695 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
697 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
700 fatal << _("programming error: unhandled MetricSection type") << endmsg;
707 // cerr << "\n\n\n ######################\nTIMESTAMP via AUDIO ##############\n" << endl;
710 MetricSection* prev = 0;
712 for (i = metrics->begin(); i != metrics->end(); ++i) {
715 TempoMetric metric (*meter, *tempo);
718 metric.set_start (prev->start());
719 metric.set_frame (prev->frame());
721 // metric will be at frames=0 bbt=1|1|0 by default
722 // which is correct for our purpose
725 bbt_time_with_metric ((*i)->frame(), bbt, metric);
727 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
733 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
734 /* round up to next beat */
740 if (bbt.beats != 1) {
741 /* round up to next bar */
747 // cerr << bbt << endl;
749 (*i)->set_start (bbt);
751 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
753 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
754 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
756 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
758 fatal << _("programming error: unhandled MetricSection type") << endmsg;
767 // cerr << "###############################################\n\n\n" << endl;
772 TempoMap::metric_at (framepos_t frame) const
774 TempoMetric m (first_meter(), first_tempo());
778 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
779 at something, because we insert the default tempo and meter during
780 TempoMap construction.
782 now see if we can find better candidates.
785 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
787 // cerr << "Looking at a metric section " << **i << endl;
789 if ((*i)->frame() > frame) {
793 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
794 m.set_tempo (*tempo);
795 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
796 m.set_meter (*meter);
799 m.set_frame ((*i)->frame ());
800 m.set_start ((*i)->start ());
803 // cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << endl;
808 TempoMap::metric_at (BBT_Time bbt) const
810 TempoMetric m (first_meter(), first_tempo());
814 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
815 at something, because we insert the default tempo and meter during
816 TempoMap construction.
818 now see if we can find better candidates.
821 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
823 BBT_Time section_start ((*i)->start());
825 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
829 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
830 m.set_tempo (*tempo);
831 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
832 m.set_meter (*meter);
835 m.set_frame ((*i)->frame ());
836 m.set_start (section_start);
843 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt) const
846 Glib::RWLock::ReaderLock lm (lock);
847 bbt_time_unlocked (frame, bbt);
852 TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt) const
854 bbt_time_with_metric (frame, bbt, metric_at (frame));
858 TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetric& metric) const
860 framecnt_t frame_diff;
862 const double divisions_per_bar = metric.meter().divisions_per_bar();
863 const double ticks_per_frame = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
865 // cerr << "*** Compute BBT time for " << frame
866 // << " from metric at " << metric.frame() << " tempo = " << metric.tempo().beats_per_minute () << " meter "
867 // << metric.meter().divisions_per_bar() << '/' << metric.meter().note_divisor()
870 /* now compute how far beyond that point we actually are. */
872 frame_diff = frame - metric.frame();
874 bbt.ticks = metric.start().ticks + (uint32_t)round((double)frame_diff / ticks_per_frame);
875 uint32_t xtra_beats = bbt.ticks / (uint32_t)BBT_Time::ticks_per_beat;
876 bbt.ticks %= (uint32_t)BBT_Time::ticks_per_beat;
878 bbt.beats = metric.start().beats + xtra_beats - 1; // correction for 1-based counting, see below for matching operation.
879 bbt.bars = metric.start().bars + (uint32_t)floor((double)bbt.beats / divisions_per_bar);
880 bbt.beats = (uint32_t)fmod((double)bbt.beats, divisions_per_bar);
882 /* if we have a fractional number of beats per bar, we see if
883 we're in the last beat (the fractional one). if so, we
884 round ticks appropriately and bump to the next bar.
886 double beat_fraction = divisions_per_bar - floor(divisions_per_bar);
888 /* XXX one problem here is that I'm not sure how to handle
889 fractional beats that don't evenly divide ticks_per_beat.
890 If they aren't handled consistently, I would guess we'll
891 continue to have strange discrepancies occuring. Perhaps
892 this will also behave badly in the case of meters like
893 0.1/4, but I can't be bothered to test that.
895 uint32_t ticks_on_last_beat = (uint32_t)floor(BBT_Time::ticks_per_beat * beat_fraction);
897 if (bbt.beats > (uint32_t)floor(divisions_per_bar) && bbt.ticks >= ticks_on_last_beat) {
898 bbt.ticks -= ticks_on_last_beat;
903 bbt.beats++; // correction for 1-based counting, see above for matching operation.
905 // cerr << "-----\t RETURN " << bbt << endl;
909 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
911 /* for this to work with fractional measure types, start and end have to be
912 "legal" BBT types, that means that the beats and ticks should be inside
916 framecnt_t frames = 0;
917 framepos_t start_frame = 0;
918 framepos_t end_frame = 0;
920 TempoMetric m = metric_at (start);
922 uint32_t bar_offset = start.bars - m.start().bars;
924 double beat_offset = bar_offset*m.meter().divisions_per_bar() - (m.start().beats-1) + (start.beats -1)
925 + start.ticks/BBT_Time::ticks_per_beat;
927 start_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
929 // cerr << "from start " << start << " compute frame = " << start_frame
930 // << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
931 // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
936 bar_offset = end.bars - m.start().bars;
938 beat_offset = bar_offset * m.meter().divisions_per_bar() - (m.start().beats -1) + (end.beats - 1)
939 + end.ticks/BBT_Time::ticks_per_beat;
941 end_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
943 // cerr << "from end " << end << " compute frame = " << end_frame
944 // << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
945 // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
948 frames = end_frame - start_frame;
955 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
957 /* this is used in timestamping the metrics by actually counting the beats */
959 framecnt_t frames = 0;
960 uint32_t bar = start.bars;
961 double beat = (double) start.beats;
962 double divisions_counted = 0;
963 double divisions_per_bar = 0;
964 double division_frames = 0;
966 divisions_per_bar = meter.divisions_per_bar();
967 division_frames = meter.frames_per_division (tempo, _frame_rate);
971 while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
973 if (beat >= divisions_per_bar) {
978 if (beat > divisions_per_bar) {
980 /* this is a fractional beat at the end of a fractional bar
981 so it should only count for the fraction
984 divisions_counted -= (ceil(divisions_per_bar) - divisions_per_bar);
993 // cerr << "Counted " << beats_counted << " from " << start << " to " << end
994 // << " bpb were " << divisions_per_bar
995 // << " fpb was " << beat_frames
998 frames = (framecnt_t) llrint (floor (divisions_counted * division_frames));
1005 TempoMap::frame_time (const BBT_Time& bbt) const
1007 BBT_Time start ; /* 1|1|0 */
1009 return count_frames_between (start, bbt);
1013 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1015 framecnt_t frames = 0;
1018 bbt_time(pos, when);
1021 Glib::RWLock::ReaderLock lm (lock);
1022 frames = bbt_duration_at_unlocked (when, bbt,dir);
1029 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1031 framecnt_t frames = 0;
1033 double divisions_per_bar;
1036 result.bars = max(1U, when.bars + dir * bbt.bars) ;
1040 TempoMetric metric = metric_at(result);
1041 divisions_per_bar = metric.meter().divisions_per_bar();
1043 /* Reduce things to legal bbt values we have to handle possible
1044 fractional=shorter beats at the end of measures and things like 0|11|9000
1045 as a duration in a 4.5/4 measure the musical decision is that the
1046 fractional beat is also a beat , although a shorter one
1050 result.beats = when.beats + bbt.beats;
1051 result.ticks = when.ticks + bbt.ticks;
1053 while (result.beats >= (divisions_per_bar + 1)) {
1055 result.beats -= (uint32_t) ceil(divisions_per_bar);
1056 metric = metric_at(result); // maybe there is a meter change
1057 divisions_per_bar = metric.meter().divisions_per_bar();
1061 /* We now counted the beats and landed in the target measure, now deal
1062 with ticks this seems complicated, but we want to deal with the
1063 corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1064 with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1068 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1071 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1072 (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_beat
1073 : BBT_Time::ticks_per_beat );
1075 while (result.ticks >= ticks_at_beat) {
1077 result.ticks -= ticks_at_beat;
1078 if (result.beats >= (divisions_per_bar + 1)) {
1081 metric = metric_at(result); // maybe there is a meter change
1082 divisions_per_bar = metric.meter().divisions_per_bar();
1084 ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1085 (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_beat
1086 : BBT_Time::ticks_per_beat);
1091 uint32_t b = bbt.beats;
1094 while (b > when.beats) {
1096 result.bars = max(1U, result.bars);
1097 metric = metric_at(result); // maybe there is a meter change
1098 divisions_per_bar = metric.meter().divisions_per_bar();
1099 if (b >= ceil(divisions_per_bar)) {
1100 b -= (uint32_t) ceil(divisions_per_bar);
1102 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1105 result.beats = when.beats - b;
1109 if (bbt.ticks <= when.ticks) {
1110 result.ticks = when.ticks - bbt.ticks;
1113 uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_beat;
1114 uint32_t t = bbt.ticks - when.ticks;
1118 if (result.beats == 1) {
1120 result.bars = max(1U, result.bars) ;
1121 metric = metric_at(result); // maybe there is a meter change
1122 divisions_per_bar = metric.meter().divisions_per_bar();
1123 result.beats = (uint32_t) ceil(divisions_per_bar);
1124 ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_beat) ;
1127 ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
1130 if (t <= ticks_at_beat) {
1131 result.ticks = ticks_at_beat - t;
1135 } while (t > ticks_at_beat);
1143 frames = count_frames_between(result, when);
1145 frames = count_frames_between(when,result);
1154 TempoMap::round_to_bar (framepos_t fr, int dir)
1157 Glib::RWLock::ReaderLock lm (lock);
1158 return round_to_type (fr, dir, Bar);
1164 TempoMap::round_to_beat (framepos_t fr, int dir)
1167 Glib::RWLock::ReaderLock lm (lock);
1168 return round_to_type (fr, dir, Beat);
1173 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1176 uint32_t ticks_one_half_subdivisions_worth;
1177 uint32_t ticks_one_subdivisions_worth;
1178 uint32_t difference;
1180 bbt_time(fr, the_beat);
1182 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1183 ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1189 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1192 /* right on the subdivision, so the difference is just the subdivision ticks */
1193 difference = ticks_one_subdivisions_worth;
1196 /* not on subdivision, compute distance to next subdivision */
1198 difference = ticks_one_subdivisions_worth - mod;
1201 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1203 } else if (dir < 0) {
1205 /* round to previous */
1207 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1210 /* right on the subdivision, so the difference is just the subdivision ticks */
1211 difference = ticks_one_subdivisions_worth;
1213 /* not on subdivision, compute distance to previous subdivision, which
1214 is just the modulus.
1221 the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1223 /* can't go backwards from wherever pos is, so just return it */
1228 /* round to nearest */
1230 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1231 difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1232 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1234 // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1235 the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1239 return frame_time (the_beat);
1243 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1245 TempoMetric metric = metric_at (frame);
1248 BBT_Time one_bar (1,0,0);
1249 BBT_Time one_beat (0,1,0);
1251 bbt_time_with_metric (frame, bbt, metric);
1255 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1259 /* find bar position preceding frame */
1262 bbt = bbt_subtract (bbt, one_bar);
1270 } else if (dir > 0) {
1272 /* find bar position following frame */
1275 bbt = bbt_add (bbt, one_bar, metric);
1283 /* "true" rounding */
1288 midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1289 midbar_ticks = BBT_Time::ticks_per_beat * fmod (midbar_beats, 1.0f);
1290 midbar_beats = floor (midbar_beats);
1292 BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1305 /* force beats & ticks to their values at the start of a bar */
1311 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1315 /* find beat position preceding frame */
1318 bbt = bbt_subtract (bbt, one_beat);
1326 } else if (dir > 0) {
1328 /* find beat position following frame */
1331 bbt = bbt_add (bbt, one_beat, metric);
1339 /* "true" rounding */
1341 /* round to nearest beat */
1342 if (bbt.ticks >= (BBT_Time::ticks_per_beat/2)) {
1345 bbt = bbt_add (bbt, one_beat, metric);
1352 /* force ticks to the value at the start of a beat */
1358 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("\tat %1 count frames from %2 to %3 = %4\n", metric.frame(), metric.start(), bbt, count_frames_between (metric.start(), bbt)));
1359 return metric.frame() + count_frames_between (metric.start(), bbt);
1362 TempoMap::BBTPointList *
1363 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1366 Metrics::const_iterator i;
1367 BBTPointList *points;
1369 const MeterSection* meter;
1370 const MeterSection* m;
1371 const TempoSection* tempo;
1372 const TempoSection* t;
1375 double divisions_per_bar;
1378 double frames_per_bar;
1384 meter = &first_meter ();
1385 tempo = &first_tempo ();
1387 /* find the starting point */
1389 for (i = metrics->begin(); i != metrics->end(); ++i) {
1391 if ((*i)->frame() > lower) {
1395 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1397 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1404 meter -> the Meter for "lower"
1405 tempo -> the Tempo for "lower"
1406 i -> for first new metric after "lower", possibly metrics->end()
1408 Now start generating points.
1411 divisions_per_bar = meter->divisions_per_bar ();
1412 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1413 beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1415 if (meter->frame() > tempo->frame()) {
1416 bar = meter->start().bars;
1417 beat = meter->start().beats;
1418 current = meter->frame();
1420 bar = tempo->start().bars;
1421 beat = tempo->start().beats;
1422 current = tempo->frame();
1425 /* initialize current to point to the bar/beat just prior to the
1426 lower frame bound passed in. assumes that current is initialized
1427 above to be on a beat.
1430 delta_bars = (lower-current) / frames_per_bar;
1431 delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1432 current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
1434 // adjust bars and beats too
1435 bar += (uint32_t) (floor(delta_bars));
1436 beat += (uint32_t) (floor(delta_beats));
1438 points = new BBTPointList;
1442 if (i == metrics->end()) {
1444 // cerr << "== limit set to end of request @ " << limit << endl;
1446 // cerr << "== limit set to next metric @ " << (*i)->frame() << endl;
1447 limit = (*i)->frame();
1450 limit = min (limit, upper);
1452 while (current < limit) {
1454 /* if we're at the start of a bar, add bar point */
1457 if (current >= lower) {
1458 // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
1459 points->push_back (BBTPoint (*meter, *tempo,(framepos_t)rint(current), Bar, bar, 1));
1464 /* add some beats if we can */
1466 beat_frame = current;
1468 while (beat <= ceil(divisions_per_bar) && beat_frame < limit) {
1469 if (beat_frame >= lower) {
1470 // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
1471 points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
1473 beat_frame += beat_frames;
1474 current+= beat_frames;
1479 // cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
1480 // << (beat > ceil(divisions_per_bar))
1481 // << " beat frame @ " << beat_frame << " vs. " << limit
1484 if (beat > ceil(divisions_per_bar) || i != metrics->end()) {
1486 /* we walked an entire bar. its
1487 important to move `current' forward
1488 by the actual frames_per_bar, not move it to
1489 an integral beat_frame, so that metrics with
1490 non-integral beats-per-bar have
1491 their bar positions set
1492 correctly. consider a metric with
1493 9-1/2 beats-per-bar. the bar we
1494 just filled had 10 beat marks,
1495 but the bar end is 1/2 beat before
1497 And it is also possible that a tempo
1498 change occured in the middle of a bar,
1499 so we subtract the possible extra fraction from the current
1502 if (beat > ceil (divisions_per_bar)) {
1503 /* next bar goes where the numbers suggest */
1504 current -= beat_frames * (ceil(divisions_per_bar)-divisions_per_bar);
1505 // cerr << "++ next bar from numbers\n";
1507 /* next bar goes where the next metric is */
1509 // cerr << "++ next bar at next metric\n";
1517 /* if we're done, then we're done */
1519 if (current >= upper) {
1523 /* i is an iterator that refers to the next metric (or none).
1524 if there is a next metric, move to it, and continue.
1527 if (i != metrics->end()) {
1529 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1531 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1533 /* new MeterSection, beat always returns to 1 */
1537 current = (*i)->frame ();
1538 // cerr << "loop around with current @ " << current << endl;
1540 divisions_per_bar = meter->divisions_per_bar ();
1541 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1542 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1553 TempoMap::tempo_section_at (framepos_t frame) const
1555 Glib::RWLock::ReaderLock lm (lock);
1556 Metrics::const_iterator i;
1557 TempoSection* prev = 0;
1559 for (i = metrics->begin(); i != metrics->end(); ++i) {
1562 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1564 if ((*i)->frame() > frame) {
1580 TempoMap::tempo_at (framepos_t frame) const
1582 TempoMetric m (metric_at (frame));
1588 TempoMap::meter_at (framepos_t frame) const
1590 TempoMetric m (metric_at (frame));
1595 TempoMap::get_state ()
1597 Metrics::const_iterator i;
1598 XMLNode *root = new XMLNode ("TempoMap");
1601 Glib::RWLock::ReaderLock lm (lock);
1602 for (i = metrics->begin(); i != metrics->end(); ++i) {
1603 root->add_child_nocopy ((*i)->get_state());
1611 TempoMap::set_state (const XMLNode& node, int /*version*/)
1614 Glib::RWLock::WriterLock lm (lock);
1617 XMLNodeConstIterator niter;
1618 Metrics old_metrics (*metrics);
1622 nlist = node.children();
1624 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1625 XMLNode* child = *niter;
1627 if (child->name() == TempoSection::xml_state_node_name) {
1630 metrics->push_back (new TempoSection (*child));
1633 catch (failed_constructor& err){
1634 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1635 *metrics = old_metrics;
1639 } else if (child->name() == MeterSection::xml_state_node_name) {
1642 metrics->push_back (new MeterSection (*child));
1645 catch (failed_constructor& err) {
1646 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1647 *metrics = old_metrics;
1653 if (niter == nlist.end()) {
1655 MetricSectionSorter cmp;
1656 metrics->sort (cmp);
1657 timestamp_metrics (true);
1661 PropertyChanged (PropertyChange ());
1667 TempoMap::dump (std::ostream& o) const
1669 const MeterSection* m;
1670 const TempoSection* t;
1672 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1674 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1675 o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
1676 << t->movable() << ')' << endl;
1677 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1678 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1679 << " (move? " << m->movable() << ')' << endl;
1685 TempoMap::n_tempos() const
1687 Glib::RWLock::ReaderLock lm (lock);
1690 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1691 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1700 TempoMap::n_meters() const
1702 Glib::RWLock::ReaderLock lm (lock);
1705 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1706 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1715 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1717 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1718 if ((*i)->frame() >= where && (*i)->movable ()) {
1719 (*i)->set_frame ((*i)->frame() + amount);
1723 timestamp_metrics (false);
1725 PropertyChanged (PropertyChange ());
1729 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1731 TempoMetric metric = metric_at (start);
1732 return bbt_add (start, other, metric);
1736 * add the BBT interval @param increment to @param start and return the result
1739 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1741 BBT_Time result = start;
1742 BBT_Time op = increment; /* argument is const, but we need to modify it */
1743 uint32_t ticks = result.ticks + op.ticks;
1745 if (ticks >= BBT_Time::ticks_per_beat) {
1747 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_beat;
1749 result.ticks += op.ticks;
1752 /* now comes the complicated part. we have to add one beat a time,
1753 checking for a new metric on every beat.
1756 /* grab all meter sections */
1758 list<const MeterSection*> meter_sections;
1760 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1761 const MeterSection* ms;
1762 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1763 meter_sections.push_back (ms);
1767 assert (!meter_sections.empty());
1769 list<const MeterSection*>::const_iterator next_meter;
1770 const Meter* meter = 0;
1772 /* go forwards through the meter sections till we get to the one
1773 covering the current value of result. this positions i to point to
1774 the next meter section too, or the end.
1777 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1779 if (result < (*next_meter)->start()) {
1780 /* this metric is past the result time. stop looking, we have what we need */
1784 if (result == (*next_meter)->start()) {
1785 /* this meter section starts at result, push i beyond it so that it points
1786 to the NEXT section, opwise we will get stuck later, and use this meter section.
1788 meter = *next_meter;
1793 meter = *next_meter;
1796 assert (meter != 0);
1798 /* OK, now have the meter for the bar start we are on, and i is an iterator
1799 that points to the metric after the one we are currently dealing with
1800 (or to metrics->end(), of course)
1805 /* given the current meter, have we gone past the end of the bar ? */
1807 if (result.beats >= meter->divisions_per_bar()) {
1808 /* move to next bar, first beat */
1819 /* check if we need to use a new meter section: has adding beats to result taken us
1820 to or after the start of the next meter section? in which case, use it.
1823 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1824 meter = *next_meter;
1829 /* finally, add bars */
1831 result.bars += op.bars++;
1837 * subtract the BBT interval @param decrement from @param start and return the result
1840 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1842 BBT_Time result = start;
1843 BBT_Time op = decrement; /* argument is const, but we need to modify it */
1845 if (op.ticks > result.ticks) {
1846 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
1848 result.ticks = BBT_Time::ticks_per_beat - (op.ticks - result.ticks);
1850 result.ticks -= op.ticks;
1853 /* now comes the complicated part. we have to subtract one beat a time,
1854 checking for a new metric on every beat.
1857 /* grab all meter sections */
1859 list<const MeterSection*> meter_sections;
1861 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1862 const MeterSection* ms;
1863 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1864 meter_sections.push_back (ms);
1868 assert (!meter_sections.empty());
1870 /* go backwards through the meter sections till we get to the one
1871 covering the current value of result. this positions i to point to
1872 the next (previous) meter section too, or the end.
1875 const MeterSection* meter = 0;
1876 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
1877 // support const_reverse_iterator::operator!=()
1879 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
1881 /* when we find the first meter section that is before or at result, use it,
1882 and set next_meter to the previous one
1885 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
1886 meter = *next_meter;
1892 assert (meter != 0);
1894 /* OK, now have the meter for the bar start we are on, and i is an iterator
1895 that points to the metric after the one we are currently dealing with
1896 (or to metrics->end(), of course)
1901 /* have we reached the start of the bar? if so, move to the last beat of the previous
1902 bar. opwise, just step back 1 beat.
1905 if (result.beats == 1) {
1907 /* move to previous bar, last beat */
1909 if (result.bars <= 1) {
1910 /* i'm sorry dave, i can't do that */
1911 throw std::out_of_range ("illegal BBT subtraction");
1915 result.beats = meter->divisions_per_bar();
1926 /* check if we need to use a new meter section: has subtracting beats to result taken us
1927 to before the start of the current meter section? in which case, use the prior one.
1930 if (result < meter->start() && next_meter != meter_sections.rend()) {
1931 meter = *next_meter;
1936 /* finally, subtract bars */
1938 if (op.bars >= result.bars) {
1939 /* i'm sorry dave, i can't do that */
1940 throw std::out_of_range ("illegal BBT subtraction");
1943 result.bars -= op.bars;
1947 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1948 * pos can be -ve, if required.
1951 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
1953 Metrics::const_iterator i;
1954 const TempoSection* tempo;
1955 const MeterSection* meter;
1957 /* Find the starting metrics for tempo & meter */
1959 for (i = metrics->begin(); i != metrics->end(); ++i) {
1961 /* This is a bit of a hack, but pos could be -ve, and if it is,
1962 we consider the initial metric changes (at time 0) to actually
1963 be in effect at pos.
1965 framepos_t f = (*i)->frame ();
1966 if (pos < 0 && f == 0) {
1974 const TempoSection* t;
1975 const MeterSection* m;
1977 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1979 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1986 meter -> the Meter for "pos"
1987 tempo -> the Tempo for "pos"
1988 i -> for first new metric after "pos", possibly metrics->end()
1993 /* Distance to the end of this section in frames */
1994 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
1996 /* Distance to the end in beats */
1997 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
1999 /* Amount to subtract this time */
2000 double const sub = min (distance_beats, beats);
2004 pos += sub * tempo->frames_per_beat (_frame_rate);
2006 /* Move on if there's anything to move to */
2007 if (i != metrics->end ()) {
2008 const TempoSection* t;
2009 const MeterSection* m;
2011 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2013 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2024 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2026 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2028 Metrics::const_iterator i;
2029 const TempoSection* tempo = 0;
2030 const MeterSection* meter = 0;
2032 /* Find the starting metrics for tempo & meter */
2034 for (i = metrics->begin(); i != metrics->end(); ++i) {
2036 /* This is a bit of a hack, but pos could be -ve, and if it is,
2037 we consider the initial metric changes (at time 0) to actually
2038 be in effect at pos.
2040 framepos_t f = (*i)->frame ();
2041 if (pos < 0 && f == 0) {
2045 if ((*i)->frame() > pos) {
2049 const TempoSection* t;
2050 const MeterSection* m;
2052 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2054 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2059 bool no_more_metrics = false;
2061 /* Move i back to the metric before "pos" */
2062 if (i != metrics->begin ()) {
2065 no_more_metrics = true;
2070 meter -> the Meter for "pos"
2071 tempo -> the Tempo for "pos"
2072 i -> the first metric before "pos", possibly metrics->end()
2077 /* Distance to the end of this section in frames */
2078 framecnt_t distance_frames = no_more_metrics ? max_framepos : (pos - (*i)->frame());
2080 /* Distance to the end in beats */
2081 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2083 /* Amount to subtract this time */
2084 double const sub = min (distance_beats, beats);
2088 pos -= sub * tempo->frames_per_beat (_frame_rate);
2090 /* Move i, tempo and meter back, if there's anything to move to.
2091 This is more complicated than the forward case, as we have to
2092 a) move back to the previous change in tempo or metric
2093 then b) scan back further to the last change in the opposite thing
2094 so that tempo/meter are both set up correctly.
2096 e.g. if we have (where M is a meter change and T a tempo change):
2099 and we move i back to M2, we must also move tempo back to T3 so
2100 that tempo/meter continue to reflect the current state.
2102 Moving further back we'd move i to T3, and meter to M1, then
2103 i to T2 and meter (still) to M1, etc.
2105 XXX: this is slightly farcical.
2108 if (i != metrics->begin ()) {
2112 bool found_tempo = false;
2113 bool found_meter = false;
2115 const TempoSection* t;
2116 const MeterSection* m;
2118 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2121 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2126 Metrics::const_iterator j = i;
2127 while (j != metrics->begin ()) {
2129 if (found_tempo && ((m = dynamic_cast<const MeterSection*> (*j)) != 0)) {
2132 } else if (found_meter && ((t = dynamic_cast<const TempoSection*> (*j)) != 0)) {
2138 no_more_metrics = true;
2145 /** Add the BBT interval op to pos and return the result */
2147 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2149 Metrics::const_iterator i;
2150 const MeterSection* meter;
2151 const MeterSection* m;
2152 const TempoSection* tempo;
2153 const TempoSection* t;
2154 double frames_per_beat;
2156 meter = &first_meter ();
2157 tempo = &first_tempo ();
2162 /* find the starting metrics for tempo & meter */
2164 for (i = metrics->begin(); i != metrics->end(); ++i) {
2166 if ((*i)->frame() > pos) {
2170 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2172 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2179 meter -> the Meter for "pos"
2180 tempo -> the Tempo for "pos"
2181 i -> for first new metric after "pos", possibly metrics->end()
2184 /* now comes the complicated part. we have to add one beat a time,
2185 checking for a new metric on every beat.
2188 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2197 /* check if we need to use a new metric section: has adding frames moved us
2198 to or after the start of the next metric section? in which case, use it.
2201 if (i != metrics->end()) {
2202 if ((*i)->frame() <= pos) {
2204 /* about to change tempo or meter, so add the
2205 * number of frames for the bars we've just
2206 * traversed before we change the
2207 * frames_per_beat value.
2210 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2213 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2215 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2219 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2226 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2232 /* given the current meter, have we gone past the end of the bar ? */
2237 /* check if we need to use a new metric section: has adding frames moved us
2238 to or after the start of the next metric section? in which case, use it.
2241 if (i != metrics->end()) {
2242 if ((*i)->frame() <= pos) {
2244 /* about to change tempo or meter, so add the
2245 * number of frames for the beats we've just
2246 * traversed before we change the
2247 * frames_per_beat value.
2250 pos += llrint (beats * frames_per_beat);
2253 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2255 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2259 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2264 pos += llrint (beats * frames_per_beat);
2267 if (op.ticks >= BBT_Time::ticks_per_beat) {
2268 pos += llrint (frames_per_beat + /* extra beat */
2269 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) /
2270 (double) BBT_Time::ticks_per_beat)));
2272 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2279 /** Count the number of beats that are equivalent to distance when going forward,
2283 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2285 Metrics::const_iterator i;
2286 const TempoSection* tempo;
2287 const MeterSection* meter;
2289 /* Find the starting metrics for tempo & meter */
2291 for (i = metrics->begin(); i != metrics->end(); ++i) {
2293 if ((*i)->frame() > pos) {
2297 const TempoSection* t;
2298 const MeterSection* m;
2300 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2302 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2309 meter -> the Meter for "pos"
2310 tempo -> the Tempo for "pos"
2311 i -> the first metric after "pos", possibly metrics->end()
2314 Evoral::MusicalTime beats = 0;
2318 /* End of this section */
2319 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2321 /* Distance to the end in frames */
2322 framecnt_t const distance_to_end = end - pos;
2324 /* Amount to subtract this time */
2325 double const sub = min (distance, distance_to_end);
2330 beats += sub / tempo->frames_per_beat (_frame_rate);
2332 /* Move on if there's anything to move to */
2333 if (i != metrics->end ()) {
2334 const TempoSection* t;
2335 const MeterSection* m;
2337 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2339 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2350 /** Compare the time of this with that of another MetricSection.
2351 * @param with_bbt True to compare using start(), false to use frame().
2352 * @return -1 for less than, 0 for equal, 1 for greater than.
2356 MetricSection::compare (MetricSection* other, bool with_bbt) const
2359 if (start() == other->start()) {
2361 } else if (start() < other->start()) {
2367 if (frame() == other->frame()) {
2369 } else if (frame() < other->frame()) {
2381 operator<< (std::ostream& o, const Meter& m) {
2382 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2385 operator<< (std::ostream& o, const Tempo& t) {
2386 return o << t.beats_per_minute() << " (1/" << t.note_type() << " per minute)" << endl;
2389 operator<< (std::ostream& o, const MetricSection& section) {
2391 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2393 const TempoSection* ts;
2394 const MeterSection* ms;
2396 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2397 o << *((Tempo*) ts);
2398 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2399 o << *((Meter*) ms);