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 section. bump the
1630 * bar and return to beat 1
1635 // bar_adjusted = true;
1643 - the end of the requested range
1644 - a tempo mark that is precisely on beat
1646 in the first case, we'll exit from
1647 the outer loop soon.
1649 in the second case, nothing special
1654 } else if ((beat > max_divs) || (next_metric != metrics->end() && dynamic_cast<MeterSection*>(*next_metric))) {
1656 /* we've arrived at either the end of a bar or
1657 a new **meter** marker (not tempo marker).
1659 its important to move `current' forward by
1660 the actual frames_per_bar, not move it to an
1661 integral beat_frame, so that metrics with
1662 non-integral beats-per-bar have their bar
1663 positions set correctly. consider a metric
1664 with 9-1/2 beats-per-bar. the bar we just
1665 filled had 10 beat marks, but the bar end is
1666 1/2 beat before the last beat mark. And it
1667 is also possible that a tempo change occured
1668 in the middle of a bar, so we subtract the
1669 possible extra fraction from the current
1672 if (beat > max_divs) {
1673 /* next bar goes where the numbers suggest */
1674 current -= beat_frames * (max_divs - divisions_per_bar);
1675 DEBUG_TRACE (DEBUG::TempoMath, "++ next bar from numbers\n");
1677 /* next bar goes where the next meter metric is */
1679 DEBUG_TRACE (DEBUG::TempoMath, "++ next bar at next metric\n");
1684 bar_adjusted = true;
1688 /* if we're done, then we're done */
1690 if (current >= upper) {
1694 /* i is an iterator that refers to the next metric (or none).
1695 if there is a next metric, move to it, and continue.
1698 if (next_metric != metrics->end()) {
1700 if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1702 } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1705 if (!bar_adjusted) {
1706 /* new MeterSection, beat always returns to 1 */
1711 if (reset_current_to_metric_section) {
1712 current = (*next_metric)->frame ();
1715 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("loop around with current @ %1\n", current));
1717 divisions_per_bar = meter->divisions_per_bar ();
1718 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1719 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1721 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 bar = %2 dpb %3 meter %4 tempo %5\n",
1722 beat_frames, frames_per_bar, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
1733 TempoMap::tempo_section_at (framepos_t frame) const
1735 Glib::RWLock::ReaderLock lm (lock);
1736 Metrics::const_iterator i;
1737 TempoSection* prev = 0;
1739 for (i = metrics->begin(); i != metrics->end(); ++i) {
1742 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1744 if ((*i)->frame() > frame) {
1760 TempoMap::tempo_at (framepos_t frame) const
1762 TempoMetric m (metric_at (frame));
1768 TempoMap::meter_at (framepos_t frame) const
1770 TempoMetric m (metric_at (frame));
1775 TempoMap::get_state ()
1777 Metrics::const_iterator i;
1778 XMLNode *root = new XMLNode ("TempoMap");
1781 Glib::RWLock::ReaderLock lm (lock);
1782 for (i = metrics->begin(); i != metrics->end(); ++i) {
1783 root->add_child_nocopy ((*i)->get_state());
1791 TempoMap::set_state (const XMLNode& node, int /*version*/)
1794 Glib::RWLock::WriterLock lm (lock);
1797 XMLNodeConstIterator niter;
1798 Metrics old_metrics (*metrics);
1799 MeterSection* last_meter = 0;
1803 nlist = node.children();
1805 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1806 XMLNode* child = *niter;
1808 if (child->name() == TempoSection::xml_state_node_name) {
1811 TempoSection* ts = new TempoSection (*child);
1812 metrics->push_back (ts);
1814 if (ts->bar_offset() < 0.0) {
1816 ts->update_bar_offset_from_bbt (*last_meter);
1821 catch (failed_constructor& err){
1822 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1823 *metrics = old_metrics;
1827 } else if (child->name() == MeterSection::xml_state_node_name) {
1830 MeterSection* ms = new MeterSection (*child);
1831 metrics->push_back (ms);
1835 catch (failed_constructor& err) {
1836 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1837 *metrics = old_metrics;
1843 if (niter == nlist.end()) {
1845 MetricSectionSorter cmp;
1846 metrics->sort (cmp);
1847 timestamp_metrics (true);
1851 PropertyChanged (PropertyChange ());
1857 TempoMap::dump (std::ostream& o) const
1859 const MeterSection* m;
1860 const TempoSection* t;
1862 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1864 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1865 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? "
1866 << t->movable() << ')' << endl;
1867 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1868 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1869 << " (movable? " << m->movable() << ')' << endl;
1875 TempoMap::n_tempos() const
1877 Glib::RWLock::ReaderLock lm (lock);
1880 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1881 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1890 TempoMap::n_meters() const
1892 Glib::RWLock::ReaderLock lm (lock);
1895 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1896 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1905 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1907 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1908 if ((*i)->frame() >= where && (*i)->movable ()) {
1909 (*i)->set_frame ((*i)->frame() + amount);
1913 timestamp_metrics_from_audio_time ();
1915 PropertyChanged (PropertyChange ());
1919 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1921 TempoMetric metric = metric_at (start);
1922 return bbt_add (start, other, metric);
1926 * add the BBT interval @param increment to @param start and return the result
1929 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1931 BBT_Time result = start;
1932 BBT_Time op = increment; /* argument is const, but we need to modify it */
1933 uint32_t ticks = result.ticks + op.ticks;
1935 if (ticks >= BBT_Time::ticks_per_bar_division) {
1937 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
1939 result.ticks += op.ticks;
1942 /* now comes the complicated part. we have to add one beat a time,
1943 checking for a new metric on every beat.
1946 /* grab all meter sections */
1948 list<const MeterSection*> meter_sections;
1950 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1951 const MeterSection* ms;
1952 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1953 meter_sections.push_back (ms);
1957 assert (!meter_sections.empty());
1959 list<const MeterSection*>::const_iterator next_meter;
1960 const Meter* meter = 0;
1962 /* go forwards through the meter sections till we get to the one
1963 covering the current value of result. this positions i to point to
1964 the next meter section too, or the end.
1967 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1969 if (result < (*next_meter)->start()) {
1970 /* this metric is past the result time. stop looking, we have what we need */
1974 if (result == (*next_meter)->start()) {
1975 /* this meter section starts at result, push i beyond it so that it points
1976 to the NEXT section, opwise we will get stuck later, and use this meter section.
1978 meter = *next_meter;
1983 meter = *next_meter;
1986 assert (meter != 0);
1988 /* OK, now have the meter for the bar start we are on, and i is an iterator
1989 that points to the metric after the one we are currently dealing with
1990 (or to metrics->end(), of course)
1995 /* given the current meter, have we gone past the end of the bar ? */
1997 if (result.beats >= meter->divisions_per_bar()) {
1998 /* move to next bar, first beat */
2009 /* check if we need to use a new meter section: has adding beats to result taken us
2010 to or after the start of the next meter section? in which case, use it.
2013 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
2014 meter = *next_meter;
2019 /* finally, add bars */
2021 result.bars += op.bars++;
2027 * subtract the BBT interval @param decrement from @param start and return the result
2030 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
2032 BBT_Time result = start;
2033 BBT_Time op = decrement; /* argument is const, but we need to modify it */
2035 if (op.ticks > result.ticks) {
2036 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
2038 result.ticks = BBT_Time::ticks_per_bar_division - (op.ticks - result.ticks);
2040 result.ticks -= op.ticks;
2043 /* now comes the complicated part. we have to subtract one beat a time,
2044 checking for a new metric on every beat.
2047 /* grab all meter sections */
2049 list<const MeterSection*> meter_sections;
2051 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
2052 const MeterSection* ms;
2053 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
2054 meter_sections.push_back (ms);
2058 assert (!meter_sections.empty());
2060 /* go backwards through the meter sections till we get to the one
2061 covering the current value of result. this positions i to point to
2062 the next (previous) meter section too, or the end.
2065 const MeterSection* meter = 0;
2066 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
2067 // support const_reverse_iterator::operator!=()
2069 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
2071 /* when we find the first meter section that is before or at result, use it,
2072 and set next_meter to the previous one
2075 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
2076 meter = *next_meter;
2082 assert (meter != 0);
2084 /* OK, now have the meter for the bar start we are on, and i is an iterator
2085 that points to the metric after the one we are currently dealing with
2086 (or to metrics->end(), of course)
2091 /* have we reached the start of the bar? if so, move to the last beat of the previous
2092 bar. opwise, just step back 1 beat.
2095 if (result.beats == 1) {
2097 /* move to previous bar, last beat */
2099 if (result.bars <= 1) {
2100 /* i'm sorry dave, i can't do that */
2101 throw std::out_of_range ("illegal BBT subtraction");
2105 result.beats = meter->divisions_per_bar();
2116 /* check if we need to use a new meter section: has subtracting beats to result taken us
2117 to before the start of the current meter section? in which case, use the prior one.
2120 if (result < meter->start() && next_meter != meter_sections.rend()) {
2121 meter = *next_meter;
2126 /* finally, subtract bars */
2128 if (op.bars >= result.bars) {
2129 /* i'm sorry dave, i can't do that */
2130 throw std::out_of_range ("illegal BBT subtraction");
2133 result.bars -= op.bars;
2137 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2138 * pos can be -ve, if required.
2141 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2143 Metrics::const_iterator i;
2144 const TempoSection* tempo;
2146 /* Find the starting tempo */
2148 for (i = metrics->begin(); i != metrics->end(); ++i) {
2150 /* This is a bit of a hack, but pos could be -ve, and if it is,
2151 we consider the initial metric changes (at time 0) to actually
2152 be in effect at pos.
2154 framepos_t f = (*i)->frame ();
2155 if (pos < 0 && f == 0) {
2163 const TempoSection* t;
2165 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2172 tempo -> the Tempo for "pos"
2173 i -> for first new metric after "pos", possibly metrics->end()
2178 /* Distance to the end of this section in frames */
2179 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
2181 /* Distance to the end in beats */
2182 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2184 /* Amount to subtract this time */
2185 double const sub = min (distance_beats, beats);
2189 pos += sub * tempo->frames_per_beat (_frame_rate);
2191 /* Move on if there's anything to move to */
2192 if (i != metrics->end ()) {
2193 const TempoSection* t;
2195 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2206 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2208 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2210 Metrics::const_iterator i;
2211 const TempoSection* tempo = 0;
2212 const TempoSection* t;
2214 /* Find the starting tempo */
2216 for (i = metrics->begin(); i != metrics->end(); ++i) {
2218 /* This is a bit of a hack, but pos could be -ve, and if it is,
2219 we consider the initial metric changes (at time 0) to actually
2220 be in effect at pos.
2222 framepos_t f = (*i)->frame ();
2223 if (pos < 0 && f == 0) {
2227 if ((*i)->frame() > pos) {
2231 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2236 bool no_more_tempos = false;
2238 /* Move i back to the tempo before "pos" */
2239 if (i != metrics->begin ()) {
2240 while (i != metrics->begin ()) {
2242 t = dynamic_cast<TempoSection*> (*i);
2248 no_more_tempos = true;
2253 tempo -> the Tempo for "pos"
2254 i -> the first metric before "pos", unless no_more_tempos is true
2259 /* Distance to the end of this section in frames */
2260 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2262 /* Distance to the end in beats */
2263 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2265 /* Amount to subtract this time */
2266 double const sub = min (distance_beats, beats);
2270 pos -= sub * tempo->frames_per_beat (_frame_rate);
2272 /* Move i and tempo back, if there's anything to move to */
2273 if (i != metrics->begin ()) {
2274 while (i != metrics->begin ()) {
2276 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2282 no_more_tempos = true;
2289 /** Add the BBT interval op to pos and return the result */
2291 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2293 Metrics::const_iterator i;
2294 const MeterSection* meter;
2295 const MeterSection* m;
2296 const TempoSection* tempo;
2297 const TempoSection* t;
2298 double frames_per_beat;
2300 meter = &first_meter ();
2301 tempo = &first_tempo ();
2306 /* find the starting metrics for tempo & meter */
2308 for (i = metrics->begin(); i != metrics->end(); ++i) {
2310 if ((*i)->frame() > pos) {
2314 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2316 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2323 meter -> the Meter for "pos"
2324 tempo -> the Tempo for "pos"
2325 i -> for first new metric after "pos", possibly metrics->end()
2328 /* now comes the complicated part. we have to add one beat a time,
2329 checking for a new metric on every beat.
2332 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2341 /* check if we need to use a new metric section: has adding frames moved us
2342 to or after the start of the next metric section? in which case, use it.
2345 if (i != metrics->end()) {
2346 if ((*i)->frame() <= pos) {
2348 /* about to change tempo or meter, so add the
2349 * number of frames for the bars we've just
2350 * traversed before we change the
2351 * frames_per_beat value.
2354 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2357 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2359 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2363 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2370 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2376 /* given the current meter, have we gone past the end of the bar ? */
2381 /* check if we need to use a new metric section: has adding frames moved us
2382 to or after the start of the next metric section? in which case, use it.
2385 if (i != metrics->end()) {
2386 if ((*i)->frame() <= pos) {
2388 /* about to change tempo or meter, so add the
2389 * number of frames for the beats we've just
2390 * traversed before we change the
2391 * frames_per_beat value.
2394 pos += llrint (beats * frames_per_beat);
2397 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2399 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2403 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2408 pos += llrint (beats * frames_per_beat);
2411 if (op.ticks >= BBT_Time::ticks_per_bar_division) {
2412 pos += llrint (frames_per_beat + /* extra beat */
2413 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_bar_division) /
2414 (double) BBT_Time::ticks_per_bar_division)));
2416 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_bar_division));
2423 /** Count the number of beats that are equivalent to distance when going forward,
2427 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2429 Metrics::const_iterator i;
2430 const TempoSection* tempo;
2432 /* Find the starting tempo */
2434 for (i = metrics->begin(); i != metrics->end(); ++i) {
2436 if ((*i)->frame() > pos) {
2440 const TempoSection* t;
2442 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2449 tempo -> the Tempo for "pos"
2450 i -> the first metric after "pos", possibly metrics->end()
2453 Evoral::MusicalTime beats = 0;
2457 /* End of this section */
2458 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2460 /* Distance to the end in frames */
2461 framecnt_t const distance_to_end = end - pos;
2463 /* Amount to subtract this time */
2464 double const sub = min (distance, distance_to_end);
2469 beats += sub / tempo->frames_per_beat (_frame_rate);
2471 /* Move on if there's anything to move to */
2472 if (i != metrics->end ()) {
2473 const TempoSection* t;
2475 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2486 /** Compare the time of this with that of another MetricSection.
2487 * @param with_bbt True to compare using start(), false to use frame().
2488 * @return -1 for less than, 0 for equal, 1 for greater than.
2492 MetricSection::compare (const MetricSection& other) const
2494 if (start() == other.start()) {
2496 } else if (start() < other.start()) {
2507 MetricSection::operator== (const MetricSection& other) const
2509 return compare (other) == 0;
2513 MetricSection::operator!= (const MetricSection& other) const
2515 return compare (other) != 0;
2519 operator<< (std::ostream& o, const Meter& m) {
2520 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2524 operator<< (std::ostream& o, const Tempo& t) {
2525 return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2529 operator<< (std::ostream& o, const MetricSection& section) {
2531 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2533 const TempoSection* ts;
2534 const MeterSection* ms;
2536 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2537 o << *((Tempo*) ts);
2538 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2539 o << *((Meter*) ms);