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 /* beats-per-bar is old; divisions-per-bar is new */
172 if ((prop = node.property ("divisions-per-bar")) == 0) {
173 if ((prop = node.property ("beats-per-bar")) == 0) {
174 error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
175 throw failed_constructor();
179 if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
180 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
181 throw failed_constructor();
184 if ((prop = node.property ("note-type")) == 0) {
185 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
186 throw failed_constructor();
189 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
190 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
191 throw failed_constructor();
194 if ((prop = node.property ("movable")) == 0) {
195 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
196 throw failed_constructor();
199 set_movable (string_is_affirmative (prop->value()));
203 MeterSection::get_state() const
205 XMLNode *root = new XMLNode (xml_state_node_name);
207 LocaleGuard lg (X_("POSIX"));
209 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
213 root->add_property ("start", buf);
214 snprintf (buf, sizeof (buf), "%f", _note_type);
215 root->add_property ("note-type", buf);
216 snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
217 root->add_property ("divisions-per-bar", buf);
218 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
219 root->add_property ("movable", buf);
224 /***********************************************************************/
226 struct MetricSectionSorter {
227 bool operator() (const MetricSection* a, const MetricSection* b) {
228 return a->start() < b->start();
232 TempoMap::TempoMap (framecnt_t fr)
234 metrics = new Metrics;
236 last_bbt_valid = false;
243 TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
244 MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
246 t->set_movable (false);
247 m->set_movable (false);
249 /* note: frame time is correct (zero) for both of these */
251 metrics->push_back (t);
252 metrics->push_back (m);
255 TempoMap::~TempoMap ()
260 TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when)
262 if (when == section.start() || !section.movable()) {
266 Glib::RWLock::WriterLock lm (lock);
267 MetricSectionSorter cmp;
269 if (when.beats != 1) {
271 /* position by audio frame, then recompute BBT timestamps from the audio ones */
273 framepos_t frame = frame_time (when);
274 // cerr << "nominal frame time = " << frame << endl;
276 framepos_t prev_frame = round_to_type (frame, -1, Beat);
277 framepos_t next_frame = round_to_type (frame, 1, Beat);
279 // cerr << "previous beat at " << prev_frame << " next at " << next_frame << endl;
281 /* use the closest beat */
283 if ((frame - prev_frame) < (next_frame - frame)) {
289 // cerr << "actual frame time = " << frame << endl;
290 section.set_frame (frame);
291 // cerr << "frame time = " << section.frame() << endl;
292 timestamp_metrics (false);
293 // cerr << "new BBT time = " << section.start() << endl;
298 /* positioned at bar start already, so just put it there */
300 section.set_start (when);
302 timestamp_metrics (true);
310 TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when)
312 if (move_metric_section (tempo, when) == 0) {
313 PropertyChanged (PropertyChange ());
318 TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
320 if (move_metric_section (meter, when) == 0) {
321 PropertyChanged (PropertyChange ());
326 TempoMap::remove_tempo (const TempoSection& tempo)
328 bool removed = false;
331 Glib::RWLock::WriterLock lm (lock);
334 for (i = metrics->begin(); i != metrics->end(); ++i) {
335 if (dynamic_cast<TempoSection*> (*i) != 0) {
336 if (tempo.frame() == (*i)->frame()) {
337 if ((*i)->movable()) {
348 PropertyChanged (PropertyChange ());
353 TempoMap::remove_meter (const MeterSection& tempo)
355 bool removed = false;
358 Glib::RWLock::WriterLock lm (lock);
361 for (i = metrics->begin(); i != metrics->end(); ++i) {
362 if (dynamic_cast<MeterSection*> (*i) != 0) {
363 if (tempo.frame() == (*i)->frame()) {
364 if ((*i)->movable()) {
375 timestamp_metrics (true);
376 PropertyChanged (PropertyChange ());
381 TempoMap::do_insert (MetricSection* section, bool with_bbt)
383 assert (section->start().ticks == 0);
385 /* we only allow new meters to be inserted on beat 1 of an existing
389 if (dynamic_cast<MeterSection*>(section) &&
390 (section->start().beats != 1 || section->start().ticks != 0)) {
392 BBT_Time corrected = section->start();
396 warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
397 section->start(), corrected) << endmsg;
399 section->set_start (corrected);
404 /* Look for any existing MetricSection that is of the same type and
405 at the same time as the new one, and remove it before adding
409 Metrics::iterator to_remove = metrics->end ();
411 for (i = metrics->begin(); i != metrics->end(); ++i) {
413 int const c = (*i)->compare (section, with_bbt);
416 /* this section is before the one to be added; go back round */
419 /* this section is after the one to be added; there can't be any at the same time */
423 /* hacky comparison of type */
424 bool const a = dynamic_cast<TempoSection*> (*i) != 0;
425 bool const b = dynamic_cast<TempoSection*> (section) != 0;
433 if (to_remove != metrics->end()) {
434 /* remove the MetricSection at the same time as the one we are about to add */
435 metrics->erase (to_remove);
438 /* Add the given MetricSection */
440 for (i = metrics->begin(); i != metrics->end(); ++i) {
442 if ((*i)->compare (section, with_bbt) < 0) {
446 metrics->insert (i, section);
450 if (i == metrics->end()) {
451 metrics->insert (metrics->end(), section);
454 timestamp_metrics (with_bbt);
458 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
461 Glib::RWLock::WriterLock lm (lock);
463 /* new tempos always start on a beat */
466 do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), true);
469 PropertyChanged (PropertyChange ());
473 TempoMap::add_tempo (const Tempo& tempo, framepos_t where)
476 Glib::RWLock::WriterLock lm (lock);
477 do_insert (new TempoSection (where, tempo.beats_per_minute(), tempo.note_type()), false);
480 PropertyChanged (PropertyChange ());
484 TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement)
486 bool replaced = false;
489 Glib::RWLock::WriterLock lm (lock);
492 for (i = metrics->begin(); i != metrics->end(); ++i) {
495 if ((ts = dynamic_cast<TempoSection*>(*i)) != 0 && ts == &existing) {
497 *((Tempo *) ts) = replacement;
500 timestamp_metrics (true);
508 PropertyChanged (PropertyChange ());
513 TempoMap::add_meter (const Meter& meter, BBT_Time where)
516 Glib::RWLock::WriterLock lm (lock);
518 /* a new meter always starts a new bar on the first beat. so
519 round the start time appropriately. remember that
520 `where' is based on the existing tempo map, not
521 the result after we insert the new meter.
525 if (where.beats != 1) {
530 /* new meters *always* start on a beat. */
533 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()), true);
536 PropertyChanged (PropertyChange ());
540 TempoMap::add_meter (const Meter& meter, framepos_t where)
543 Glib::RWLock::WriterLock lm (lock);
544 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()), false);
547 PropertyChanged (PropertyChange ());
551 TempoMap::replace_meter (MeterSection& existing, const Meter& replacement)
553 bool replaced = false;
556 Glib::RWLock::WriterLock lm (lock);
559 for (i = metrics->begin(); i != metrics->end(); ++i) {
561 if ((ms = dynamic_cast<MeterSection*>(*i)) != 0 && ms == &existing) {
563 *((Meter*) ms) = replacement;
566 timestamp_metrics (true);
573 PropertyChanged (PropertyChange ());
578 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
580 Tempo newtempo (beats_per_minute, note_type);
583 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
584 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
585 *((Tempo*) t) = newtempo;
586 PropertyChanged (PropertyChange ());
593 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
595 Tempo newtempo (beats_per_minute, note_type);
601 /* find the TempoSection immediately preceding "where"
604 for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
606 if ((*i)->frame() > where) {
612 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
622 error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
631 *((Tempo*)prev) = newtempo;
632 PropertyChanged (PropertyChange ());
636 TempoMap::first_meter () const
638 const MeterSection *m = 0;
640 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
641 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
646 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
652 TempoMap::first_tempo () const
654 const TempoSection *t = 0;
656 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
657 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
662 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
668 TempoMap::timestamp_metrics (bool use_bbt)
676 meter = &first_meter ();
677 tempo = &first_tempo ();
681 // cerr << "\n\n\n ######################\nTIMESTAMP via BBT ##############\n" << endl;
683 framepos_t current = 0;
684 framepos_t section_frames;
688 for (i = metrics->begin(); i != metrics->end(); ++i) {
692 section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
694 current += section_frames;
698 (*i)->set_frame (current);
700 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
702 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
705 fatal << _("programming error: unhandled MetricSection type") << endmsg;
712 // cerr << "\n\n\n ######################\nTIMESTAMP via AUDIO ##############\n" << endl;
715 MetricSection* prev = 0;
717 for (i = metrics->begin(); i != metrics->end(); ++i) {
720 TempoMetric metric (*meter, *tempo);
723 metric.set_start (prev->start());
724 metric.set_frame (prev->frame());
726 // metric will be at frames=0 bbt=1|1|0 by default
727 // which is correct for our purpose
730 bbt_time_with_metric ((*i)->frame(), bbt, metric);
732 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
738 if (bbt.ticks > BBT_Time::ticks_per_beat/2) {
739 /* round up to next beat */
745 if (bbt.beats != 1) {
746 /* round up to next bar */
752 // cerr << bbt << endl;
754 (*i)->set_start (bbt);
756 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
758 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
759 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
761 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
763 fatal << _("programming error: unhandled MetricSection type") << endmsg;
772 // cerr << "###############################################\n\n\n" << endl;
777 TempoMap::metric_at (framepos_t frame) const
779 TempoMetric m (first_meter(), first_tempo());
783 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
784 at something, because we insert the default tempo and meter during
785 TempoMap construction.
787 now see if we can find better candidates.
790 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
792 // cerr << "Looking at a metric section " << **i << endl;
794 if ((*i)->frame() > frame) {
798 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
799 m.set_tempo (*tempo);
800 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
801 m.set_meter (*meter);
804 m.set_frame ((*i)->frame ());
805 m.set_start ((*i)->start ());
808 // cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << endl;
813 TempoMap::metric_at (BBT_Time bbt) const
815 TempoMetric m (first_meter(), first_tempo());
819 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
820 at something, because we insert the default tempo and meter during
821 TempoMap construction.
823 now see if we can find better candidates.
826 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
828 BBT_Time section_start ((*i)->start());
830 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
834 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
835 m.set_tempo (*tempo);
836 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
837 m.set_meter (*meter);
840 m.set_frame ((*i)->frame ());
841 m.set_start (section_start);
848 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt) const
851 Glib::RWLock::ReaderLock lm (lock);
852 bbt_time_unlocked (frame, bbt);
857 TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt) const
859 bbt_time_with_metric (frame, bbt, metric_at (frame));
863 TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetric& metric) const
865 framecnt_t frame_diff;
867 const double divisions_per_bar = metric.meter().divisions_per_bar();
868 const double ticks_per_frame = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
870 // cerr << "*** Compute BBT time for " << frame
871 // << " from metric at " << metric.frame() << " tempo = " << metric.tempo().beats_per_minute () << " meter "
872 // << metric.meter().divisions_per_bar() << '/' << metric.meter().note_divisor()
875 /* now compute how far beyond that point we actually are. */
877 frame_diff = frame - metric.frame();
879 bbt.ticks = metric.start().ticks + (uint32_t)round((double)frame_diff / ticks_per_frame);
880 uint32_t xtra_beats = bbt.ticks / (uint32_t)BBT_Time::ticks_per_beat;
881 bbt.ticks %= (uint32_t)BBT_Time::ticks_per_beat;
883 bbt.beats = metric.start().beats + xtra_beats - 1; // correction for 1-based counting, see below for matching operation.
884 bbt.bars = metric.start().bars + (uint32_t)floor((double)bbt.beats / divisions_per_bar);
885 bbt.beats = (uint32_t)fmod((double)bbt.beats, divisions_per_bar);
887 /* if we have a fractional number of beats per bar, we see if
888 we're in the last beat (the fractional one). if so, we
889 round ticks appropriately and bump to the next bar.
891 double beat_fraction = divisions_per_bar - floor(divisions_per_bar);
893 /* XXX one problem here is that I'm not sure how to handle
894 fractional beats that don't evenly divide ticks_per_beat.
895 If they aren't handled consistently, I would guess we'll
896 continue to have strange discrepancies occuring. Perhaps
897 this will also behave badly in the case of meters like
898 0.1/4, but I can't be bothered to test that.
900 uint32_t ticks_on_last_beat = (uint32_t)floor(BBT_Time::ticks_per_beat * beat_fraction);
902 if (bbt.beats > (uint32_t)floor(divisions_per_bar) && bbt.ticks >= ticks_on_last_beat) {
903 bbt.ticks -= ticks_on_last_beat;
908 bbt.beats++; // correction for 1-based counting, see above for matching operation.
910 // cerr << "-----\t RETURN " << bbt << endl;
914 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
916 /* for this to work with fractional measure types, start and end have to be
917 "legal" BBT types, that means that the beats and ticks should be inside
921 framecnt_t frames = 0;
922 framepos_t start_frame = 0;
923 framepos_t end_frame = 0;
925 TempoMetric m = metric_at (start);
927 uint32_t bar_offset = start.bars - m.start().bars;
929 double beat_offset = bar_offset*m.meter().divisions_per_bar() - (m.start().beats-1) + (start.beats -1)
930 + start.ticks/BBT_Time::ticks_per_beat;
932 start_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
934 // cerr << "from start " << start << " compute frame = " << start_frame
935 // << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
936 // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
941 bar_offset = end.bars - m.start().bars;
943 beat_offset = bar_offset * m.meter().divisions_per_bar() - (m.start().beats -1) + (end.beats - 1)
944 + end.ticks/BBT_Time::ticks_per_beat;
946 end_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
948 // cerr << "from end " << end << " compute frame = " << end_frame
949 // << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
950 // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
953 frames = end_frame - start_frame;
960 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
962 /* this is used in timestamping the metrics by actually counting the beats */
964 framecnt_t frames = 0;
965 uint32_t bar = start.bars;
966 double beat = (double) start.beats;
967 double divisions_counted = 0;
968 double divisions_per_bar = 0;
969 double division_frames = 0;
971 divisions_per_bar = meter.divisions_per_bar();
972 division_frames = meter.frames_per_division (tempo, _frame_rate);
976 while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
978 if (beat >= divisions_per_bar) {
983 if (beat > divisions_per_bar) {
985 /* this is a fractional beat at the end of a fractional bar
986 so it should only count for the fraction
989 divisions_counted -= (ceil(divisions_per_bar) - divisions_per_bar);
998 // cerr << "Counted " << beats_counted << " from " << start << " to " << end
999 // << " bpb were " << divisions_per_bar
1000 // << " fpb was " << beat_frames
1003 frames = (framecnt_t) llrint (floor (divisions_counted * division_frames));
1010 TempoMap::frame_time (const BBT_Time& bbt) const
1012 BBT_Time start ; /* 1|1|0 */
1014 return count_frames_between (start, bbt);
1018 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1020 framecnt_t frames = 0;
1023 bbt_time(pos, when);
1026 Glib::RWLock::ReaderLock lm (lock);
1027 frames = bbt_duration_at_unlocked (when, bbt,dir);
1034 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1036 framecnt_t frames = 0;
1038 double divisions_per_bar;
1041 result.bars = max(1U, when.bars + dir * bbt.bars) ;
1045 TempoMetric metric = metric_at(result);
1046 divisions_per_bar = metric.meter().divisions_per_bar();
1048 /* Reduce things to legal bbt values we have to handle possible
1049 fractional=shorter beats at the end of measures and things like 0|11|9000
1050 as a duration in a 4.5/4 measure the musical decision is that the
1051 fractional beat is also a beat , although a shorter one
1055 result.beats = when.beats + bbt.beats;
1056 result.ticks = when.ticks + bbt.ticks;
1058 while (result.beats >= (divisions_per_bar + 1)) {
1060 result.beats -= (uint32_t) ceil(divisions_per_bar);
1061 metric = metric_at(result); // maybe there is a meter change
1062 divisions_per_bar = metric.meter().divisions_per_bar();
1066 /* We now counted the beats and landed in the target measure, now deal
1067 with ticks this seems complicated, but we want to deal with the
1068 corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1069 with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1073 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1076 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1077 (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_beat
1078 : BBT_Time::ticks_per_beat );
1080 while (result.ticks >= ticks_at_beat) {
1082 result.ticks -= ticks_at_beat;
1083 if (result.beats >= (divisions_per_bar + 1)) {
1086 metric = metric_at(result); // maybe there is a meter change
1087 divisions_per_bar = metric.meter().divisions_per_bar();
1089 ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1090 (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_beat
1091 : BBT_Time::ticks_per_beat);
1096 uint32_t b = bbt.beats;
1099 while (b > when.beats) {
1101 result.bars = max(1U, result.bars);
1102 metric = metric_at(result); // maybe there is a meter change
1103 divisions_per_bar = metric.meter().divisions_per_bar();
1104 if (b >= ceil(divisions_per_bar)) {
1105 b -= (uint32_t) ceil(divisions_per_bar);
1107 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1110 result.beats = when.beats - b;
1114 if (bbt.ticks <= when.ticks) {
1115 result.ticks = when.ticks - bbt.ticks;
1118 uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_beat;
1119 uint32_t t = bbt.ticks - when.ticks;
1123 if (result.beats == 1) {
1125 result.bars = max(1U, result.bars) ;
1126 metric = metric_at(result); // maybe there is a meter change
1127 divisions_per_bar = metric.meter().divisions_per_bar();
1128 result.beats = (uint32_t) ceil(divisions_per_bar);
1129 ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_beat) ;
1132 ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
1135 if (t <= ticks_at_beat) {
1136 result.ticks = ticks_at_beat - t;
1140 } while (t > ticks_at_beat);
1148 frames = count_frames_between(result, when);
1150 frames = count_frames_between(when,result);
1159 TempoMap::round_to_bar (framepos_t fr, int dir)
1162 Glib::RWLock::ReaderLock lm (lock);
1163 return round_to_type (fr, dir, Bar);
1169 TempoMap::round_to_beat (framepos_t fr, int dir)
1172 Glib::RWLock::ReaderLock lm (lock);
1173 return round_to_type (fr, dir, Beat);
1178 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1181 uint32_t ticks_one_half_subdivisions_worth;
1182 uint32_t ticks_one_subdivisions_worth;
1183 uint32_t difference;
1185 bbt_time(fr, the_beat);
1187 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1188 ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1194 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1197 /* right on the subdivision, so the difference is just the subdivision ticks */
1198 difference = ticks_one_subdivisions_worth;
1201 /* not on subdivision, compute distance to next subdivision */
1203 difference = ticks_one_subdivisions_worth - mod;
1206 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1208 } else if (dir < 0) {
1210 /* round to previous */
1212 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1215 /* right on the subdivision, so the difference is just the subdivision ticks */
1216 difference = ticks_one_subdivisions_worth;
1218 /* not on subdivision, compute distance to previous subdivision, which
1219 is just the modulus.
1226 the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1228 /* can't go backwards from wherever pos is, so just return it */
1233 /* round to nearest */
1235 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1236 difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1237 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1239 // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1240 the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1244 return frame_time (the_beat);
1248 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1250 TempoMetric metric = metric_at (frame);
1253 BBT_Time one_bar (1,0,0);
1254 BBT_Time one_beat (0,1,0);
1256 bbt_time_with_metric (frame, bbt, metric);
1260 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1264 /* find bar position preceding frame */
1267 bbt = bbt_subtract (bbt, one_bar);
1275 } else if (dir > 0) {
1277 /* find bar position following frame */
1280 bbt = bbt_add (bbt, one_bar, metric);
1288 /* "true" rounding */
1293 midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1294 midbar_ticks = BBT_Time::ticks_per_beat * fmod (midbar_beats, 1.0f);
1295 midbar_beats = floor (midbar_beats);
1297 BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1310 /* force beats & ticks to their values at the start of a bar */
1316 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1320 /* find beat position preceding frame */
1323 bbt = bbt_subtract (bbt, one_beat);
1331 } else if (dir > 0) {
1333 /* find beat position following frame */
1336 bbt = bbt_add (bbt, one_beat, metric);
1344 /* "true" rounding */
1346 /* round to nearest beat */
1347 if (bbt.ticks >= (BBT_Time::ticks_per_beat/2)) {
1350 bbt = bbt_add (bbt, one_beat, metric);
1357 /* force ticks to the value at the start of a beat */
1363 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)));
1364 return metric.frame() + count_frames_between (metric.start(), bbt);
1367 TempoMap::BBTPointList *
1368 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1371 Metrics::const_iterator i;
1372 BBTPointList *points;
1374 const MeterSection* meter;
1375 const MeterSection* m;
1376 const TempoSection* tempo;
1377 const TempoSection* t;
1380 double divisions_per_bar;
1383 double frames_per_bar;
1389 meter = &first_meter ();
1390 tempo = &first_tempo ();
1392 /* find the starting point */
1394 for (i = metrics->begin(); i != metrics->end(); ++i) {
1396 if ((*i)->frame() > lower) {
1400 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1402 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1409 meter -> the Meter for "lower"
1410 tempo -> the Tempo for "lower"
1411 i -> for first new metric after "lower", possibly metrics->end()
1413 Now start generating points.
1416 divisions_per_bar = meter->divisions_per_bar ();
1417 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1418 beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1420 if (meter->frame() > tempo->frame()) {
1421 bar = meter->start().bars;
1422 beat = meter->start().beats;
1423 current = meter->frame();
1425 bar = tempo->start().bars;
1426 beat = tempo->start().beats;
1427 current = tempo->frame();
1430 /* initialize current to point to the bar/beat just prior to the
1431 lower frame bound passed in. assumes that current is initialized
1432 above to be on a beat.
1435 delta_bars = (lower-current) / frames_per_bar;
1436 delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1437 current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
1439 // adjust bars and beats too
1440 bar += (uint32_t) (floor(delta_bars));
1441 beat += (uint32_t) (floor(delta_beats));
1443 points = new BBTPointList;
1447 if (i == metrics->end()) {
1449 // cerr << "== limit set to end of request @ " << limit << endl;
1451 // cerr << "== limit set to next metric @ " << (*i)->frame() << endl;
1452 limit = (*i)->frame();
1455 limit = min (limit, upper);
1457 while (current < limit) {
1459 /* if we're at the start of a bar, add bar point */
1462 if (current >= lower) {
1463 // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
1464 points->push_back (BBTPoint (*meter, *tempo,(framepos_t)rint(current), Bar, bar, 1));
1469 /* add some beats if we can */
1471 beat_frame = current;
1473 while (beat <= ceil(divisions_per_bar) && beat_frame < limit) {
1474 if (beat_frame >= lower) {
1475 // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
1476 points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
1478 beat_frame += beat_frames;
1479 current+= beat_frames;
1484 // cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
1485 // << (beat > ceil(divisions_per_bar))
1486 // << " beat frame @ " << beat_frame << " vs. " << limit
1489 if (beat > ceil(divisions_per_bar) || i != metrics->end()) {
1491 /* we walked an entire bar. its
1492 important to move `current' forward
1493 by the actual frames_per_bar, not move it to
1494 an integral beat_frame, so that metrics with
1495 non-integral beats-per-bar have
1496 their bar positions set
1497 correctly. consider a metric with
1498 9-1/2 beats-per-bar. the bar we
1499 just filled had 10 beat marks,
1500 but the bar end is 1/2 beat before
1502 And it is also possible that a tempo
1503 change occured in the middle of a bar,
1504 so we subtract the possible extra fraction from the current
1507 if (beat > ceil (divisions_per_bar)) {
1508 /* next bar goes where the numbers suggest */
1509 current -= beat_frames * (ceil(divisions_per_bar)-divisions_per_bar);
1510 // cerr << "++ next bar from numbers\n";
1512 /* next bar goes where the next metric is */
1514 // cerr << "++ next bar at next metric\n";
1522 /* if we're done, then we're done */
1524 if (current >= upper) {
1528 /* i is an iterator that refers to the next metric (or none).
1529 if there is a next metric, move to it, and continue.
1532 if (i != metrics->end()) {
1534 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1536 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1538 /* new MeterSection, beat always returns to 1 */
1542 current = (*i)->frame ();
1543 // cerr << "loop around with current @ " << current << endl;
1545 divisions_per_bar = meter->divisions_per_bar ();
1546 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1547 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1558 TempoMap::tempo_section_at (framepos_t frame) const
1560 Glib::RWLock::ReaderLock lm (lock);
1561 Metrics::const_iterator i;
1562 TempoSection* prev = 0;
1564 for (i = metrics->begin(); i != metrics->end(); ++i) {
1567 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1569 if ((*i)->frame() > frame) {
1585 TempoMap::tempo_at (framepos_t frame) const
1587 TempoMetric m (metric_at (frame));
1593 TempoMap::meter_at (framepos_t frame) const
1595 TempoMetric m (metric_at (frame));
1600 TempoMap::get_state ()
1602 Metrics::const_iterator i;
1603 XMLNode *root = new XMLNode ("TempoMap");
1606 Glib::RWLock::ReaderLock lm (lock);
1607 for (i = metrics->begin(); i != metrics->end(); ++i) {
1608 root->add_child_nocopy ((*i)->get_state());
1616 TempoMap::set_state (const XMLNode& node, int /*version*/)
1619 Glib::RWLock::WriterLock lm (lock);
1622 XMLNodeConstIterator niter;
1623 Metrics old_metrics (*metrics);
1627 nlist = node.children();
1629 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1630 XMLNode* child = *niter;
1632 if (child->name() == TempoSection::xml_state_node_name) {
1635 metrics->push_back (new TempoSection (*child));
1638 catch (failed_constructor& err){
1639 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1640 *metrics = old_metrics;
1644 } else if (child->name() == MeterSection::xml_state_node_name) {
1647 metrics->push_back (new MeterSection (*child));
1650 catch (failed_constructor& err) {
1651 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1652 *metrics = old_metrics;
1658 if (niter == nlist.end()) {
1660 MetricSectionSorter cmp;
1661 metrics->sort (cmp);
1662 timestamp_metrics (true);
1666 PropertyChanged (PropertyChange ());
1672 TempoMap::dump (std::ostream& o) const
1674 const MeterSection* m;
1675 const TempoSection* t;
1677 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1679 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1680 o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
1681 << t->movable() << ')' << endl;
1682 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1683 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1684 << " (move? " << m->movable() << ')' << endl;
1690 TempoMap::n_tempos() const
1692 Glib::RWLock::ReaderLock lm (lock);
1695 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1696 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1705 TempoMap::n_meters() const
1707 Glib::RWLock::ReaderLock lm (lock);
1710 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1711 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1720 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1722 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1723 if ((*i)->frame() >= where && (*i)->movable ()) {
1724 (*i)->set_frame ((*i)->frame() + amount);
1728 timestamp_metrics (false);
1730 PropertyChanged (PropertyChange ());
1734 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1736 TempoMetric metric = metric_at (start);
1737 return bbt_add (start, other, metric);
1741 * add the BBT interval @param increment to @param start and return the result
1744 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1746 BBT_Time result = start;
1747 BBT_Time op = increment; /* argument is const, but we need to modify it */
1748 uint32_t ticks = result.ticks + op.ticks;
1750 if (ticks >= BBT_Time::ticks_per_beat) {
1752 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_beat;
1754 result.ticks += op.ticks;
1757 /* now comes the complicated part. we have to add one beat a time,
1758 checking for a new metric on every beat.
1761 /* grab all meter sections */
1763 list<const MeterSection*> meter_sections;
1765 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1766 const MeterSection* ms;
1767 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1768 meter_sections.push_back (ms);
1772 assert (!meter_sections.empty());
1774 list<const MeterSection*>::const_iterator next_meter;
1775 const Meter* meter = 0;
1777 /* go forwards through the meter sections till we get to the one
1778 covering the current value of result. this positions i to point to
1779 the next meter section too, or the end.
1782 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1784 if (result < (*next_meter)->start()) {
1785 /* this metric is past the result time. stop looking, we have what we need */
1789 if (result == (*next_meter)->start()) {
1790 /* this meter section starts at result, push i beyond it so that it points
1791 to the NEXT section, opwise we will get stuck later, and use this meter section.
1793 meter = *next_meter;
1798 meter = *next_meter;
1801 assert (meter != 0);
1803 /* OK, now have the meter for the bar start we are on, and i is an iterator
1804 that points to the metric after the one we are currently dealing with
1805 (or to metrics->end(), of course)
1810 /* given the current meter, have we gone past the end of the bar ? */
1812 if (result.beats >= meter->divisions_per_bar()) {
1813 /* move to next bar, first beat */
1824 /* check if we need to use a new meter section: has adding beats to result taken us
1825 to or after the start of the next meter section? in which case, use it.
1828 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1829 meter = *next_meter;
1834 /* finally, add bars */
1836 result.bars += op.bars++;
1842 * subtract the BBT interval @param decrement from @param start and return the result
1845 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1847 BBT_Time result = start;
1848 BBT_Time op = decrement; /* argument is const, but we need to modify it */
1850 if (op.ticks > result.ticks) {
1851 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
1853 result.ticks = BBT_Time::ticks_per_beat - (op.ticks - result.ticks);
1855 result.ticks -= op.ticks;
1858 /* now comes the complicated part. we have to subtract one beat a time,
1859 checking for a new metric on every beat.
1862 /* grab all meter sections */
1864 list<const MeterSection*> meter_sections;
1866 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1867 const MeterSection* ms;
1868 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1869 meter_sections.push_back (ms);
1873 assert (!meter_sections.empty());
1875 /* go backwards through the meter sections till we get to the one
1876 covering the current value of result. this positions i to point to
1877 the next (previous) meter section too, or the end.
1880 const MeterSection* meter = 0;
1881 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
1882 // support const_reverse_iterator::operator!=()
1884 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
1886 /* when we find the first meter section that is before or at result, use it,
1887 and set next_meter to the previous one
1890 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
1891 meter = *next_meter;
1897 assert (meter != 0);
1899 /* OK, now have the meter for the bar start we are on, and i is an iterator
1900 that points to the metric after the one we are currently dealing with
1901 (or to metrics->end(), of course)
1906 /* have we reached the start of the bar? if so, move to the last beat of the previous
1907 bar. opwise, just step back 1 beat.
1910 if (result.beats == 1) {
1912 /* move to previous bar, last beat */
1914 if (result.bars <= 1) {
1915 /* i'm sorry dave, i can't do that */
1916 throw std::out_of_range ("illegal BBT subtraction");
1920 result.beats = meter->divisions_per_bar();
1931 /* check if we need to use a new meter section: has subtracting beats to result taken us
1932 to before the start of the current meter section? in which case, use the prior one.
1935 if (result < meter->start() && next_meter != meter_sections.rend()) {
1936 meter = *next_meter;
1941 /* finally, subtract bars */
1943 if (op.bars >= result.bars) {
1944 /* i'm sorry dave, i can't do that */
1945 throw std::out_of_range ("illegal BBT subtraction");
1948 result.bars -= op.bars;
1952 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1953 * pos can be -ve, if required.
1956 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
1958 Metrics::const_iterator i;
1959 const TempoSection* tempo;
1961 /* Find the starting tempo */
1963 for (i = metrics->begin(); i != metrics->end(); ++i) {
1965 /* This is a bit of a hack, but pos could be -ve, and if it is,
1966 we consider the initial metric changes (at time 0) to actually
1967 be in effect at pos.
1969 framepos_t f = (*i)->frame ();
1970 if (pos < 0 && f == 0) {
1978 const TempoSection* t;
1980 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
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;
2010 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2021 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2023 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2025 Metrics::const_iterator i;
2026 const TempoSection* tempo = 0;
2027 const TempoSection* t;
2029 /* Find the starting tempo */
2031 for (i = metrics->begin(); i != metrics->end(); ++i) {
2033 /* This is a bit of a hack, but pos could be -ve, and if it is,
2034 we consider the initial metric changes (at time 0) to actually
2035 be in effect at pos.
2037 framepos_t f = (*i)->frame ();
2038 if (pos < 0 && f == 0) {
2042 if ((*i)->frame() > pos) {
2046 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2051 bool no_more_tempos = false;
2053 /* Move i back to the tempo before "pos" */
2054 if (i != metrics->begin ()) {
2055 while (i != metrics->begin ()) {
2057 t = dynamic_cast<TempoSection*> (*i);
2063 no_more_tempos = true;
2068 tempo -> the Tempo for "pos"
2069 i -> the first metric before "pos", unless no_more_tempos is true
2074 /* Distance to the end of this section in frames */
2075 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2077 /* Distance to the end in beats */
2078 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2080 /* Amount to subtract this time */
2081 double const sub = min (distance_beats, beats);
2085 pos -= sub * tempo->frames_per_beat (_frame_rate);
2087 /* Move i and tempo back, if there's anything to move to */
2088 if (i != metrics->begin ()) {
2089 while (i != metrics->begin ()) {
2091 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2097 no_more_tempos = true;
2104 /** Add the BBT interval op to pos and return the result */
2106 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2108 Metrics::const_iterator i;
2109 const MeterSection* meter;
2110 const MeterSection* m;
2111 const TempoSection* tempo;
2112 const TempoSection* t;
2113 double frames_per_beat;
2115 meter = &first_meter ();
2116 tempo = &first_tempo ();
2121 /* find the starting metrics for tempo & meter */
2123 for (i = metrics->begin(); i != metrics->end(); ++i) {
2125 if ((*i)->frame() > pos) {
2129 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2131 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2138 meter -> the Meter for "pos"
2139 tempo -> the Tempo for "pos"
2140 i -> for first new metric after "pos", possibly metrics->end()
2143 /* now comes the complicated part. we have to add one beat a time,
2144 checking for a new metric on every beat.
2147 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2156 /* check if we need to use a new metric section: has adding frames moved us
2157 to or after the start of the next metric section? in which case, use it.
2160 if (i != metrics->end()) {
2161 if ((*i)->frame() <= pos) {
2163 /* about to change tempo or meter, so add the
2164 * number of frames for the bars we've just
2165 * traversed before we change the
2166 * frames_per_beat value.
2169 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2172 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2174 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2178 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2185 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2191 /* given the current meter, have we gone past the end of the bar ? */
2196 /* check if we need to use a new metric section: has adding frames moved us
2197 to or after the start of the next metric section? in which case, use it.
2200 if (i != metrics->end()) {
2201 if ((*i)->frame() <= pos) {
2203 /* about to change tempo or meter, so add the
2204 * number of frames for the beats we've just
2205 * traversed before we change the
2206 * frames_per_beat value.
2209 pos += llrint (beats * frames_per_beat);
2212 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2214 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2218 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2223 pos += llrint (beats * frames_per_beat);
2226 if (op.ticks >= BBT_Time::ticks_per_beat) {
2227 pos += llrint (frames_per_beat + /* extra beat */
2228 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) /
2229 (double) BBT_Time::ticks_per_beat)));
2231 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2238 /** Count the number of beats that are equivalent to distance when going forward,
2242 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2244 Metrics::const_iterator i;
2245 const TempoSection* tempo;
2247 /* Find the starting tempo */
2249 for (i = metrics->begin(); i != metrics->end(); ++i) {
2251 if ((*i)->frame() > pos) {
2255 const TempoSection* t;
2257 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2264 tempo -> the Tempo for "pos"
2265 i -> the first metric after "pos", possibly metrics->end()
2268 Evoral::MusicalTime beats = 0;
2272 /* End of this section */
2273 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2275 /* Distance to the end in frames */
2276 framecnt_t const distance_to_end = end - pos;
2278 /* Amount to subtract this time */
2279 double const sub = min (distance, distance_to_end);
2284 beats += sub / tempo->frames_per_beat (_frame_rate);
2286 /* Move on if there's anything to move to */
2287 if (i != metrics->end ()) {
2288 const TempoSection* t;
2290 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2301 /** Compare the time of this with that of another MetricSection.
2302 * @param with_bbt True to compare using start(), false to use frame().
2303 * @return -1 for less than, 0 for equal, 1 for greater than.
2307 MetricSection::compare (MetricSection* other, bool with_bbt) const
2310 if (start() == other->start()) {
2312 } else if (start() < other->start()) {
2318 if (frame() == other->frame()) {
2320 } else if (frame() < other->frame()) {
2332 operator<< (std::ostream& o, const Meter& m) {
2333 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2336 operator<< (std::ostream& o, const Tempo& t) {
2337 return o << t.beats_per_minute() << " (1/" << t.note_type() << " per minute)" << endl;
2340 operator<< (std::ostream& o, const MetricSection& section) {
2342 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2344 const TempoSection* ts;
2345 const MeterSection* ms;
2347 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2348 o << *((Tempo*) ts);
2349 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2350 o << *((Meter*) ms);