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_division (const Tempo& tempo, framecnt_t sr) const
59 return (60.0 * sr) / (tempo.beats_per_minute() * (_note_type/tempo.note_type()));
63 Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
65 return frames_per_division (tempo, sr) * _divisions_per_bar;
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 const double divisions_per_bar = metric.meter().divisions_per_bar();
866 const double frames_per_tick = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_beat;
868 /* now compute how far beyond the metric we actually are, and add the
869 * relevant number of ticks to the metric's BBT time
872 framecnt_t frame_diff = frame - metric.frame();
873 uint32_t tick_diff = (uint32_t) lrint ((double) frame_diff / frames_per_tick);
875 bbt.ticks = metric.start().ticks + tick_diff;
876 uint32_t beat_overflow = bbt.ticks / (uint32_t) BBT_Time::ticks_per_beat;
877 bbt.ticks = bbt.ticks % (uint32_t) BBT_Time::ticks_per_beat;
878 bbt.beats = metric.start().beats + beat_overflow;
879 /* bbt.beats uses 1-based counting, so adjust to get the right answer */
880 uint32_t bar_overflow = (bbt.beats - 1) / (uint32_t) divisions_per_bar;
881 bbt.bars = metric.start().bars + bar_overflow;
883 /* fmod will map bbt.beats as follows:
885 Beats divisions per bar Normalized beat
902 so, the only special cases are 0, N, 2N etc. however bbt.beats is
903 never zero, so the only actual special cases are N, 2N and so on,
904 allowing us to use a special case check for fmod () == 0 and
905 changing the value to divisions per bar
908 bbt.beats = (uint32_t) fmod (bbt.beats, divisions_per_bar);
910 if (bbt.beats == 0) {
911 bbt.beats = divisions_per_bar;
916 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
918 /* for this to work with fractional measure types, start and end have to be
919 "legal" BBT types, that means that the beats and ticks should be inside
923 framecnt_t frames = 0;
924 framepos_t start_frame = 0;
925 framepos_t end_frame = 0;
927 TempoMetric m = metric_at (start);
929 uint32_t bar_offset = start.bars - m.start().bars;
931 double beat_offset = bar_offset*m.meter().divisions_per_bar() - (m.start().beats-1) + (start.beats -1)
932 + start.ticks/BBT_Time::ticks_per_beat;
934 start_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
936 // cerr << "from start " << start << " compute frame = " << start_frame
937 // << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
938 // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
943 bar_offset = end.bars - m.start().bars;
945 beat_offset = bar_offset * m.meter().divisions_per_bar() - (m.start().beats -1) + (end.beats - 1)
946 + end.ticks/BBT_Time::ticks_per_beat;
948 end_frame = m.frame() + (framepos_t) rint(beat_offset * m.meter().frames_per_division(m.tempo(),_frame_rate));
950 // cerr << "from end " << end << " compute frame = " << end_frame
951 // << " from metric at " << m.frame() << " tempo = " << m.tempo().beats_per_minute () << " meter "
952 // << m.meter().divisions_per_bar() << '/' << m.meter().note_divisor()
955 frames = end_frame - start_frame;
962 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
964 /* this is used in timestamping the metrics by actually counting the beats */
966 framecnt_t frames = 0;
967 uint32_t bar = start.bars;
968 double beat = (double) start.beats;
969 double divisions_counted = 0;
970 double divisions_per_bar = 0;
971 double division_frames = 0;
973 divisions_per_bar = meter.divisions_per_bar();
974 division_frames = meter.frames_per_division (tempo, _frame_rate);
978 while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
980 if (beat >= divisions_per_bar) {
985 if (beat > divisions_per_bar) {
987 /* this is a fractional beat at the end of a fractional bar
988 so it should only count for the fraction
991 divisions_counted -= (ceil(divisions_per_bar) - divisions_per_bar);
1000 // cerr << "Counted " << beats_counted << " from " << start << " to " << end
1001 // << " bpb were " << divisions_per_bar
1002 // << " fpb was " << beat_frames
1005 frames = (framecnt_t) llrint (floor (divisions_counted * division_frames));
1012 TempoMap::frame_time (const BBT_Time& bbt) const
1014 BBT_Time start ; /* 1|1|0 */
1016 return count_frames_between (start, bbt);
1020 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1022 framecnt_t frames = 0;
1025 bbt_time(pos, when);
1028 Glib::RWLock::ReaderLock lm (lock);
1029 frames = bbt_duration_at_unlocked (when, bbt,dir);
1036 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1038 framecnt_t frames = 0;
1040 double divisions_per_bar;
1043 result.bars = max(1U, when.bars + dir * bbt.bars) ;
1047 TempoMetric metric = metric_at(result);
1048 divisions_per_bar = metric.meter().divisions_per_bar();
1050 /* Reduce things to legal bbt values we have to handle possible
1051 fractional=shorter beats at the end of measures and things like 0|11|9000
1052 as a duration in a 4.5/4 measure the musical decision is that the
1053 fractional beat is also a beat , although a shorter one
1057 result.beats = when.beats + bbt.beats;
1058 result.ticks = when.ticks + bbt.ticks;
1060 while (result.beats >= (divisions_per_bar + 1)) {
1062 result.beats -= (uint32_t) ceil(divisions_per_bar);
1063 metric = metric_at(result); // maybe there is a meter change
1064 divisions_per_bar = metric.meter().divisions_per_bar();
1068 /* We now counted the beats and landed in the target measure, now deal
1069 with ticks this seems complicated, but we want to deal with the
1070 corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1071 with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1075 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1078 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1079 (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_beat
1080 : BBT_Time::ticks_per_beat );
1082 while (result.ticks >= ticks_at_beat) {
1084 result.ticks -= ticks_at_beat;
1085 if (result.beats >= (divisions_per_bar + 1)) {
1088 metric = metric_at(result); // maybe there is a meter change
1089 divisions_per_bar = metric.meter().divisions_per_bar();
1091 ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1092 (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_beat
1093 : BBT_Time::ticks_per_beat);
1098 uint32_t b = bbt.beats;
1101 while (b > when.beats) {
1103 result.bars = max(1U, result.bars);
1104 metric = metric_at(result); // maybe there is a meter change
1105 divisions_per_bar = metric.meter().divisions_per_bar();
1106 if (b >= ceil(divisions_per_bar)) {
1107 b -= (uint32_t) ceil(divisions_per_bar);
1109 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1112 result.beats = when.beats - b;
1116 if (bbt.ticks <= when.ticks) {
1117 result.ticks = when.ticks - bbt.ticks;
1120 uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_beat;
1121 uint32_t t = bbt.ticks - when.ticks;
1125 if (result.beats == 1) {
1127 result.bars = max(1U, result.bars) ;
1128 metric = metric_at(result); // maybe there is a meter change
1129 divisions_per_bar = metric.meter().divisions_per_bar();
1130 result.beats = (uint32_t) ceil(divisions_per_bar);
1131 ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_beat) ;
1134 ticks_at_beat = (uint32_t) BBT_Time::ticks_per_beat;
1137 if (t <= ticks_at_beat) {
1138 result.ticks = ticks_at_beat - t;
1142 } while (t > ticks_at_beat);
1150 frames = count_frames_between(result, when);
1152 frames = count_frames_between(when,result);
1161 TempoMap::round_to_bar (framepos_t fr, int dir)
1164 Glib::RWLock::ReaderLock lm (lock);
1165 return round_to_type (fr, dir, Bar);
1171 TempoMap::round_to_beat (framepos_t fr, int dir)
1174 Glib::RWLock::ReaderLock lm (lock);
1175 return round_to_type (fr, dir, Beat);
1180 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1183 uint32_t ticks_one_half_subdivisions_worth;
1184 uint32_t ticks_one_subdivisions_worth;
1185 uint32_t difference;
1187 bbt_time(fr, the_beat);
1189 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_beat / sub_num;
1190 ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1196 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1199 /* right on the subdivision, so the difference is just the subdivision ticks */
1200 difference = ticks_one_subdivisions_worth;
1203 /* not on subdivision, compute distance to next subdivision */
1205 difference = ticks_one_subdivisions_worth - mod;
1208 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1210 } else if (dir < 0) {
1212 /* round to previous */
1214 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1217 /* right on the subdivision, so the difference is just the subdivision ticks */
1218 difference = ticks_one_subdivisions_worth;
1220 /* not on subdivision, compute distance to previous subdivision, which
1221 is just the modulus.
1228 the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1230 /* can't go backwards from wherever pos is, so just return it */
1235 /* round to nearest */
1237 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1238 difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1239 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1241 // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1242 the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1246 return frame_time (the_beat);
1250 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1252 TempoMetric metric = metric_at (frame);
1255 BBT_Time one_bar (1,0,0);
1256 BBT_Time one_beat (0,1,0);
1258 bbt_time_with_metric (frame, bbt, metric);
1262 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1266 /* find bar position preceding frame */
1269 bbt = bbt_subtract (bbt, one_bar);
1277 } else if (dir > 0) {
1279 /* find bar position following frame */
1282 bbt = bbt_add (bbt, one_bar, metric);
1290 /* "true" rounding */
1295 midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1296 midbar_ticks = BBT_Time::ticks_per_beat * fmod (midbar_beats, 1.0f);
1297 midbar_beats = floor (midbar_beats);
1299 BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1312 /* force beats & ticks to their values at the start of a bar */
1318 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1322 /* find beat position preceding frame */
1325 bbt = bbt_subtract (bbt, one_beat);
1333 } else if (dir > 0) {
1335 /* find beat position following frame */
1338 bbt = bbt_add (bbt, one_beat, metric);
1346 /* "true" rounding */
1348 /* round to nearest beat */
1349 if (bbt.ticks >= (BBT_Time::ticks_per_beat/2)) {
1352 bbt = bbt_add (bbt, one_beat, metric);
1359 /* force ticks to the value at the start of a beat */
1365 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)));
1366 return metric.frame() + count_frames_between (metric.start(), bbt);
1369 TempoMap::BBTPointList *
1370 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1373 Metrics::const_iterator i;
1374 BBTPointList *points;
1376 const MeterSection* meter;
1377 const MeterSection* m;
1378 const TempoSection* tempo;
1379 const TempoSection* t;
1382 double divisions_per_bar;
1385 double frames_per_bar;
1391 meter = &first_meter ();
1392 tempo = &first_tempo ();
1394 /* find the starting point */
1396 for (i = metrics->begin(); i != metrics->end(); ++i) {
1398 if ((*i)->frame() > lower) {
1402 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1404 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1411 meter -> the Meter for "lower"
1412 tempo -> the Tempo for "lower"
1413 i -> for first new metric after "lower", possibly metrics->end()
1415 Now start generating points.
1418 divisions_per_bar = meter->divisions_per_bar ();
1419 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1420 beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1422 // cerr << "Start with beat frames = " << beat_frames << " bar = " << frames_per_bar << endl;
1424 if (meter->frame() > tempo->frame()) {
1425 bar = meter->start().bars;
1426 beat = meter->start().beats;
1427 current = meter->frame();
1429 bar = tempo->start().bars;
1430 beat = tempo->start().beats;
1431 current = tempo->frame();
1434 /* initialize current to point to the bar/beat just prior to the
1435 lower frame bound passed in. assumes that current is initialized
1436 above to be on a beat.
1439 delta_bars = (lower-current) / frames_per_bar;
1440 delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1441 current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
1443 // adjust bars and beats too
1444 bar += (uint32_t) (floor(delta_bars));
1445 beat += (uint32_t) (floor(delta_beats));
1447 points = new BBTPointList;
1451 if (i == metrics->end()) {
1453 // cerr << "== limit set to end of request @ " << limit << endl;
1455 // cerr << "== limit set to next meter section @ " << (*i)->frame() << endl;
1456 limit = (*i)->frame();
1459 limit = min (limit, upper);
1461 while (current < limit) {
1463 /* if we're at the start of a bar, add bar point */
1466 if (current >= lower) {
1467 // cerr << "Add Bar at " << bar << "|1" << " @ " << current << endl;
1468 points->push_back (BBTPoint (*meter, *tempo,(framepos_t)rint(current), Bar, bar, 1));
1473 /* add some beats if we can */
1475 beat_frame = current;
1477 while (beat <= ceil(divisions_per_bar) && beat_frame < limit) {
1478 if (beat_frame >= lower) {
1479 // cerr << "Add Beat at " << bar << '|' << beat << " @ " << beat_frame << endl;
1480 points->push_back (BBTPoint (*meter, *tempo, (framepos_t) rint(beat_frame), Beat, bar, beat));
1482 beat_frame += beat_frames;
1483 current+= beat_frames;
1488 // cerr << "out of beats, @ end ? " << (i == metrics->end()) << " out of bpb ? "
1489 // << (beat > ceil(divisions_per_bar))
1490 // << " beat frame @ " << beat_frame << " vs. " << limit
1493 if (beat > ceil(divisions_per_bar) || (i != metrics->end() && dynamic_cast<MeterSection*>(*i))) {
1495 /* we've arrived at either the end of a bar or
1498 its important to move `current' forward by
1499 the actual frames_per_bar, not move it to an
1500 integral beat_frame, so that metrics with
1501 non-integral beats-per-bar have their bar
1502 positions set correctly. consider a metric
1503 with 9-1/2 beats-per-bar. the bar we just
1504 filled had 10 beat marks, but the bar end is
1505 1/2 beat before the last beat mark. And it
1506 is also possible that a tempo change occured
1507 in the middle of a bar, so we subtract the
1508 possible extra fraction from the current
1511 if (beat > ceil (divisions_per_bar)) {
1512 /* next bar goes where the numbers suggest */
1513 current -= beat_frames * (ceil(divisions_per_bar)-divisions_per_bar);
1514 // cerr << "++ next bar from numbers\n";
1516 /* next bar goes where the next metric is */
1518 // cerr << "++ next bar at next metric\n";
1525 /* if we're done, then we're done */
1527 if (current >= upper) {
1531 /* i is an iterator that refers to the next metric (or none).
1532 if there is a next metric, move to it, and continue.
1535 if (i != metrics->end()) {
1537 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1539 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1541 /* new MeterSection, beat always returns to 1 */
1545 current = (*i)->frame ();
1546 // cerr << "loop around with current @ " << current << endl;
1548 divisions_per_bar = meter->divisions_per_bar ();
1549 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1550 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1552 // cerr << "New metric with beat frames = " << beat_frames << " bar = " << frames_per_bar << endl;
1563 TempoMap::tempo_section_at (framepos_t frame) const
1565 Glib::RWLock::ReaderLock lm (lock);
1566 Metrics::const_iterator i;
1567 TempoSection* prev = 0;
1569 for (i = metrics->begin(); i != metrics->end(); ++i) {
1572 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1574 if ((*i)->frame() > frame) {
1590 TempoMap::tempo_at (framepos_t frame) const
1592 TempoMetric m (metric_at (frame));
1598 TempoMap::meter_at (framepos_t frame) const
1600 TempoMetric m (metric_at (frame));
1605 TempoMap::get_state ()
1607 Metrics::const_iterator i;
1608 XMLNode *root = new XMLNode ("TempoMap");
1611 Glib::RWLock::ReaderLock lm (lock);
1612 for (i = metrics->begin(); i != metrics->end(); ++i) {
1613 root->add_child_nocopy ((*i)->get_state());
1621 TempoMap::set_state (const XMLNode& node, int /*version*/)
1624 Glib::RWLock::WriterLock lm (lock);
1627 XMLNodeConstIterator niter;
1628 Metrics old_metrics (*metrics);
1632 nlist = node.children();
1634 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1635 XMLNode* child = *niter;
1637 if (child->name() == TempoSection::xml_state_node_name) {
1640 metrics->push_back (new TempoSection (*child));
1643 catch (failed_constructor& err){
1644 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1645 *metrics = old_metrics;
1649 } else if (child->name() == MeterSection::xml_state_node_name) {
1652 metrics->push_back (new MeterSection (*child));
1655 catch (failed_constructor& err) {
1656 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1657 *metrics = old_metrics;
1663 if (niter == nlist.end()) {
1665 MetricSectionSorter cmp;
1666 metrics->sort (cmp);
1667 timestamp_metrics (true);
1671 PropertyChanged (PropertyChange ());
1677 TempoMap::dump (std::ostream& o) const
1679 const MeterSection* m;
1680 const TempoSection* t;
1682 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1684 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1685 o << "Tempo @ " << *i << ' ' << t->beats_per_minute() << " BPM (denom = " << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (move? "
1686 << t->movable() << ')' << endl;
1687 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1688 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1689 << " (move? " << m->movable() << ')' << endl;
1695 TempoMap::n_tempos() const
1697 Glib::RWLock::ReaderLock lm (lock);
1700 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1701 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1710 TempoMap::n_meters() const
1712 Glib::RWLock::ReaderLock lm (lock);
1715 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1716 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1725 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1727 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1728 if ((*i)->frame() >= where && (*i)->movable ()) {
1729 (*i)->set_frame ((*i)->frame() + amount);
1733 timestamp_metrics (false);
1735 PropertyChanged (PropertyChange ());
1739 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1741 TempoMetric metric = metric_at (start);
1742 return bbt_add (start, other, metric);
1746 * add the BBT interval @param increment to @param start and return the result
1749 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1751 BBT_Time result = start;
1752 BBT_Time op = increment; /* argument is const, but we need to modify it */
1753 uint32_t ticks = result.ticks + op.ticks;
1755 if (ticks >= BBT_Time::ticks_per_beat) {
1757 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_beat;
1759 result.ticks += op.ticks;
1762 /* now comes the complicated part. we have to add one beat a time,
1763 checking for a new metric on every beat.
1766 /* grab all meter sections */
1768 list<const MeterSection*> meter_sections;
1770 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1771 const MeterSection* ms;
1772 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1773 meter_sections.push_back (ms);
1777 assert (!meter_sections.empty());
1779 list<const MeterSection*>::const_iterator next_meter;
1780 const Meter* meter = 0;
1782 /* go forwards through the meter sections till we get to the one
1783 covering the current value of result. this positions i to point to
1784 the next meter section too, or the end.
1787 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1789 if (result < (*next_meter)->start()) {
1790 /* this metric is past the result time. stop looking, we have what we need */
1794 if (result == (*next_meter)->start()) {
1795 /* this meter section starts at result, push i beyond it so that it points
1796 to the NEXT section, opwise we will get stuck later, and use this meter section.
1798 meter = *next_meter;
1803 meter = *next_meter;
1806 assert (meter != 0);
1808 /* OK, now have the meter for the bar start we are on, and i is an iterator
1809 that points to the metric after the one we are currently dealing with
1810 (or to metrics->end(), of course)
1815 /* given the current meter, have we gone past the end of the bar ? */
1817 if (result.beats >= meter->divisions_per_bar()) {
1818 /* move to next bar, first beat */
1829 /* check if we need to use a new meter section: has adding beats to result taken us
1830 to or after the start of the next meter section? in which case, use it.
1833 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1834 meter = *next_meter;
1839 /* finally, add bars */
1841 result.bars += op.bars++;
1847 * subtract the BBT interval @param decrement from @param start and return the result
1850 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1852 BBT_Time result = start;
1853 BBT_Time op = decrement; /* argument is const, but we need to modify it */
1855 if (op.ticks > result.ticks) {
1856 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
1858 result.ticks = BBT_Time::ticks_per_beat - (op.ticks - result.ticks);
1860 result.ticks -= op.ticks;
1863 /* now comes the complicated part. we have to subtract one beat a time,
1864 checking for a new metric on every beat.
1867 /* grab all meter sections */
1869 list<const MeterSection*> meter_sections;
1871 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1872 const MeterSection* ms;
1873 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1874 meter_sections.push_back (ms);
1878 assert (!meter_sections.empty());
1880 /* go backwards through the meter sections till we get to the one
1881 covering the current value of result. this positions i to point to
1882 the next (previous) meter section too, or the end.
1885 const MeterSection* meter = 0;
1886 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
1887 // support const_reverse_iterator::operator!=()
1889 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
1891 /* when we find the first meter section that is before or at result, use it,
1892 and set next_meter to the previous one
1895 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
1896 meter = *next_meter;
1902 assert (meter != 0);
1904 /* OK, now have the meter for the bar start we are on, and i is an iterator
1905 that points to the metric after the one we are currently dealing with
1906 (or to metrics->end(), of course)
1911 /* have we reached the start of the bar? if so, move to the last beat of the previous
1912 bar. opwise, just step back 1 beat.
1915 if (result.beats == 1) {
1917 /* move to previous bar, last beat */
1919 if (result.bars <= 1) {
1920 /* i'm sorry dave, i can't do that */
1921 throw std::out_of_range ("illegal BBT subtraction");
1925 result.beats = meter->divisions_per_bar();
1936 /* check if we need to use a new meter section: has subtracting beats to result taken us
1937 to before the start of the current meter section? in which case, use the prior one.
1940 if (result < meter->start() && next_meter != meter_sections.rend()) {
1941 meter = *next_meter;
1946 /* finally, subtract bars */
1948 if (op.bars >= result.bars) {
1949 /* i'm sorry dave, i can't do that */
1950 throw std::out_of_range ("illegal BBT subtraction");
1953 result.bars -= op.bars;
1957 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1958 * pos can be -ve, if required.
1961 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
1963 Metrics::const_iterator i;
1964 const TempoSection* tempo;
1966 /* Find the starting tempo */
1968 for (i = metrics->begin(); i != metrics->end(); ++i) {
1970 /* This is a bit of a hack, but pos could be -ve, and if it is,
1971 we consider the initial metric changes (at time 0) to actually
1972 be in effect at pos.
1974 framepos_t f = (*i)->frame ();
1975 if (pos < 0 && f == 0) {
1983 const TempoSection* t;
1985 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1992 tempo -> the Tempo for "pos"
1993 i -> for first new metric after "pos", possibly metrics->end()
1998 /* Distance to the end of this section in frames */
1999 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
2001 /* Distance to the end in beats */
2002 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2004 /* Amount to subtract this time */
2005 double const sub = min (distance_beats, beats);
2009 pos += sub * tempo->frames_per_beat (_frame_rate);
2011 /* Move on if there's anything to move to */
2012 if (i != metrics->end ()) {
2013 const TempoSection* t;
2015 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2026 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2028 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2030 Metrics::const_iterator i;
2031 const TempoSection* tempo = 0;
2032 const TempoSection* t;
2034 /* Find the starting tempo */
2036 for (i = metrics->begin(); i != metrics->end(); ++i) {
2038 /* This is a bit of a hack, but pos could be -ve, and if it is,
2039 we consider the initial metric changes (at time 0) to actually
2040 be in effect at pos.
2042 framepos_t f = (*i)->frame ();
2043 if (pos < 0 && f == 0) {
2047 if ((*i)->frame() > pos) {
2051 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2056 bool no_more_tempos = false;
2058 /* Move i back to the tempo before "pos" */
2059 if (i != metrics->begin ()) {
2060 while (i != metrics->begin ()) {
2062 t = dynamic_cast<TempoSection*> (*i);
2068 no_more_tempos = true;
2073 tempo -> the Tempo for "pos"
2074 i -> the first metric before "pos", unless no_more_tempos is true
2079 /* Distance to the end of this section in frames */
2080 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2082 /* Distance to the end in beats */
2083 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2085 /* Amount to subtract this time */
2086 double const sub = min (distance_beats, beats);
2090 pos -= sub * tempo->frames_per_beat (_frame_rate);
2092 /* Move i and tempo back, if there's anything to move to */
2093 if (i != metrics->begin ()) {
2094 while (i != metrics->begin ()) {
2096 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2102 no_more_tempos = true;
2109 /** Add the BBT interval op to pos and return the result */
2111 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2113 Metrics::const_iterator i;
2114 const MeterSection* meter;
2115 const MeterSection* m;
2116 const TempoSection* tempo;
2117 const TempoSection* t;
2118 double frames_per_beat;
2120 meter = &first_meter ();
2121 tempo = &first_tempo ();
2126 /* find the starting metrics for tempo & meter */
2128 for (i = metrics->begin(); i != metrics->end(); ++i) {
2130 if ((*i)->frame() > pos) {
2134 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2136 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2143 meter -> the Meter for "pos"
2144 tempo -> the Tempo for "pos"
2145 i -> for first new metric after "pos", possibly metrics->end()
2148 /* now comes the complicated part. we have to add one beat a time,
2149 checking for a new metric on every beat.
2152 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2161 /* check if we need to use a new metric section: has adding frames moved us
2162 to or after the start of the next metric section? in which case, use it.
2165 if (i != metrics->end()) {
2166 if ((*i)->frame() <= pos) {
2168 /* about to change tempo or meter, so add the
2169 * number of frames for the bars we've just
2170 * traversed before we change the
2171 * frames_per_beat value.
2174 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2177 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2179 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2183 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2190 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2196 /* given the current meter, have we gone past the end of the bar ? */
2201 /* check if we need to use a new metric section: has adding frames moved us
2202 to or after the start of the next metric section? in which case, use it.
2205 if (i != metrics->end()) {
2206 if ((*i)->frame() <= pos) {
2208 /* about to change tempo or meter, so add the
2209 * number of frames for the beats we've just
2210 * traversed before we change the
2211 * frames_per_beat value.
2214 pos += llrint (beats * frames_per_beat);
2217 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2219 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2223 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2228 pos += llrint (beats * frames_per_beat);
2231 if (op.ticks >= BBT_Time::ticks_per_beat) {
2232 pos += llrint (frames_per_beat + /* extra beat */
2233 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_beat) /
2234 (double) BBT_Time::ticks_per_beat)));
2236 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_beat));
2243 /** Count the number of beats that are equivalent to distance when going forward,
2247 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2249 Metrics::const_iterator i;
2250 const TempoSection* tempo;
2252 /* Find the starting tempo */
2254 for (i = metrics->begin(); i != metrics->end(); ++i) {
2256 if ((*i)->frame() > pos) {
2260 const TempoSection* t;
2262 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2269 tempo -> the Tempo for "pos"
2270 i -> the first metric after "pos", possibly metrics->end()
2273 Evoral::MusicalTime beats = 0;
2277 /* End of this section */
2278 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2280 /* Distance to the end in frames */
2281 framecnt_t const distance_to_end = end - pos;
2283 /* Amount to subtract this time */
2284 double const sub = min (distance, distance_to_end);
2289 beats += sub / tempo->frames_per_beat (_frame_rate);
2291 /* Move on if there's anything to move to */
2292 if (i != metrics->end ()) {
2293 const TempoSection* t;
2295 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2306 /** Compare the time of this with that of another MetricSection.
2307 * @param with_bbt True to compare using start(), false to use frame().
2308 * @return -1 for less than, 0 for equal, 1 for greater than.
2312 MetricSection::compare (MetricSection* other, bool with_bbt) const
2315 if (start() == other->start()) {
2317 } else if (start() < other->start()) {
2323 if (frame() == other->frame()) {
2325 } else if (frame() < other->frame()) {
2337 operator<< (std::ostream& o, const Meter& m) {
2338 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2341 operator<< (std::ostream& o, const Tempo& t) {
2342 return o << t.beats_per_minute() << " (1/" << t.note_type() << " per minute)" << endl;
2345 operator<< (std::ostream& o, const MetricSection& section) {
2347 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2349 const TempoSection* ts;
2350 const MeterSection* ms;
2352 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2353 o << *((Tempo*) ts);
2354 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2355 o << *((Meter*) ms);