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()));
121 if ((prop = node.property ("bar-offset")) == 0) {
124 if (sscanf (prop->value().c_str(), "%lf", &_bar_offset) != 1 || _bar_offset < 0.0) {
125 error << _("TempoSection XML node has an illegal \"bar-offset\" value") << endmsg;
126 throw failed_constructor();
132 TempoSection::get_state() const
134 XMLNode *root = new XMLNode (xml_state_node_name);
136 LocaleGuard lg (X_("POSIX"));
138 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
142 root->add_property ("start", buf);
143 snprintf (buf, sizeof (buf), "%f", _beats_per_minute);
144 root->add_property ("beats-per-minute", buf);
145 snprintf (buf, sizeof (buf), "%f", _note_type);
146 root->add_property ("note-type", buf);
147 // snprintf (buf, sizeof (buf), "%f", _bar_offset);
148 // root->add_property ("bar-offset", buf);
149 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
150 root->add_property ("movable", buf);
157 TempoSection::update_bar_offset_from_bbt (const Meter& m)
159 _bar_offset = ((double) (start().beats - 1) + (start().ticks/Timecode::BBT_Time::ticks_per_bar_division)) /
160 (m.divisions_per_bar() - 1);
162 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar()));
166 TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
170 if (_bar_offset < 0.0) {
175 new_start.bars = start().bars;
177 double ticks = BBT_Time::ticks_per_bar_division * (_bar_offset * (meter.divisions_per_bar() - 1));
178 new_start.beats = (uint32_t) floor(ticks/BBT_Time::ticks_per_bar_division);
179 new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_bar_division);
181 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
182 _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
184 /* remember the 1-based counting properties of beats */
185 new_start.beats += 1;
187 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("tempo updated BBT time to %1 from bar offset %2 w/dpb = %3\n", new_start, _bar_offset, meter.divisions_per_bar()));
189 set_start (new_start);
192 /***********************************************************************/
194 const string MeterSection::xml_state_node_name = "Meter";
196 MeterSection::MeterSection (const XMLNode& node)
197 : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
199 const XMLProperty *prop;
201 LocaleGuard lg (X_("POSIX"));
203 if ((prop = node.property ("start")) == 0) {
204 error << _("MeterSection XML node has no \"start\" property") << endmsg;
205 throw failed_constructor();
208 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
212 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
213 throw failed_constructor();
218 /* beats-per-bar is old; divisions-per-bar is new */
220 if ((prop = node.property ("divisions-per-bar")) == 0) {
221 if ((prop = node.property ("beats-per-bar")) == 0) {
222 error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
223 throw failed_constructor();
227 if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
228 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
229 throw failed_constructor();
232 if ((prop = node.property ("note-type")) == 0) {
233 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
234 throw failed_constructor();
237 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
238 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
239 throw failed_constructor();
242 if ((prop = node.property ("movable")) == 0) {
243 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
244 throw failed_constructor();
247 set_movable (string_is_affirmative (prop->value()));
251 MeterSection::get_state() const
253 XMLNode *root = new XMLNode (xml_state_node_name);
255 LocaleGuard lg (X_("POSIX"));
257 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
261 root->add_property ("start", buf);
262 snprintf (buf, sizeof (buf), "%f", _note_type);
263 root->add_property ("note-type", buf);
264 snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
265 root->add_property ("divisions-per-bar", buf);
266 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
267 root->add_property ("movable", buf);
272 /***********************************************************************/
274 struct MetricSectionSorter {
275 bool operator() (const MetricSection* a, const MetricSection* b) {
276 return a->start() < b->start();
280 TempoMap::TempoMap (framecnt_t fr)
282 metrics = new Metrics;
284 last_bbt_valid = false;
291 TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
292 MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
294 t->set_movable (false);
295 m->set_movable (false);
297 /* note: frame time is correct (zero) for both of these */
299 metrics->push_back (t);
300 metrics->push_back (m);
303 TempoMap::~TempoMap ()
308 TempoMap::remove_tempo (const TempoSection& tempo, bool send_signal)
310 bool removed = false;
313 Glib::RWLock::WriterLock lm (lock);
316 for (i = metrics->begin(); i != metrics->end(); ++i) {
317 if (dynamic_cast<TempoSection*> (*i) != 0) {
318 if (tempo.frame() == (*i)->frame()) {
319 if ((*i)->movable()) {
330 timestamp_metrics (false);
332 PropertyChanged (PropertyChange ());
338 TempoMap::remove_meter (const MeterSection& tempo, bool send_signal)
340 bool removed = false;
343 Glib::RWLock::WriterLock lm (lock);
346 for (i = metrics->begin(); i != metrics->end(); ++i) {
347 if (dynamic_cast<MeterSection*> (*i) != 0) {
348 if (tempo.frame() == (*i)->frame()) {
349 if ((*i)->movable()) {
360 timestamp_metrics (true);
362 PropertyChanged (PropertyChange ());
368 TempoMap::do_insert (MetricSection* section)
370 bool reassign_tempo_bbt = false;
372 assert (section->start().ticks == 0);
374 /* we only allow new meters to be inserted on beat 1 of an existing
378 if (dynamic_cast<MeterSection*>(section)) {
380 /* we need to (potentially) update the BBT times of tempo
381 sections based on this new meter.
384 reassign_tempo_bbt = true;
386 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
388 BBT_Time corrected = section->start();
392 warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
393 section->start(), corrected) << endmsg;
395 section->set_start (corrected);
401 /* Look for any existing MetricSection that is of the same type and
402 at the same time as the new one, and remove it before adding
406 Metrics::iterator to_remove = metrics->end ();
408 for (i = metrics->begin(); i != metrics->end(); ++i) {
410 int const c = (*i)->compare (*section);
413 /* this section is before the one to be added; go back round */
416 /* this section is after the one to be added; there can't be any at the same time */
420 /* hacky comparison of type */
421 bool const a = dynamic_cast<TempoSection*> (*i) != 0;
422 bool const b = dynamic_cast<TempoSection*> (section) != 0;
430 if (to_remove != metrics->end()) {
431 /* remove the MetricSection at the same time as the one we are about to add */
432 metrics->erase (to_remove);
435 /* Add the given MetricSection */
437 for (i = metrics->begin(); i != metrics->end(); ++i) {
439 if ((*i)->compare (*section) < 0) {
443 metrics->insert (i, section);
447 if (i == metrics->end()) {
448 metrics->insert (metrics->end(), section);
451 timestamp_metrics (reassign_tempo_bbt);
455 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where)
457 const TempoSection& first (first_tempo());
460 remove_tempo (ts, false);
461 add_tempo (tempo, where);
463 /* cannot move the first tempo section */
464 *((Tempo*)&first) = tempo;
465 timestamp_metrics (false);
468 PropertyChanged (PropertyChange ());
472 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
475 Glib::RWLock::WriterLock lm (lock);
477 /* new tempos always start on a beat */
480 TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type());
482 /* find the meter to use to set the bar offset of this
486 const Meter* meter = &first_meter();
488 /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
489 at something, because we insert the default tempo and meter during
490 TempoMap construction.
492 now see if we can find better candidates.
495 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
497 const MeterSection* m;
499 if (where < (*i)->start()) {
503 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
508 ts->update_bar_offset_from_bbt (*meter);
515 PropertyChanged (PropertyChange ());
519 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
521 const MeterSection& first (first_meter());
524 remove_meter (ms, false);
525 add_meter (meter, where);
527 /* cannot move the first meter section */
528 *((Meter*)&first) = meter;
529 timestamp_metrics (true);
532 PropertyChanged (PropertyChange ());
536 TempoMap::add_meter (const Meter& meter, BBT_Time where)
539 Glib::RWLock::WriterLock lm (lock);
541 /* a new meter always starts a new bar on the first beat. so
542 round the start time appropriately. remember that
543 `where' is based on the existing tempo map, not
544 the result after we insert the new meter.
548 if (where.beats != 1) {
553 /* new meters *always* start on a beat. */
556 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
560 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
565 PropertyChanged (PropertyChange ());
569 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
571 Tempo newtempo (beats_per_minute, note_type);
574 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
575 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
576 *((Tempo*) t) = newtempo;
577 PropertyChanged (PropertyChange ());
584 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
586 Tempo newtempo (beats_per_minute, note_type);
592 /* find the TempoSection immediately preceding "where"
595 for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
597 if ((*i)->frame() > where) {
603 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
613 error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
622 *((Tempo*)prev) = newtempo;
623 PropertyChanged (PropertyChange ());
627 TempoMap::first_meter () const
629 const MeterSection *m = 0;
631 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
632 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
637 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
643 TempoMap::first_tempo () const
645 const TempoSection *t = 0;
647 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
648 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
653 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
659 TempoMap::timestamp_metrics_from_audio_time ()
662 const MeterSection* meter;
663 const TempoSection* tempo;
667 meter = &first_meter ();
668 tempo = &first_tempo ();
673 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
676 MetricSection* prev = 0;
678 for (i = metrics->begin(); i != metrics->end(); ++i) {
681 TempoMetric metric (*meter, *tempo);
684 metric.set_start (prev->start());
685 metric.set_frame (prev->frame());
687 // metric will be at frames=0 bbt=1|1|0 by default
688 // which is correct for our purpose
691 bbt_time_with_metric ((*i)->frame(), bbt, metric);
693 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
699 if (bbt.ticks > BBT_Time::ticks_per_bar_division/2) {
700 /* round up to next beat */
706 if (bbt.beats != 1) {
707 /* round up to next bar */
713 // cerr << bbt << endl;
715 (*i)->set_start (bbt);
717 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
719 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
720 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
722 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
724 fatal << _("programming error: unhandled MetricSection type") << endmsg;
732 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
740 TempoMap::timestamp_metrics (bool reassign_tempo_bbt)
743 const MeterSection* meter;
744 const TempoSection* tempo;
748 DEBUG_TRACE (DEBUG::TempoMath, "###################### TIMESTAMP via BBT ##############\n");
750 framepos_t current = 0;
751 framepos_t section_frames;
755 if (reassign_tempo_bbt) {
757 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
759 meter = &first_meter ();
760 tempo = &first_tempo ();
762 for (i = metrics->begin(); i != metrics->end(); ++i) {
764 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
766 /* reassign the BBT time of this tempo section
767 * based on its bar offset position.
770 t->update_bbt_time_from_bar_offset (*meter);
773 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
776 fatal << _("programming error: unhandled MetricSection type") << endmsg;
782 meter = &first_meter ();
783 tempo = &first_tempo ();
785 for (i = metrics->begin(); i != metrics->end(); ++i) {
789 section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
790 current += section_frames;
792 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frames between %1 & %2 = %3 using %4 & %6 puts %7 at %8\n",
793 start, end, section_frames,
794 *((Meter*) meter), *((Tempo*) tempo),
795 (*i)->start(), current));
799 (*i)->set_frame (current);
801 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
803 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
806 fatal << _("programming error: unhandled MetricSection type") << endmsg;
813 if (DEBUG_ENABLED(DEBUG::TempoMath)) {
818 DEBUG_TRACE (DEBUG::TempoMath, "###############################################\n");
823 TempoMap::metric_at (framepos_t frame) const
825 TempoMetric m (first_meter(), first_tempo());
829 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
830 at something, because we insert the default tempo and meter during
831 TempoMap construction.
833 now see if we can find better candidates.
836 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
838 // cerr << "Looking at a metric section " << **i << endl;
840 if ((*i)->frame() > frame) {
844 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
845 m.set_tempo (*tempo);
846 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
847 m.set_meter (*meter);
850 m.set_frame ((*i)->frame ());
851 m.set_start ((*i)->start ());
854 // cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << " location " << m.frame() << " = " << m.start() << endl;
859 TempoMap::metric_at (BBT_Time bbt) const
861 TempoMetric m (first_meter(), first_tempo());
865 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
866 at something, because we insert the default tempo and meter during
867 TempoMap construction.
869 now see if we can find better candidates.
872 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
874 BBT_Time section_start ((*i)->start());
876 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
880 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
881 m.set_tempo (*tempo);
882 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
883 m.set_meter (*meter);
886 m.set_frame ((*i)->frame ());
887 m.set_start (section_start);
894 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt) const
897 Glib::RWLock::ReaderLock lm (lock);
898 bbt_time_unlocked (frame, bbt);
903 TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt) const
905 bbt_time_with_metric (frame, bbt, metric_at (frame));
909 TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetric& metric) const
911 const double divisions_per_bar = metric.meter().divisions_per_bar();
912 const double frames_per_tick = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_bar_division;
914 /* now compute how far beyond the metric we actually are, and add the
915 * relevant number of ticks to the metric's BBT time
918 framecnt_t frame_diff = frame - metric.frame();
919 uint32_t tick_diff = (uint32_t) lrint ((double) frame_diff / frames_per_tick);
921 bbt.ticks = metric.start().ticks + tick_diff;
922 uint32_t beat_overflow = bbt.ticks / (uint32_t) BBT_Time::ticks_per_bar_division;
923 bbt.ticks = bbt.ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
924 bbt.beats = metric.start().beats + beat_overflow;
925 /* bbt.beats uses 1-based counting, so adjust to get the right answer */
926 uint32_t bar_overflow = (bbt.beats - 1) / (uint32_t) divisions_per_bar;
927 bbt.bars = metric.start().bars + bar_overflow;
929 /* fmod will map bbt.beats as follows:
931 Beats divisions per bar Normalized beat
948 so, the only special cases are 0, N, 2N etc. however bbt.beats is
949 never zero, so the only actual special cases are N, 2N and so on,
950 allowing us to use a special case check for fmod () == 0 and
951 changing the value to divisions per bar
954 bbt.beats = (uint32_t) fmod (bbt.beats, divisions_per_bar);
956 if (bbt.beats == 0) {
957 bbt.beats = divisions_per_bar;
962 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
964 TempoMetric bm = metric_at (start);
965 TempoMetric em = metric_at (end);
967 return count_frames_with_metrics (bm, em, start, end);
971 TempoMap::count_frames_with_metrics (const TempoMetric& bm, const TempoMetric& em, const BBT_Time& start, const BBT_Time& end) const
973 framecnt_t frames = 0;
974 framepos_t start_frame = 0;
975 framepos_t end_frame = 0;
977 uint32_t bar_offset = start.bars - bm.start().bars;
979 double beat_offset = bar_offset*bm.meter().divisions_per_bar() - (bm.start().beats-1) + (start.beats -1)
980 + start.ticks/BBT_Time::ticks_per_bar_division;
982 start_frame = bm.frame() + (framepos_t) rint(beat_offset * bm.meter().frames_per_division(bm.tempo(),_frame_rate));
985 cerr << "from start " << start << " compute frame = " << start_frame
986 << " from metric at " << bm.frame() << " tempo = " << bm.tempo().beats_per_minute () << " meter "
987 << bm.meter().divisions_per_bar() << '/' << bm.meter().note_divisor()
991 bar_offset = end.bars - em.start().bars;
993 beat_offset = bar_offset * em.meter().divisions_per_bar() - (em.start().beats -1) + (end.beats - 1)
994 + end.ticks/BBT_Time::ticks_per_bar_division;
996 end_frame = em.frame() + (framepos_t) rint(beat_offset * em.meter().frames_per_division(em.tempo(),_frame_rate));
999 cerr << "from end " << end << " compute frame = " << end_frame
1000 << " from metric at " << em.frame() << " tempo = " << em.tempo().beats_per_minute () << " meter "
1001 << em.meter().divisions_per_bar() << '/' << em.meter().note_divisor()
1005 frames = end_frame - start_frame;
1011 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
1013 /* this is used in timestamping the metrics by actually counting the
1014 * beats between two metrics ONLY. this means that we know we have a
1015 * fixed divisions_per_bar and frames_per_division for the entire
1019 framecnt_t frames = 0;
1020 uint32_t bar = start.bars;
1021 double beat = (double) start.beats;
1022 double divisions_counted = 0;
1023 double divisions_per_bar = 0;
1024 double division_frames = 0;
1028 divisions_per_bar = meter.divisions_per_bar();
1029 max_divs = ceil (divisions_per_bar);
1030 division_frames = meter.frames_per_division (tempo, _frame_rate);
1032 if (start.ticks > 0) {
1033 ticks = -start.ticks;
1039 while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
1042 ++divisions_counted;
1044 if (beat > max_divs) {
1046 if (beat > divisions_per_bar) {
1048 /* this is a fractional beat at the end of a fractional bar
1049 so it should only count for the fraction
1052 divisions_counted -= (max_divs - divisions_per_bar);
1063 cerr << "for " << start.ticks << " and " << end.ticks << " adjust divs by " << ticks << " = "
1064 << (ticks/BBT_Time::ticks_per_bar_division) << " divs => "
1065 << ((ticks/BBT_Time::ticks_per_bar_division) * division_frames)
1066 << " (fpd = " << division_frames << ')'
1070 frames = (framecnt_t) llrint (floor ((divisions_counted + (ticks/BBT_Time::ticks_per_bar_division)) * division_frames));
1073 cerr << "Counted " << divisions_counted << " + " << ticks << " from " << start << " to " << end
1074 << " dpb were " << divisions_per_bar
1075 << " fpd was " << division_frames
1086 TempoMap::frame_time (const BBT_Time& bbt) const
1088 BBT_Time start ; /* 1|1|0 */
1090 return count_frames_between (start, bbt);
1094 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1096 framecnt_t frames = 0;
1099 bbt_time(pos, when);
1102 Glib::RWLock::ReaderLock lm (lock);
1103 frames = bbt_duration_at_unlocked (when, bbt,dir);
1110 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1112 framecnt_t frames = 0;
1114 double divisions_per_bar;
1117 result.bars = max(1U, when.bars + dir * bbt.bars) ;
1121 TempoMetric metric = metric_at(result);
1122 divisions_per_bar = metric.meter().divisions_per_bar();
1124 /* Reduce things to legal bbt values we have to handle possible
1125 fractional=shorter beats at the end of measures and things like 0|11|9000
1126 as a duration in a 4.5/4 measure the musical decision is that the
1127 fractional beat is also a beat , although a shorter one
1131 result.beats = when.beats + bbt.beats;
1132 result.ticks = when.ticks + bbt.ticks;
1134 while (result.beats >= (divisions_per_bar + 1)) {
1136 result.beats -= (uint32_t) ceil(divisions_per_bar);
1137 metric = metric_at(result); // maybe there is a meter change
1138 divisions_per_bar = metric.meter().divisions_per_bar();
1142 /* We now counted the beats and landed in the target measure, now deal
1143 with ticks this seems complicated, but we want to deal with the
1144 corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1145 with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1149 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1152 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1153 (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_bar_division
1154 : BBT_Time::ticks_per_bar_division );
1156 while (result.ticks >= ticks_at_beat) {
1158 result.ticks -= ticks_at_beat;
1159 if (result.beats >= (divisions_per_bar + 1)) {
1162 metric = metric_at(result); // maybe there is a meter change
1163 divisions_per_bar = metric.meter().divisions_per_bar();
1165 ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1166 (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_bar_division
1167 : BBT_Time::ticks_per_bar_division);
1172 uint32_t b = bbt.beats;
1175 while (b > when.beats) {
1177 result.bars = max(1U, result.bars);
1178 metric = metric_at(result); // maybe there is a meter change
1179 divisions_per_bar = metric.meter().divisions_per_bar();
1180 if (b >= ceil(divisions_per_bar)) {
1181 b -= (uint32_t) ceil(divisions_per_bar);
1183 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1186 result.beats = when.beats - b;
1190 if (bbt.ticks <= when.ticks) {
1191 result.ticks = when.ticks - bbt.ticks;
1194 uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_bar_division;
1195 uint32_t t = bbt.ticks - when.ticks;
1199 if (result.beats == 1) {
1201 result.bars = max(1U, result.bars) ;
1202 metric = metric_at(result); // maybe there is a meter change
1203 divisions_per_bar = metric.meter().divisions_per_bar();
1204 result.beats = (uint32_t) ceil(divisions_per_bar);
1205 ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_bar_division) ;
1208 ticks_at_beat = (uint32_t) BBT_Time::ticks_per_bar_division;
1211 if (t <= ticks_at_beat) {
1212 result.ticks = ticks_at_beat - t;
1216 } while (t > ticks_at_beat);
1224 frames = count_frames_between(result, when);
1226 frames = count_frames_between(when,result);
1235 TempoMap::round_to_bar (framepos_t fr, int dir)
1238 Glib::RWLock::ReaderLock lm (lock);
1239 return round_to_type (fr, dir, Bar);
1245 TempoMap::round_to_beat (framepos_t fr, int dir)
1248 Glib::RWLock::ReaderLock lm (lock);
1249 return round_to_type (fr, dir, Beat);
1254 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1257 uint32_t ticks_one_half_subdivisions_worth;
1258 uint32_t ticks_one_subdivisions_worth;
1259 uint32_t difference;
1261 bbt_time(fr, the_beat);
1263 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_bar_division / sub_num;
1264 ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1270 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1273 /* right on the subdivision, so the difference is just the subdivision ticks */
1274 difference = ticks_one_subdivisions_worth;
1277 /* not on subdivision, compute distance to next subdivision */
1279 difference = ticks_one_subdivisions_worth - mod;
1282 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1284 } else if (dir < 0) {
1286 /* round to previous */
1288 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1291 /* right on the subdivision, so the difference is just the subdivision ticks */
1292 difference = ticks_one_subdivisions_worth;
1294 /* not on subdivision, compute distance to previous subdivision, which
1295 is just the modulus.
1302 the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1304 /* can't go backwards from wherever pos is, so just return it */
1309 /* round to nearest */
1311 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1312 difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1313 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1315 // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1316 the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1320 return frame_time (the_beat);
1324 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1326 TempoMetric metric = metric_at (frame);
1329 BBT_Time one_bar (1,0,0);
1330 BBT_Time one_beat (0,1,0);
1332 bbt_time_with_metric (frame, bbt, metric);
1336 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1340 /* find bar position preceding frame */
1343 bbt = bbt_subtract (bbt, one_bar);
1351 } else if (dir > 0) {
1353 /* find bar position following frame */
1356 bbt = bbt_add (bbt, one_bar, metric);
1364 /* "true" rounding */
1369 midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1370 midbar_ticks = BBT_Time::ticks_per_bar_division * fmod (midbar_beats, 1.0f);
1371 midbar_beats = floor (midbar_beats);
1373 BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1386 /* force beats & ticks to their values at the start of a bar */
1392 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1396 /* find beat position preceding frame */
1399 bbt = bbt_subtract (bbt, one_beat);
1407 } else if (dir > 0) {
1409 /* find beat position following frame */
1412 bbt = bbt_add (bbt, one_beat, metric);
1420 /* "true" rounding */
1422 /* round to nearest beat */
1423 if (bbt.ticks >= (BBT_Time::ticks_per_bar_division/2)) {
1426 bbt = bbt_add (bbt, one_beat, metric);
1433 /* force ticks to the value at the start of a beat */
1439 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)));
1440 return metric.frame() + count_frames_between (metric.start(), bbt);
1443 TempoMap::BBTPointList *
1444 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1446 Metrics::const_iterator next_metric;
1447 BBTPointList *points;
1449 const MeterSection* meter;
1450 const MeterSection* m;
1451 const TempoSection* tempo;
1452 const TempoSection* t;
1455 double divisions_per_bar;
1458 double frames_per_bar;
1464 meter = &first_meter ();
1465 tempo = &first_tempo ();
1467 /* find the starting point */
1469 for (next_metric = metrics->begin(); next_metric != metrics->end(); ++next_metric) {
1471 if ((*next_metric)->frame() > lower) {
1475 if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1477 } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1484 meter -> the Meter for "lower"
1485 tempo -> the Tempo for "lower"
1486 i -> for first new metric after "lower", possibly metrics->end()
1488 Now start generating points.
1491 divisions_per_bar = meter->divisions_per_bar ();
1492 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1493 beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1495 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Start with beat frames = %1 bar = %2\n", beat_frames, frames_per_bar));
1497 if (meter->frame() > tempo->frame()) {
1498 bar = meter->start().bars;
1499 beat = meter->start().beats;
1500 current = meter->frame();
1502 bar = tempo->start().bars;
1503 beat = tempo->start().beats;
1504 current = tempo->frame();
1507 /* initialize current to point to the bar/beat just prior to the
1508 lower frame bound passed in. assumes that current is initialized
1509 above to be on a beat.
1512 delta_bars = (lower-current) / frames_per_bar;
1513 delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1514 current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
1516 // adjust bars and beats too
1517 bar += (uint32_t) (floor(delta_bars));
1518 beat += (uint32_t) (floor(delta_beats));
1520 points = new BBTPointList;
1524 /* we're going to add bar or beat points until we hit the
1527 (1) the end point of this request
1528 (2) the next metric section
1531 if (next_metric == metrics->end()) {
1533 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to end of request @ %1\n", limit));
1535 limit = (*next_metric)->frame();
1536 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to next metric section @ %1\n", limit));
1539 limit = min (limit, upper);
1541 bool reset_current_to_metric_section = true;
1542 bool bar_adjusted = false;
1545 while (current < limit) {
1547 /* if we're at the start of a bar, add bar point */
1550 if (current >= lower) {
1551 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", bar, current));
1552 points->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current), Bar, bar, 1));
1557 /* add some beats if we can */
1559 beat_frame = current;
1561 const uint32_t max_divs = ceil (divisions_per_bar);
1563 while (beat <= max_divs && beat_frame < limit) {
1565 if (beat_frame >= lower) {
1566 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", bar, beat, beat_frame));
1567 points->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(beat_frame), Beat, bar, beat));
1570 beat_frame += beat_frames;
1571 current = beat_frame;
1575 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("break in beats addition @ end ? %1 out of bpb ? %2 beat frame @ %3 vs %4 beat @ %5 vs %6\n",
1576 (next_metric == metrics->end()), (beat > max_divs), beat_frame, limit, beat, max_divs));
1578 if (beat <= max_divs) {
1580 /* we didn't reach the end of the bar.
1582 this could be be because we hit "upper"
1583 or a new metric section.
1587 if (next_metric != metrics->end() && limit == (*next_metric)->frame()) {
1589 /* we bumped into a new metric
1590 * section. meter sections are always
1591 * at bar boundaries, but tempo
1592 * sections can begin anywhere and need
1593 * special handling if they are not on
1597 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("stopped at metric at %1 @ 2\n", (*next_metric)->start(), (*next_metric)->frame()));
1599 if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0) && ts->start().ticks != 0) {
1601 /* compute current at the *next* beat,
1602 using the tempo section we just
1606 /* recompute how many frames per
1607 * division using the tempo we've just
1611 double next_beat_frames = meter->frames_per_division (*ts,_frame_rate);
1613 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
1614 (*next_metric)->start(), (*next_metric)->frame(), ts->bar_offset()));
1616 current -= beat_frames;
1617 current += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
1619 /* avoid resetting current to position
1620 of the next metric section as we
1621 iterate through "metrics"
1625 reset_current_to_metric_section = false;
1627 } else if (dynamic_cast<MeterSection*> (*next_metric)) {
1629 /* we hit a new meter
1630 * section. nothing to do - the
1631 * right thing will happen as
1632 * we move to the next metric
1633 * section down below.
1638 /* we hit a tempo mark that is
1639 * precisely on beat. nothing
1641 * right thing will happen as
1642 * we move to the next metric
1643 * section down below.
1651 - the end of the requested range
1653 we'll exit from the outer loop soon.
1657 } else if ((beat > max_divs) || (next_metric != metrics->end() && dynamic_cast<MeterSection*>(*next_metric))) {
1659 /* we've arrived at either the end of a bar or
1660 a new **meter** marker (not tempo marker).
1662 its important to move `current' forward by
1663 the actual frames_per_bar, not move it to an
1664 integral beat_frame, so that metrics with
1665 non-integral beats-per-bar have their bar
1666 positions set correctly. consider a metric
1667 with 9-1/2 beats-per-bar. the bar we just
1668 filled had 10 beat marks, but the bar end is
1669 1/2 beat before the last beat mark. And it
1670 is also possible that a tempo change occured
1671 in the middle of a bar, so we subtract the
1672 possible extra fraction from the current
1675 if (beat > max_divs) {
1676 /* next bar goes where the numbers suggest */
1677 current -= beat_frames * (max_divs - divisions_per_bar);
1678 DEBUG_TRACE (DEBUG::TempoMath, "++ next bar from numbers\n");
1680 /* next bar goes where the next meter metric is */
1682 DEBUG_TRACE (DEBUG::TempoMath, "++ next bar at next metric\n");
1687 bar_adjusted = true;
1691 /* if we're done, then we're done */
1693 if (current >= upper) {
1697 /* i is an iterator that refers to the next metric (or none).
1698 if there is a next metric, move to it, and continue.
1701 if (next_metric != metrics->end()) {
1703 if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1705 } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1708 if (!bar_adjusted) {
1709 /* new MeterSection, beat always returns to 1 */
1714 if (reset_current_to_metric_section) {
1715 current = (*next_metric)->frame ();
1718 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("loop around with current @ %1\n", current));
1720 divisions_per_bar = meter->divisions_per_bar ();
1721 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1722 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1724 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 bar = %2 dpb %3 meter %4 tempo %5\n",
1725 beat_frames, frames_per_bar, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
1736 TempoMap::tempo_section_at (framepos_t frame) const
1738 Glib::RWLock::ReaderLock lm (lock);
1739 Metrics::const_iterator i;
1740 TempoSection* prev = 0;
1742 for (i = metrics->begin(); i != metrics->end(); ++i) {
1745 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1747 if ((*i)->frame() > frame) {
1763 TempoMap::tempo_at (framepos_t frame) const
1765 TempoMetric m (metric_at (frame));
1771 TempoMap::meter_at (framepos_t frame) const
1773 TempoMetric m (metric_at (frame));
1778 TempoMap::get_state ()
1780 Metrics::const_iterator i;
1781 XMLNode *root = new XMLNode ("TempoMap");
1784 Glib::RWLock::ReaderLock lm (lock);
1785 for (i = metrics->begin(); i != metrics->end(); ++i) {
1786 root->add_child_nocopy ((*i)->get_state());
1794 TempoMap::set_state (const XMLNode& node, int /*version*/)
1797 Glib::RWLock::WriterLock lm (lock);
1800 XMLNodeConstIterator niter;
1801 Metrics old_metrics (*metrics);
1802 MeterSection* last_meter = 0;
1806 nlist = node.children();
1808 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1809 XMLNode* child = *niter;
1811 if (child->name() == TempoSection::xml_state_node_name) {
1814 TempoSection* ts = new TempoSection (*child);
1815 metrics->push_back (ts);
1817 if (ts->bar_offset() < 0.0) {
1819 ts->update_bar_offset_from_bbt (*last_meter);
1824 catch (failed_constructor& err){
1825 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1826 *metrics = old_metrics;
1830 } else if (child->name() == MeterSection::xml_state_node_name) {
1833 MeterSection* ms = new MeterSection (*child);
1834 metrics->push_back (ms);
1838 catch (failed_constructor& err) {
1839 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1840 *metrics = old_metrics;
1846 if (niter == nlist.end()) {
1848 MetricSectionSorter cmp;
1849 metrics->sort (cmp);
1850 timestamp_metrics (true);
1854 PropertyChanged (PropertyChange ());
1860 TempoMap::dump (std::ostream& o) const
1862 const MeterSection* m;
1863 const TempoSection* t;
1865 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1867 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1868 o << "Tempo @ " << *i << " (Bar-offset: " << t->bar_offset() << ") " << t->beats_per_minute() << " BPM (pulse = 1/" << t->note_type() << ") at " << t->start() << " frame= " << t->frame() << " (movable? "
1869 << t->movable() << ')' << endl;
1870 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1871 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1872 << " (movable? " << m->movable() << ')' << endl;
1878 TempoMap::n_tempos() const
1880 Glib::RWLock::ReaderLock lm (lock);
1883 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1884 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1893 TempoMap::n_meters() const
1895 Glib::RWLock::ReaderLock lm (lock);
1898 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1899 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1908 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1910 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1911 if ((*i)->frame() >= where && (*i)->movable ()) {
1912 (*i)->set_frame ((*i)->frame() + amount);
1916 timestamp_metrics_from_audio_time ();
1918 PropertyChanged (PropertyChange ());
1922 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1924 TempoMetric metric = metric_at (start);
1925 return bbt_add (start, other, metric);
1929 * add the BBT interval @param increment to @param start and return the result
1932 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1934 BBT_Time result = start;
1935 BBT_Time op = increment; /* argument is const, but we need to modify it */
1936 uint32_t ticks = result.ticks + op.ticks;
1938 if (ticks >= BBT_Time::ticks_per_bar_division) {
1940 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
1942 result.ticks += op.ticks;
1945 /* now comes the complicated part. we have to add one beat a time,
1946 checking for a new metric on every beat.
1949 /* grab all meter sections */
1951 list<const MeterSection*> meter_sections;
1953 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1954 const MeterSection* ms;
1955 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1956 meter_sections.push_back (ms);
1960 assert (!meter_sections.empty());
1962 list<const MeterSection*>::const_iterator next_meter;
1963 const Meter* meter = 0;
1965 /* go forwards through the meter sections till we get to the one
1966 covering the current value of result. this positions i to point to
1967 the next meter section too, or the end.
1970 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1972 if (result < (*next_meter)->start()) {
1973 /* this metric is past the result time. stop looking, we have what we need */
1977 if (result == (*next_meter)->start()) {
1978 /* this meter section starts at result, push i beyond it so that it points
1979 to the NEXT section, opwise we will get stuck later, and use this meter section.
1981 meter = *next_meter;
1986 meter = *next_meter;
1989 assert (meter != 0);
1991 /* OK, now have the meter for the bar start we are on, and i is an iterator
1992 that points to the metric after the one we are currently dealing with
1993 (or to metrics->end(), of course)
1998 /* given the current meter, have we gone past the end of the bar ? */
2000 if (result.beats >= meter->divisions_per_bar()) {
2001 /* move to next bar, first beat */
2012 /* check if we need to use a new meter section: has adding beats to result taken us
2013 to or after the start of the next meter section? in which case, use it.
2016 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
2017 meter = *next_meter;
2022 /* finally, add bars */
2024 result.bars += op.bars++;
2030 * subtract the BBT interval @param decrement from @param start and return the result
2033 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
2035 BBT_Time result = start;
2036 BBT_Time op = decrement; /* argument is const, but we need to modify it */
2038 if (op.ticks > result.ticks) {
2039 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
2041 result.ticks = BBT_Time::ticks_per_bar_division - (op.ticks - result.ticks);
2043 result.ticks -= op.ticks;
2046 /* now comes the complicated part. we have to subtract one beat a time,
2047 checking for a new metric on every beat.
2050 /* grab all meter sections */
2052 list<const MeterSection*> meter_sections;
2054 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
2055 const MeterSection* ms;
2056 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
2057 meter_sections.push_back (ms);
2061 assert (!meter_sections.empty());
2063 /* go backwards through the meter sections till we get to the one
2064 covering the current value of result. this positions i to point to
2065 the next (previous) meter section too, or the end.
2068 const MeterSection* meter = 0;
2069 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
2070 // support const_reverse_iterator::operator!=()
2072 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
2074 /* when we find the first meter section that is before or at result, use it,
2075 and set next_meter to the previous one
2078 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
2079 meter = *next_meter;
2085 assert (meter != 0);
2087 /* OK, now have the meter for the bar start we are on, and i is an iterator
2088 that points to the metric after the one we are currently dealing with
2089 (or to metrics->end(), of course)
2094 /* have we reached the start of the bar? if so, move to the last beat of the previous
2095 bar. opwise, just step back 1 beat.
2098 if (result.beats == 1) {
2100 /* move to previous bar, last beat */
2102 if (result.bars <= 1) {
2103 /* i'm sorry dave, i can't do that */
2104 throw std::out_of_range ("illegal BBT subtraction");
2108 result.beats = meter->divisions_per_bar();
2119 /* check if we need to use a new meter section: has subtracting beats to result taken us
2120 to before the start of the current meter section? in which case, use the prior one.
2123 if (result < meter->start() && next_meter != meter_sections.rend()) {
2124 meter = *next_meter;
2129 /* finally, subtract bars */
2131 if (op.bars >= result.bars) {
2132 /* i'm sorry dave, i can't do that */
2133 throw std::out_of_range ("illegal BBT subtraction");
2136 result.bars -= op.bars;
2140 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2141 * pos can be -ve, if required.
2144 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2146 Metrics::const_iterator i;
2147 const TempoSection* tempo;
2149 /* Find the starting tempo */
2151 for (i = metrics->begin(); i != metrics->end(); ++i) {
2153 /* This is a bit of a hack, but pos could be -ve, and if it is,
2154 we consider the initial metric changes (at time 0) to actually
2155 be in effect at pos.
2157 framepos_t f = (*i)->frame ();
2158 if (pos < 0 && f == 0) {
2166 const TempoSection* t;
2168 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2175 tempo -> the Tempo for "pos"
2176 i -> for first new metric after "pos", possibly metrics->end()
2181 /* Distance to the end of this section in frames */
2182 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
2184 /* Distance to the end in beats */
2185 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2187 /* Amount to subtract this time */
2188 double const sub = min (distance_beats, beats);
2192 pos += sub * tempo->frames_per_beat (_frame_rate);
2194 /* Move on if there's anything to move to */
2195 if (i != metrics->end ()) {
2196 const TempoSection* t;
2198 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2209 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2211 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2213 Metrics::const_iterator i;
2214 const TempoSection* tempo = 0;
2215 const TempoSection* t;
2217 /* Find the starting tempo */
2219 for (i = metrics->begin(); i != metrics->end(); ++i) {
2221 /* This is a bit of a hack, but pos could be -ve, and if it is,
2222 we consider the initial metric changes (at time 0) to actually
2223 be in effect at pos.
2225 framepos_t f = (*i)->frame ();
2226 if (pos < 0 && f == 0) {
2230 if ((*i)->frame() > pos) {
2234 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2239 bool no_more_tempos = false;
2241 /* Move i back to the tempo before "pos" */
2242 if (i != metrics->begin ()) {
2243 while (i != metrics->begin ()) {
2245 t = dynamic_cast<TempoSection*> (*i);
2251 no_more_tempos = true;
2256 tempo -> the Tempo for "pos"
2257 i -> the first metric before "pos", unless no_more_tempos is true
2262 /* Distance to the end of this section in frames */
2263 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2265 /* Distance to the end in beats */
2266 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2268 /* Amount to subtract this time */
2269 double const sub = min (distance_beats, beats);
2273 pos -= sub * tempo->frames_per_beat (_frame_rate);
2275 /* Move i and tempo back, if there's anything to move to */
2276 if (i != metrics->begin ()) {
2277 while (i != metrics->begin ()) {
2279 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2285 no_more_tempos = true;
2292 /** Add the BBT interval op to pos and return the result */
2294 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2296 Metrics::const_iterator i;
2297 const MeterSection* meter;
2298 const MeterSection* m;
2299 const TempoSection* tempo;
2300 const TempoSection* t;
2301 double frames_per_beat;
2303 meter = &first_meter ();
2304 tempo = &first_tempo ();
2309 /* find the starting metrics for tempo & meter */
2311 for (i = metrics->begin(); i != metrics->end(); ++i) {
2313 if ((*i)->frame() > pos) {
2317 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2319 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2326 meter -> the Meter for "pos"
2327 tempo -> the Tempo for "pos"
2328 i -> for first new metric after "pos", possibly metrics->end()
2331 /* now comes the complicated part. we have to add one beat a time,
2332 checking for a new metric on every beat.
2335 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2344 /* check if we need to use a new metric section: has adding frames moved us
2345 to or after the start of the next metric section? in which case, use it.
2348 if (i != metrics->end()) {
2349 if ((*i)->frame() <= pos) {
2351 /* about to change tempo or meter, so add the
2352 * number of frames for the bars we've just
2353 * traversed before we change the
2354 * frames_per_beat value.
2357 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2360 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2362 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2366 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2373 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2379 /* given the current meter, have we gone past the end of the bar ? */
2384 /* check if we need to use a new metric section: has adding frames moved us
2385 to or after the start of the next metric section? in which case, use it.
2388 if (i != metrics->end()) {
2389 if ((*i)->frame() <= pos) {
2391 /* about to change tempo or meter, so add the
2392 * number of frames for the beats we've just
2393 * traversed before we change the
2394 * frames_per_beat value.
2397 pos += llrint (beats * frames_per_beat);
2400 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2402 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2406 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2411 pos += llrint (beats * frames_per_beat);
2414 if (op.ticks >= BBT_Time::ticks_per_bar_division) {
2415 pos += llrint (frames_per_beat + /* extra beat */
2416 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_bar_division) /
2417 (double) BBT_Time::ticks_per_bar_division)));
2419 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_bar_division));
2426 /** Count the number of beats that are equivalent to distance when going forward,
2430 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2432 Metrics::const_iterator i;
2433 const TempoSection* tempo;
2435 /* Find the starting tempo */
2437 for (i = metrics->begin(); i != metrics->end(); ++i) {
2439 if ((*i)->frame() > pos) {
2443 const TempoSection* t;
2445 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2452 tempo -> the Tempo for "pos"
2453 i -> the first metric after "pos", possibly metrics->end()
2456 Evoral::MusicalTime beats = 0;
2460 /* End of this section */
2461 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2463 /* Distance to the end in frames */
2464 framecnt_t const distance_to_end = end - pos;
2466 /* Amount to subtract this time */
2467 double const sub = min (distance, distance_to_end);
2472 beats += sub / tempo->frames_per_beat (_frame_rate);
2474 /* Move on if there's anything to move to */
2475 if (i != metrics->end ()) {
2476 const TempoSection* t;
2478 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2489 /** Compare the time of this with that of another MetricSection.
2490 * @param with_bbt True to compare using start(), false to use frame().
2491 * @return -1 for less than, 0 for equal, 1 for greater than.
2495 MetricSection::compare (const MetricSection& other) const
2497 if (start() == other.start()) {
2499 } else if (start() < other.start()) {
2510 MetricSection::operator== (const MetricSection& other) const
2512 return compare (other) == 0;
2516 MetricSection::operator!= (const MetricSection& other) const
2518 return compare (other) != 0;
2522 operator<< (std::ostream& o, const Meter& m) {
2523 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2527 operator<< (std::ostream& o, const Tempo& t) {
2528 return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2532 operator<< (std::ostream& o, const MetricSection& section) {
2534 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2536 const TempoSection* ts;
2537 const MeterSection* ms;
2539 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2540 o << *((Tempo*) ts);
2541 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2542 o << *((Meter*) ms);