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();
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;
176 /* remember the 1-based counting properties of beats */
177 new_start.beats = 1 + (uint32_t) floor (_bar_offset * meter.divisions_per_bar());
178 new_start.ticks = (uint32_t) floor (BBT_Time::ticks_per_bar_division *
179 ((_bar_offset * meter.divisions_per_bar()) - (new_start.beats-1)));
181 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("tempo updated BBT time to %1 from bar offset %2\n", new_start, _bar_offset));
183 set_start (new_start);
186 /***********************************************************************/
188 const string MeterSection::xml_state_node_name = "Meter";
190 MeterSection::MeterSection (const XMLNode& node)
191 : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
193 const XMLProperty *prop;
195 LocaleGuard lg (X_("POSIX"));
197 if ((prop = node.property ("start")) == 0) {
198 error << _("MeterSection XML node has no \"start\" property") << endmsg;
199 throw failed_constructor();
202 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
206 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
207 throw failed_constructor();
212 /* beats-per-bar is old; divisions-per-bar is new */
214 if ((prop = node.property ("divisions-per-bar")) == 0) {
215 if ((prop = node.property ("beats-per-bar")) == 0) {
216 error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
217 throw failed_constructor();
221 if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
222 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
223 throw failed_constructor();
226 if ((prop = node.property ("note-type")) == 0) {
227 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
228 throw failed_constructor();
231 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
232 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
233 throw failed_constructor();
236 if ((prop = node.property ("movable")) == 0) {
237 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
238 throw failed_constructor();
241 set_movable (string_is_affirmative (prop->value()));
245 MeterSection::get_state() const
247 XMLNode *root = new XMLNode (xml_state_node_name);
249 LocaleGuard lg (X_("POSIX"));
251 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
255 root->add_property ("start", buf);
256 snprintf (buf, sizeof (buf), "%f", _note_type);
257 root->add_property ("note-type", buf);
258 snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
259 root->add_property ("divisions-per-bar", buf);
260 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
261 root->add_property ("movable", buf);
266 /***********************************************************************/
268 struct MetricSectionSorter {
269 bool operator() (const MetricSection* a, const MetricSection* b) {
270 return a->start() < b->start();
274 TempoMap::TempoMap (framecnt_t fr)
276 metrics = new Metrics;
278 last_bbt_valid = false;
285 TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
286 MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
288 t->set_movable (false);
289 m->set_movable (false);
291 /* note: frame time is correct (zero) for both of these */
293 metrics->push_back (t);
294 metrics->push_back (m);
297 TempoMap::~TempoMap ()
302 TempoMap::remove_tempo (const TempoSection& tempo, bool send_signal)
304 bool removed = false;
307 Glib::RWLock::WriterLock lm (lock);
310 for (i = metrics->begin(); i != metrics->end(); ++i) {
311 if (dynamic_cast<TempoSection*> (*i) != 0) {
312 if (tempo.frame() == (*i)->frame()) {
313 if ((*i)->movable()) {
324 timestamp_metrics (false);
326 PropertyChanged (PropertyChange ());
332 TempoMap::remove_meter (const MeterSection& tempo, bool send_signal)
334 bool removed = false;
337 Glib::RWLock::WriterLock lm (lock);
340 for (i = metrics->begin(); i != metrics->end(); ++i) {
341 if (dynamic_cast<MeterSection*> (*i) != 0) {
342 if (tempo.frame() == (*i)->frame()) {
343 if ((*i)->movable()) {
354 timestamp_metrics (true);
356 PropertyChanged (PropertyChange ());
362 TempoMap::do_insert (MetricSection* section)
364 bool reassign_tempo_bbt = false;
366 assert (section->start().ticks == 0);
368 /* we only allow new meters to be inserted on beat 1 of an existing
372 if (dynamic_cast<MeterSection*>(section)) {
374 /* we need to (potentially) update the BBT times of tempo
375 sections based on this new meter.
378 reassign_tempo_bbt = true;
380 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
382 BBT_Time corrected = section->start();
386 warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
387 section->start(), corrected) << endmsg;
389 section->set_start (corrected);
395 /* Look for any existing MetricSection that is of the same type and
396 at the same time as the new one, and remove it before adding
400 Metrics::iterator to_remove = metrics->end ();
402 for (i = metrics->begin(); i != metrics->end(); ++i) {
404 int const c = (*i)->compare (*section);
407 /* this section is before the one to be added; go back round */
410 /* this section is after the one to be added; there can't be any at the same time */
414 /* hacky comparison of type */
415 bool const a = dynamic_cast<TempoSection*> (*i) != 0;
416 bool const b = dynamic_cast<TempoSection*> (section) != 0;
424 if (to_remove != metrics->end()) {
425 /* remove the MetricSection at the same time as the one we are about to add */
426 metrics->erase (to_remove);
429 /* Add the given MetricSection */
431 for (i = metrics->begin(); i != metrics->end(); ++i) {
433 if ((*i)->compare (*section) < 0) {
437 metrics->insert (i, section);
441 if (i == metrics->end()) {
442 metrics->insert (metrics->end(), section);
445 timestamp_metrics (reassign_tempo_bbt);
449 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where)
451 const TempoSection& first (first_tempo());
454 remove_tempo (ts, false);
455 add_tempo (tempo, where);
457 /* cannot move the first tempo section */
458 *((Tempo*)&first) = tempo;
459 timestamp_metrics (false);
462 PropertyChanged (PropertyChange ());
466 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
469 Glib::RWLock::WriterLock lm (lock);
471 /* new tempos always start on a beat */
474 TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type());
476 /* find the meter to use to set the bar offset of this
480 const Meter* meter = &first_meter();
482 /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
483 at something, because we insert the default tempo and meter during
484 TempoMap construction.
486 now see if we can find better candidates.
489 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
491 const MeterSection* m;
493 if (where < (*i)->start()) {
497 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
502 ts->update_bar_offset_from_bbt (*meter);
509 PropertyChanged (PropertyChange ());
513 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
515 const MeterSection& first (first_meter());
518 remove_meter (ms, false);
519 add_meter (meter, where);
521 /* cannot move the first meter section */
522 *((Meter*)&first) = meter;
523 timestamp_metrics (true);
526 PropertyChanged (PropertyChange ());
530 TempoMap::add_meter (const Meter& meter, BBT_Time where)
533 Glib::RWLock::WriterLock lm (lock);
535 /* a new meter always starts a new bar on the first beat. so
536 round the start time appropriately. remember that
537 `where' is based on the existing tempo map, not
538 the result after we insert the new meter.
542 if (where.beats != 1) {
547 /* new meters *always* start on a beat. */
550 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
554 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
559 PropertyChanged (PropertyChange ());
563 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
565 Tempo newtempo (beats_per_minute, note_type);
568 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
569 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
570 *((Tempo*) t) = newtempo;
571 PropertyChanged (PropertyChange ());
578 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
580 Tempo newtempo (beats_per_minute, note_type);
586 /* find the TempoSection immediately preceding "where"
589 for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
591 if ((*i)->frame() > where) {
597 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
607 error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
616 *((Tempo*)prev) = newtempo;
617 PropertyChanged (PropertyChange ());
621 TempoMap::first_meter () const
623 const MeterSection *m = 0;
625 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
626 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
631 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
637 TempoMap::first_tempo () const
639 const TempoSection *t = 0;
641 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
642 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
647 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
653 TempoMap::timestamp_metrics_from_audio_time ()
656 const MeterSection* meter;
657 const TempoSection* tempo;
661 meter = &first_meter ();
662 tempo = &first_tempo ();
667 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
670 MetricSection* prev = 0;
672 for (i = metrics->begin(); i != metrics->end(); ++i) {
675 TempoMetric metric (*meter, *tempo);
678 metric.set_start (prev->start());
679 metric.set_frame (prev->frame());
681 // metric will be at frames=0 bbt=1|1|0 by default
682 // which is correct for our purpose
685 bbt_time_with_metric ((*i)->frame(), bbt, metric);
687 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
693 if (bbt.ticks > BBT_Time::ticks_per_bar_division/2) {
694 /* round up to next beat */
700 if (bbt.beats != 1) {
701 /* round up to next bar */
707 // cerr << bbt << endl;
709 (*i)->set_start (bbt);
711 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
713 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
714 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
716 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
718 fatal << _("programming error: unhandled MetricSection type") << endmsg;
726 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
734 TempoMap::timestamp_metrics (bool reassign_tempo_bbt)
737 const MeterSection* meter;
738 const TempoSection* tempo;
742 DEBUG_TRACE (DEBUG::TempoMath, "###################### TIMESTAMP via BBT ##############\n");
744 framepos_t current = 0;
745 framepos_t section_frames;
749 if (reassign_tempo_bbt) {
751 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
753 meter = &first_meter ();
754 tempo = &first_tempo ();
756 for (i = metrics->begin(); i != metrics->end(); ++i) {
758 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
760 /* reassign the BBT time of this tempo section
761 * based on its bar offset position.
764 t->update_bbt_time_from_bar_offset (*meter);
767 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
770 fatal << _("programming error: unhandled MetricSection type") << endmsg;
776 meter = &first_meter ();
777 tempo = &first_tempo ();
779 for (i = metrics->begin(); i != metrics->end(); ++i) {
783 section_frames = count_frames_between_metrics (*meter, *tempo, start, end);
784 current += section_frames;
786 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("frames between %1 & %2 = %3 using %4 & %6 puts %7 at %8\n",
787 start, end, section_frames,
788 *((Meter*) meter), *((Tempo*) tempo),
789 (*i)->start(), current));
793 (*i)->set_frame (current);
795 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
797 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
800 fatal << _("programming error: unhandled MetricSection type") << endmsg;
807 if (DEBUG_ENABLED(DEBUG::TempoMath)) {
812 DEBUG_TRACE (DEBUG::TempoMath, "###############################################\n");
817 TempoMap::metric_at (framepos_t frame) const
819 TempoMetric m (first_meter(), first_tempo());
823 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
824 at something, because we insert the default tempo and meter during
825 TempoMap construction.
827 now see if we can find better candidates.
830 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
832 // cerr << "Looking at a metric section " << **i << endl;
834 if ((*i)->frame() > frame) {
838 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
839 m.set_tempo (*tempo);
840 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
841 m.set_meter (*meter);
844 m.set_frame ((*i)->frame ());
845 m.set_start ((*i)->start ());
848 // cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << " location " << m.frame() << " = " << m.start() << endl;
853 TempoMap::metric_at (BBT_Time bbt) const
855 TempoMetric m (first_meter(), first_tempo());
859 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
860 at something, because we insert the default tempo and meter during
861 TempoMap construction.
863 now see if we can find better candidates.
866 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
868 BBT_Time section_start ((*i)->start());
870 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
874 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
875 m.set_tempo (*tempo);
876 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
877 m.set_meter (*meter);
880 m.set_frame ((*i)->frame ());
881 m.set_start (section_start);
888 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt) const
891 Glib::RWLock::ReaderLock lm (lock);
892 bbt_time_unlocked (frame, bbt);
897 TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt) const
899 bbt_time_with_metric (frame, bbt, metric_at (frame));
903 TempoMap::bbt_time_with_metric (framepos_t frame, BBT_Time& bbt, const TempoMetric& metric) const
905 const double divisions_per_bar = metric.meter().divisions_per_bar();
906 const double frames_per_tick = metric.meter().frames_per_division (metric.tempo(),_frame_rate) / BBT_Time::ticks_per_bar_division;
908 /* now compute how far beyond the metric we actually are, and add the
909 * relevant number of ticks to the metric's BBT time
912 framecnt_t frame_diff = frame - metric.frame();
913 uint32_t tick_diff = (uint32_t) lrint ((double) frame_diff / frames_per_tick);
915 bbt.ticks = metric.start().ticks + tick_diff;
916 uint32_t beat_overflow = bbt.ticks / (uint32_t) BBT_Time::ticks_per_bar_division;
917 bbt.ticks = bbt.ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
918 bbt.beats = metric.start().beats + beat_overflow;
919 /* bbt.beats uses 1-based counting, so adjust to get the right answer */
920 uint32_t bar_overflow = (bbt.beats - 1) / (uint32_t) divisions_per_bar;
921 bbt.bars = metric.start().bars + bar_overflow;
923 /* fmod will map bbt.beats as follows:
925 Beats divisions per bar Normalized beat
942 so, the only special cases are 0, N, 2N etc. however bbt.beats is
943 never zero, so the only actual special cases are N, 2N and so on,
944 allowing us to use a special case check for fmod () == 0 and
945 changing the value to divisions per bar
948 bbt.beats = (uint32_t) fmod (bbt.beats, divisions_per_bar);
950 if (bbt.beats == 0) {
951 bbt.beats = divisions_per_bar;
956 TempoMap::count_frames_between (const BBT_Time& start, const BBT_Time& end) const
958 TempoMetric bm = metric_at (start);
959 TempoMetric em = metric_at (end);
961 return count_frames_with_metrics (bm, em, start, end);
965 TempoMap::count_frames_with_metrics (const TempoMetric& bm, const TempoMetric& em, const BBT_Time& start, const BBT_Time& end) const
967 framecnt_t frames = 0;
968 framepos_t start_frame = 0;
969 framepos_t end_frame = 0;
971 uint32_t bar_offset = start.bars - bm.start().bars;
973 double beat_offset = bar_offset*bm.meter().divisions_per_bar() - (bm.start().beats-1) + (start.beats -1)
974 + start.ticks/BBT_Time::ticks_per_bar_division;
976 start_frame = bm.frame() + (framepos_t) rint(beat_offset * bm.meter().frames_per_division(bm.tempo(),_frame_rate));
979 cerr << "from start " << start << " compute frame = " << start_frame
980 << " from metric at " << bm.frame() << " tempo = " << bm.tempo().beats_per_minute () << " meter "
981 << bm.meter().divisions_per_bar() << '/' << bm.meter().note_divisor()
985 bar_offset = end.bars - em.start().bars;
987 beat_offset = bar_offset * em.meter().divisions_per_bar() - (em.start().beats -1) + (end.beats - 1)
988 + end.ticks/BBT_Time::ticks_per_bar_division;
990 end_frame = em.frame() + (framepos_t) rint(beat_offset * em.meter().frames_per_division(em.tempo(),_frame_rate));
993 cerr << "from end " << end << " compute frame = " << end_frame
994 << " from metric at " << em.frame() << " tempo = " << em.tempo().beats_per_minute () << " meter "
995 << em.meter().divisions_per_bar() << '/' << em.meter().note_divisor()
999 frames = end_frame - start_frame;
1005 TempoMap::count_frames_between_metrics (const Meter& meter, const Tempo& tempo, const BBT_Time& start, const BBT_Time& end) const
1007 /* this is used in timestamping the metrics by actually counting the
1008 * beats between two metrics ONLY. this means that we know we have a
1009 * fixed divisions_per_bar and frames_per_division for the entire
1013 framecnt_t frames = 0;
1014 uint32_t bar = start.bars;
1015 double beat = (double) start.beats;
1016 double divisions_counted = 0;
1017 double divisions_per_bar = 0;
1018 double division_frames = 0;
1022 divisions_per_bar = meter.divisions_per_bar();
1023 max_divs = ceil (divisions_per_bar);
1024 division_frames = meter.frames_per_division (tempo, _frame_rate);
1026 if (start.ticks > 0) {
1027 ticks = -start.ticks;
1033 while (bar < end.bars || (bar == end.bars && beat < end.beats)) {
1036 ++divisions_counted;
1038 if (beat > max_divs) {
1040 if (beat > divisions_per_bar) {
1042 /* this is a fractional beat at the end of a fractional bar
1043 so it should only count for the fraction
1046 divisions_counted -= (max_divs - divisions_per_bar);
1057 cerr << "for " << start.ticks << " and " << end.ticks << " adjust divs by " << ticks << " = "
1058 << (ticks/BBT_Time::ticks_per_bar_division) << " divs => "
1059 << ((ticks/BBT_Time::ticks_per_bar_division) * division_frames)
1060 << " (fpd = " << division_frames << ')'
1064 frames = (framecnt_t) llrint (floor ((divisions_counted + (ticks/BBT_Time::ticks_per_bar_division)) * division_frames));
1067 cerr << "Counted " << divisions_counted << " + " << ticks << " from " << start << " to " << end
1068 << " dpb were " << divisions_per_bar
1069 << " fpd was " << division_frames
1080 TempoMap::frame_time (const BBT_Time& bbt) const
1082 BBT_Time start ; /* 1|1|0 */
1084 return count_frames_between (start, bbt);
1088 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir) const
1090 framecnt_t frames = 0;
1093 bbt_time(pos, when);
1096 Glib::RWLock::ReaderLock lm (lock);
1097 frames = bbt_duration_at_unlocked (when, bbt,dir);
1104 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const
1106 framecnt_t frames = 0;
1108 double divisions_per_bar;
1111 result.bars = max(1U, when.bars + dir * bbt.bars) ;
1115 TempoMetric metric = metric_at(result);
1116 divisions_per_bar = metric.meter().divisions_per_bar();
1118 /* Reduce things to legal bbt values we have to handle possible
1119 fractional=shorter beats at the end of measures and things like 0|11|9000
1120 as a duration in a 4.5/4 measure the musical decision is that the
1121 fractional beat is also a beat , although a shorter one
1125 result.beats = when.beats + bbt.beats;
1126 result.ticks = when.ticks + bbt.ticks;
1128 while (result.beats >= (divisions_per_bar + 1)) {
1130 result.beats -= (uint32_t) ceil(divisions_per_bar);
1131 metric = metric_at(result); // maybe there is a meter change
1132 divisions_per_bar = metric.meter().divisions_per_bar();
1136 /* We now counted the beats and landed in the target measure, now deal
1137 with ticks this seems complicated, but we want to deal with the
1138 corner case of a sequence of time signatures like 0.2/4-0.7/4 and
1139 with request like bbt = 3|2|9000 ,so we repeat the same loop but add
1143 /* of course gtk_ardour only allows bar with at least 1.0 beats .....
1146 uint32_t ticks_at_beat = (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1147 (1 - (ceil(divisions_per_bar) - divisions_per_bar))* BBT_Time::ticks_per_bar_division
1148 : BBT_Time::ticks_per_bar_division );
1150 while (result.ticks >= ticks_at_beat) {
1152 result.ticks -= ticks_at_beat;
1153 if (result.beats >= (divisions_per_bar + 1)) {
1156 metric = metric_at(result); // maybe there is a meter change
1157 divisions_per_bar = metric.meter().divisions_per_bar();
1159 ticks_at_beat= (uint32_t) (result.beats == ceil(divisions_per_bar) ?
1160 (1 - (ceil(divisions_per_bar) - divisions_per_bar) ) * BBT_Time::ticks_per_bar_division
1161 : BBT_Time::ticks_per_bar_division);
1166 uint32_t b = bbt.beats;
1169 while (b > when.beats) {
1171 result.bars = max(1U, result.bars);
1172 metric = metric_at(result); // maybe there is a meter change
1173 divisions_per_bar = metric.meter().divisions_per_bar();
1174 if (b >= ceil(divisions_per_bar)) {
1175 b -= (uint32_t) ceil(divisions_per_bar);
1177 b = (uint32_t) ceil(divisions_per_bar) - b + when.beats ;
1180 result.beats = when.beats - b;
1184 if (bbt.ticks <= when.ticks) {
1185 result.ticks = when.ticks - bbt.ticks;
1188 uint32_t ticks_at_beat= (uint32_t) BBT_Time::ticks_per_bar_division;
1189 uint32_t t = bbt.ticks - when.ticks;
1193 if (result.beats == 1) {
1195 result.bars = max(1U, result.bars) ;
1196 metric = metric_at(result); // maybe there is a meter change
1197 divisions_per_bar = metric.meter().divisions_per_bar();
1198 result.beats = (uint32_t) ceil(divisions_per_bar);
1199 ticks_at_beat = (uint32_t) ((1 - (ceil(divisions_per_bar) - divisions_per_bar)) * BBT_Time::ticks_per_bar_division) ;
1202 ticks_at_beat = (uint32_t) BBT_Time::ticks_per_bar_division;
1205 if (t <= ticks_at_beat) {
1206 result.ticks = ticks_at_beat - t;
1210 } while (t > ticks_at_beat);
1218 frames = count_frames_between(result, when);
1220 frames = count_frames_between(when,result);
1229 TempoMap::round_to_bar (framepos_t fr, int dir)
1232 Glib::RWLock::ReaderLock lm (lock);
1233 return round_to_type (fr, dir, Bar);
1239 TempoMap::round_to_beat (framepos_t fr, int dir)
1242 Glib::RWLock::ReaderLock lm (lock);
1243 return round_to_type (fr, dir, Beat);
1248 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1251 uint32_t ticks_one_half_subdivisions_worth;
1252 uint32_t ticks_one_subdivisions_worth;
1253 uint32_t difference;
1255 bbt_time(fr, the_beat);
1257 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_bar_division / sub_num;
1258 ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1264 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1267 /* right on the subdivision, so the difference is just the subdivision ticks */
1268 difference = ticks_one_subdivisions_worth;
1271 /* not on subdivision, compute distance to next subdivision */
1273 difference = ticks_one_subdivisions_worth - mod;
1276 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1278 } else if (dir < 0) {
1280 /* round to previous */
1282 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1285 /* right on the subdivision, so the difference is just the subdivision ticks */
1286 difference = ticks_one_subdivisions_worth;
1288 /* not on subdivision, compute distance to previous subdivision, which
1289 is just the modulus.
1296 the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1298 /* can't go backwards from wherever pos is, so just return it */
1303 /* round to nearest */
1305 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1306 difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1307 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1309 // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1310 the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1314 return frame_time (the_beat);
1318 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1320 TempoMetric metric = metric_at (frame);
1323 BBT_Time one_bar (1,0,0);
1324 BBT_Time one_beat (0,1,0);
1326 bbt_time_with_metric (frame, bbt, metric);
1330 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to bars in direction %2\n", frame, dir, bbt));
1334 /* find bar position preceding frame */
1337 bbt = bbt_subtract (bbt, one_bar);
1345 } else if (dir > 0) {
1347 /* find bar position following frame */
1350 bbt = bbt_add (bbt, one_bar, metric);
1358 /* "true" rounding */
1363 midbar_beats = metric.meter().divisions_per_bar() / 2 + 1;
1364 midbar_ticks = BBT_Time::ticks_per_bar_division * fmod (midbar_beats, 1.0f);
1365 midbar_beats = floor (midbar_beats);
1367 BBT_Time midbar (bbt.bars, lrintf (midbar_beats), lrintf (midbar_ticks));
1380 /* force beats & ticks to their values at the start of a bar */
1386 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3) to beat in direction %2\n", frame, (dir < 0 ? "back" : "forward"), bbt));
1390 /* find beat position preceding frame */
1393 bbt = bbt_subtract (bbt, one_beat);
1401 } else if (dir > 0) {
1403 /* find beat position following frame */
1406 bbt = bbt_add (bbt, one_beat, metric);
1414 /* "true" rounding */
1416 /* round to nearest beat */
1417 if (bbt.ticks >= (BBT_Time::ticks_per_bar_division/2)) {
1420 bbt = bbt_add (bbt, one_beat, metric);
1427 /* force ticks to the value at the start of a beat */
1433 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)));
1434 return metric.frame() + count_frames_between (metric.start(), bbt);
1437 TempoMap::BBTPointList *
1438 TempoMap::get_points (framepos_t lower, framepos_t upper) const
1440 Metrics::const_iterator next_metric;
1441 BBTPointList *points;
1443 const MeterSection* meter;
1444 const MeterSection* m;
1445 const TempoSection* tempo;
1446 const TempoSection* t;
1449 double divisions_per_bar;
1452 double frames_per_bar;
1458 meter = &first_meter ();
1459 tempo = &first_tempo ();
1461 /* find the starting point */
1463 for (next_metric = metrics->begin(); next_metric != metrics->end(); ++next_metric) {
1465 if ((*next_metric)->frame() > lower) {
1469 if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1471 } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1478 meter -> the Meter for "lower"
1479 tempo -> the Tempo for "lower"
1480 i -> for first new metric after "lower", possibly metrics->end()
1482 Now start generating points.
1485 divisions_per_bar = meter->divisions_per_bar ();
1486 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1487 beat_frames = meter->frames_per_division (*tempo,_frame_rate);
1489 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Start with beat frames = %1 bar = %2\n", beat_frames, frames_per_bar));
1491 if (meter->frame() > tempo->frame()) {
1492 bar = meter->start().bars;
1493 beat = meter->start().beats;
1494 current = meter->frame();
1496 bar = tempo->start().bars;
1497 beat = tempo->start().beats;
1498 current = tempo->frame();
1501 /* initialize current to point to the bar/beat just prior to the
1502 lower frame bound passed in. assumes that current is initialized
1503 above to be on a beat.
1506 delta_bars = (lower-current) / frames_per_bar;
1507 delta_beats = modf(delta_bars, &dummy) * divisions_per_bar;
1508 current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames);
1510 // adjust bars and beats too
1511 bar += (uint32_t) (floor(delta_bars));
1512 beat += (uint32_t) (floor(delta_beats));
1514 points = new BBTPointList;
1518 /* we're going to add bar or beat points until we hit the
1521 (1) the end point of this request
1522 (2) the next metric section
1525 if (next_metric == metrics->end()) {
1527 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to end of request @ %1\n", limit));
1529 limit = (*next_metric)->frame();
1530 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("== limit set to next metric section @ %1\n", limit));
1533 limit = min (limit, upper);
1535 bool reset_current_to_metric_section = true;
1536 bool bar_adjusted = false;
1539 while (current < limit) {
1541 /* if we're at the start of a bar, add bar point */
1544 if (current >= lower) {
1545 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", bar, current));
1546 points->push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current), Bar, bar, 1));
1551 /* add some beats if we can */
1553 beat_frame = current;
1555 const uint32_t max_divs = ceil (divisions_per_bar);
1557 while (beat <= max_divs && beat_frame < limit) {
1559 if (beat_frame >= lower) {
1560 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", bar, beat, beat_frame));
1561 points->push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(beat_frame), Beat, bar, beat));
1564 beat_frame += beat_frames;
1565 current = beat_frame;
1569 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",
1570 (next_metric == metrics->end()), (beat > max_divs), beat_frame, limit, beat, max_divs));
1572 if (beat <= max_divs) {
1574 /* we didn't reach the end of the bar.
1576 this could be be because we hit "upper"
1577 or a new metric section.
1579 meter sections are always at the start
1580 of a measure. put differently, if a meter
1581 indicates N divisions per bar, the next
1582 meter must be a multiple of N divisions
1585 so, we've hit a tempo section, which may or
1586 may not be precisely on a beat.
1589 if (next_metric != metrics->end() && limit == (*next_metric)->frame() && ((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0) && ts->start().ticks != 0) {
1591 /* compute current at the *next* beat,
1592 using the tempo section we just
1595 also, avoid resetting it to position
1596 of the next metric section as we
1600 reset_current_to_metric_section = false;
1602 /* recompute how many frames per
1603 * division using the tempo we've just
1607 double next_beat_frames = meter->frames_per_division (*ts,_frame_rate);
1609 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
1610 (*next_metric)->start(), (*next_metric)->frame(), ts->bar_offset()));
1612 current -= beat_frames;
1613 current += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
1616 } else if ((beat > max_divs) || (next_metric != metrics->end() && dynamic_cast<MeterSection*>(*next_metric))) {
1618 /* we've arrived at either the end of a bar or
1619 a new **meter** marker (not tempo marker).
1621 its important to move `current' forward by
1622 the actual frames_per_bar, not move it to an
1623 integral beat_frame, so that metrics with
1624 non-integral beats-per-bar have their bar
1625 positions set correctly. consider a metric
1626 with 9-1/2 beats-per-bar. the bar we just
1627 filled had 10 beat marks, but the bar end is
1628 1/2 beat before the last beat mark. And it
1629 is also possible that a tempo change occured
1630 in the middle of a bar, so we subtract the
1631 possible extra fraction from the current
1634 if (beat > max_divs) {
1635 /* next bar goes where the numbers suggest */
1636 current -= beat_frames * (max_divs - divisions_per_bar);
1637 DEBUG_TRACE (DEBUG::TempoMath, "++ next bar from numbers\n");
1639 /* next bar goes where the next meter metric is */
1641 DEBUG_TRACE (DEBUG::TempoMath, "++ next bar at next metric\n");
1646 bar_adjusted = true;
1650 /* if we're done, then we're done */
1652 if (current >= upper) {
1656 /* i is an iterator that refers to the next metric (or none).
1657 if there is a next metric, move to it, and continue.
1660 if (next_metric != metrics->end()) {
1662 if ((t = dynamic_cast<const TempoSection*>(*next_metric)) != 0) {
1664 } else if ((m = dynamic_cast<const MeterSection*>(*next_metric)) != 0) {
1667 if (!bar_adjusted) {
1668 /* new MeterSection, beat always returns to 1 */
1673 if (reset_current_to_metric_section) {
1674 current = (*next_metric)->frame ();
1677 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("loop around with current @ %1\n", current));
1679 divisions_per_bar = meter->divisions_per_bar ();
1680 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
1681 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
1683 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 bar = %2 dpb %3 meter %4 tempo %5\n",
1684 beat_frames, frames_per_bar, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
1695 TempoMap::tempo_section_at (framepos_t frame) const
1697 Glib::RWLock::ReaderLock lm (lock);
1698 Metrics::const_iterator i;
1699 TempoSection* prev = 0;
1701 for (i = metrics->begin(); i != metrics->end(); ++i) {
1704 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1706 if ((*i)->frame() > frame) {
1722 TempoMap::tempo_at (framepos_t frame) const
1724 TempoMetric m (metric_at (frame));
1730 TempoMap::meter_at (framepos_t frame) const
1732 TempoMetric m (metric_at (frame));
1737 TempoMap::get_state ()
1739 Metrics::const_iterator i;
1740 XMLNode *root = new XMLNode ("TempoMap");
1743 Glib::RWLock::ReaderLock lm (lock);
1744 for (i = metrics->begin(); i != metrics->end(); ++i) {
1745 root->add_child_nocopy ((*i)->get_state());
1753 TempoMap::set_state (const XMLNode& node, int /*version*/)
1756 Glib::RWLock::WriterLock lm (lock);
1759 XMLNodeConstIterator niter;
1760 Metrics old_metrics (*metrics);
1761 MeterSection* last_meter = 0;
1765 nlist = node.children();
1767 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1768 XMLNode* child = *niter;
1770 if (child->name() == TempoSection::xml_state_node_name) {
1773 TempoSection* ts = new TempoSection (*child);
1774 metrics->push_back (ts);
1776 if (ts->bar_offset() < 0.0) {
1778 ts->update_bar_offset_from_bbt (*last_meter);
1783 catch (failed_constructor& err){
1784 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1785 *metrics = old_metrics;
1789 } else if (child->name() == MeterSection::xml_state_node_name) {
1792 MeterSection* ms = new MeterSection (*child);
1793 metrics->push_back (ms);
1797 catch (failed_constructor& err) {
1798 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1799 *metrics = old_metrics;
1805 if (niter == nlist.end()) {
1807 MetricSectionSorter cmp;
1808 metrics->sort (cmp);
1809 timestamp_metrics (true);
1813 PropertyChanged (PropertyChange ());
1819 TempoMap::dump (std::ostream& o) const
1821 const MeterSection* m;
1822 const TempoSection* t;
1824 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1826 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1827 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? "
1828 << t->movable() << ')' << endl;
1829 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1830 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1831 << " (movable? " << m->movable() << ')' << endl;
1837 TempoMap::n_tempos() const
1839 Glib::RWLock::ReaderLock lm (lock);
1842 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1843 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1852 TempoMap::n_meters() const
1854 Glib::RWLock::ReaderLock lm (lock);
1857 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1858 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1867 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1869 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1870 if ((*i)->frame() >= where && (*i)->movable ()) {
1871 (*i)->set_frame ((*i)->frame() + amount);
1875 timestamp_metrics_from_audio_time ();
1877 PropertyChanged (PropertyChange ());
1881 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1883 TempoMetric metric = metric_at (start);
1884 return bbt_add (start, other, metric);
1888 * add the BBT interval @param increment to @param start and return the result
1891 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1893 BBT_Time result = start;
1894 BBT_Time op = increment; /* argument is const, but we need to modify it */
1895 uint32_t ticks = result.ticks + op.ticks;
1897 if (ticks >= BBT_Time::ticks_per_bar_division) {
1899 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
1901 result.ticks += op.ticks;
1904 /* now comes the complicated part. we have to add one beat a time,
1905 checking for a new metric on every beat.
1908 /* grab all meter sections */
1910 list<const MeterSection*> meter_sections;
1912 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1913 const MeterSection* ms;
1914 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1915 meter_sections.push_back (ms);
1919 assert (!meter_sections.empty());
1921 list<const MeterSection*>::const_iterator next_meter;
1922 const Meter* meter = 0;
1924 /* go forwards through the meter sections till we get to the one
1925 covering the current value of result. this positions i to point to
1926 the next meter section too, or the end.
1929 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1931 if (result < (*next_meter)->start()) {
1932 /* this metric is past the result time. stop looking, we have what we need */
1936 if (result == (*next_meter)->start()) {
1937 /* this meter section starts at result, push i beyond it so that it points
1938 to the NEXT section, opwise we will get stuck later, and use this meter section.
1940 meter = *next_meter;
1945 meter = *next_meter;
1948 assert (meter != 0);
1950 /* OK, now have the meter for the bar start we are on, and i is an iterator
1951 that points to the metric after the one we are currently dealing with
1952 (or to metrics->end(), of course)
1957 /* given the current meter, have we gone past the end of the bar ? */
1959 if (result.beats >= meter->divisions_per_bar()) {
1960 /* move to next bar, first beat */
1971 /* check if we need to use a new meter section: has adding beats to result taken us
1972 to or after the start of the next meter section? in which case, use it.
1975 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1976 meter = *next_meter;
1981 /* finally, add bars */
1983 result.bars += op.bars++;
1989 * subtract the BBT interval @param decrement from @param start and return the result
1992 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1994 BBT_Time result = start;
1995 BBT_Time op = decrement; /* argument is const, but we need to modify it */
1997 if (op.ticks > result.ticks) {
1998 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
2000 result.ticks = BBT_Time::ticks_per_bar_division - (op.ticks - result.ticks);
2002 result.ticks -= op.ticks;
2005 /* now comes the complicated part. we have to subtract one beat a time,
2006 checking for a new metric on every beat.
2009 /* grab all meter sections */
2011 list<const MeterSection*> meter_sections;
2013 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
2014 const MeterSection* ms;
2015 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
2016 meter_sections.push_back (ms);
2020 assert (!meter_sections.empty());
2022 /* go backwards through the meter sections till we get to the one
2023 covering the current value of result. this positions i to point to
2024 the next (previous) meter section too, or the end.
2027 const MeterSection* meter = 0;
2028 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
2029 // support const_reverse_iterator::operator!=()
2031 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
2033 /* when we find the first meter section that is before or at result, use it,
2034 and set next_meter to the previous one
2037 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
2038 meter = *next_meter;
2044 assert (meter != 0);
2046 /* OK, now have the meter for the bar start we are on, and i is an iterator
2047 that points to the metric after the one we are currently dealing with
2048 (or to metrics->end(), of course)
2053 /* have we reached the start of the bar? if so, move to the last beat of the previous
2054 bar. opwise, just step back 1 beat.
2057 if (result.beats == 1) {
2059 /* move to previous bar, last beat */
2061 if (result.bars <= 1) {
2062 /* i'm sorry dave, i can't do that */
2063 throw std::out_of_range ("illegal BBT subtraction");
2067 result.beats = meter->divisions_per_bar();
2078 /* check if we need to use a new meter section: has subtracting beats to result taken us
2079 to before the start of the current meter section? in which case, use the prior one.
2082 if (result < meter->start() && next_meter != meter_sections.rend()) {
2083 meter = *next_meter;
2088 /* finally, subtract bars */
2090 if (op.bars >= result.bars) {
2091 /* i'm sorry dave, i can't do that */
2092 throw std::out_of_range ("illegal BBT subtraction");
2095 result.bars -= op.bars;
2099 /** Add some (fractional) beats to a session frame position, and return the result in frames.
2100 * pos can be -ve, if required.
2103 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2105 Metrics::const_iterator i;
2106 const TempoSection* tempo;
2108 /* Find the starting tempo */
2110 for (i = metrics->begin(); i != metrics->end(); ++i) {
2112 /* This is a bit of a hack, but pos could be -ve, and if it is,
2113 we consider the initial metric changes (at time 0) to actually
2114 be in effect at pos.
2116 framepos_t f = (*i)->frame ();
2117 if (pos < 0 && f == 0) {
2125 const TempoSection* t;
2127 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2134 tempo -> the Tempo for "pos"
2135 i -> for first new metric after "pos", possibly metrics->end()
2140 /* Distance to the end of this section in frames */
2141 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
2143 /* Distance to the end in beats */
2144 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2146 /* Amount to subtract this time */
2147 double const sub = min (distance_beats, beats);
2151 pos += sub * tempo->frames_per_beat (_frame_rate);
2153 /* Move on if there's anything to move to */
2154 if (i != metrics->end ()) {
2155 const TempoSection* t;
2157 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2168 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
2170 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats) const
2172 Metrics::const_iterator i;
2173 const TempoSection* tempo = 0;
2174 const TempoSection* t;
2176 /* Find the starting tempo */
2178 for (i = metrics->begin(); i != metrics->end(); ++i) {
2180 /* This is a bit of a hack, but pos could be -ve, and if it is,
2181 we consider the initial metric changes (at time 0) to actually
2182 be in effect at pos.
2184 framepos_t f = (*i)->frame ();
2185 if (pos < 0 && f == 0) {
2189 if ((*i)->frame() > pos) {
2193 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2198 bool no_more_tempos = false;
2200 /* Move i back to the tempo before "pos" */
2201 if (i != metrics->begin ()) {
2202 while (i != metrics->begin ()) {
2204 t = dynamic_cast<TempoSection*> (*i);
2210 no_more_tempos = true;
2215 tempo -> the Tempo for "pos"
2216 i -> the first metric before "pos", unless no_more_tempos is true
2221 /* Distance to the end of this section in frames */
2222 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
2224 /* Distance to the end in beats */
2225 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
2227 /* Amount to subtract this time */
2228 double const sub = min (distance_beats, beats);
2232 pos -= sub * tempo->frames_per_beat (_frame_rate);
2234 /* Move i and tempo back, if there's anything to move to */
2235 if (i != metrics->begin ()) {
2236 while (i != metrics->begin ()) {
2238 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2244 no_more_tempos = true;
2251 /** Add the BBT interval op to pos and return the result */
2253 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op) const
2255 Metrics::const_iterator i;
2256 const MeterSection* meter;
2257 const MeterSection* m;
2258 const TempoSection* tempo;
2259 const TempoSection* t;
2260 double frames_per_beat;
2262 meter = &first_meter ();
2263 tempo = &first_tempo ();
2268 /* find the starting metrics for tempo & meter */
2270 for (i = metrics->begin(); i != metrics->end(); ++i) {
2272 if ((*i)->frame() > pos) {
2276 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2278 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2285 meter -> the Meter for "pos"
2286 tempo -> the Tempo for "pos"
2287 i -> for first new metric after "pos", possibly metrics->end()
2290 /* now comes the complicated part. we have to add one beat a time,
2291 checking for a new metric on every beat.
2294 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2303 /* check if we need to use a new metric section: has adding frames moved us
2304 to or after the start of the next metric section? in which case, use it.
2307 if (i != metrics->end()) {
2308 if ((*i)->frame() <= pos) {
2310 /* about to change tempo or meter, so add the
2311 * number of frames for the bars we've just
2312 * traversed before we change the
2313 * frames_per_beat value.
2316 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2319 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2321 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2325 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2332 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2338 /* given the current meter, have we gone past the end of the bar ? */
2343 /* check if we need to use a new metric section: has adding frames moved us
2344 to or after the start of the next metric section? in which case, use it.
2347 if (i != metrics->end()) {
2348 if ((*i)->frame() <= pos) {
2350 /* about to change tempo or meter, so add the
2351 * number of frames for the beats we've just
2352 * traversed before we change the
2353 * frames_per_beat value.
2356 pos += llrint (beats * frames_per_beat);
2359 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2361 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2365 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2370 pos += llrint (beats * frames_per_beat);
2373 if (op.ticks >= BBT_Time::ticks_per_bar_division) {
2374 pos += llrint (frames_per_beat + /* extra beat */
2375 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_bar_division) /
2376 (double) BBT_Time::ticks_per_bar_division)));
2378 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_bar_division));
2385 /** Count the number of beats that are equivalent to distance when going forward,
2389 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance) const
2391 Metrics::const_iterator i;
2392 const TempoSection* tempo;
2394 /* Find the starting tempo */
2396 for (i = metrics->begin(); i != metrics->end(); ++i) {
2398 if ((*i)->frame() > pos) {
2402 const TempoSection* t;
2404 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2411 tempo -> the Tempo for "pos"
2412 i -> the first metric after "pos", possibly metrics->end()
2415 Evoral::MusicalTime beats = 0;
2419 /* End of this section */
2420 framepos_t const end = i == metrics->end() ? max_framepos : (*i)->frame ();
2422 /* Distance to the end in frames */
2423 framecnt_t const distance_to_end = end - pos;
2425 /* Amount to subtract this time */
2426 double const sub = min (distance, distance_to_end);
2431 beats += sub / tempo->frames_per_beat (_frame_rate);
2433 /* Move on if there's anything to move to */
2434 if (i != metrics->end ()) {
2435 const TempoSection* t;
2437 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2448 /** Compare the time of this with that of another MetricSection.
2449 * @param with_bbt True to compare using start(), false to use frame().
2450 * @return -1 for less than, 0 for equal, 1 for greater than.
2454 MetricSection::compare (const MetricSection& other) const
2456 if (start() == other.start()) {
2458 } else if (start() < other.start()) {
2469 MetricSection::operator== (const MetricSection& other) const
2471 return compare (other) == 0;
2475 MetricSection::operator!= (const MetricSection& other) const
2477 return compare (other) != 0;
2481 operator<< (std::ostream& o, const Meter& m) {
2482 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2486 operator<< (std::ostream& o, const Tempo& t) {
2487 return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2491 operator<< (std::ostream& o, const MetricSection& section) {
2493 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2495 const TempoSection* ts;
2496 const MeterSection* ms;
2498 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2499 o << *((Tempo*) ts);
2500 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2501 o << *((Meter*) ms);