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 = ((start().beats - 1) * BBT_Time::ticks_per_bar_division + start().ticks) /
160 (m.divisions_per_bar() * BBT_Time::ticks_per_bar_division);
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 * meter.divisions_per_bar() * _bar_offset;
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 /* remember the 1-based counting properties of beats */
182 new_start.beats += 1;
184 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n",
185 _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats));
187 set_start (new_start);
190 /***********************************************************************/
192 const string MeterSection::xml_state_node_name = "Meter";
194 MeterSection::MeterSection (const XMLNode& node)
195 : MetricSection (BBT_Time()), Meter (TempoMap::default_meter())
197 const XMLProperty *prop;
199 LocaleGuard lg (X_("POSIX"));
201 if ((prop = node.property ("start")) == 0) {
202 error << _("MeterSection XML node has no \"start\" property") << endmsg;
203 throw failed_constructor();
206 if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
210 error << _("MeterSection XML node has an illegal \"start\" value") << endmsg;
211 throw failed_constructor();
216 /* beats-per-bar is old; divisions-per-bar is new */
218 if ((prop = node.property ("divisions-per-bar")) == 0) {
219 if ((prop = node.property ("beats-per-bar")) == 0) {
220 error << _("MeterSection XML node has no \"beats-per-bar\" or \"divisions-per-bar\" property") << endmsg;
221 throw failed_constructor();
225 if (sscanf (prop->value().c_str(), "%lf", &_divisions_per_bar) != 1 || _divisions_per_bar < 0.0) {
226 error << _("MeterSection XML node has an illegal \"beats-per-bar\" or \"divisions-per-bar\" value") << endmsg;
227 throw failed_constructor();
230 if ((prop = node.property ("note-type")) == 0) {
231 error << _("MeterSection XML node has no \"note-type\" property") << endmsg;
232 throw failed_constructor();
235 if (sscanf (prop->value().c_str(), "%lf", &_note_type) != 1 || _note_type < 0.0) {
236 error << _("MeterSection XML node has an illegal \"note-type\" value") << endmsg;
237 throw failed_constructor();
240 if ((prop = node.property ("movable")) == 0) {
241 error << _("MeterSection XML node has no \"movable\" property") << endmsg;
242 throw failed_constructor();
245 set_movable (string_is_affirmative (prop->value()));
249 MeterSection::get_state() const
251 XMLNode *root = new XMLNode (xml_state_node_name);
253 LocaleGuard lg (X_("POSIX"));
255 snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32,
259 root->add_property ("start", buf);
260 snprintf (buf, sizeof (buf), "%f", _note_type);
261 root->add_property ("note-type", buf);
262 snprintf (buf, sizeof (buf), "%f", _divisions_per_bar);
263 root->add_property ("divisions-per-bar", buf);
264 snprintf (buf, sizeof (buf), "%s", movable()?"yes":"no");
265 root->add_property ("movable", buf);
270 /***********************************************************************/
272 struct MetricSectionSorter {
273 bool operator() (const MetricSection* a, const MetricSection* b) {
274 return a->start() < b->start();
278 TempoMap::TempoMap (framecnt_t fr)
280 metrics = new Metrics;
282 last_bbt_valid = false;
289 TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type());
290 MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor());
292 t->set_movable (false);
293 m->set_movable (false);
295 /* note: frame time is correct (zero) for both of these */
297 metrics->push_back (t);
298 metrics->push_back (m);
301 TempoMap::~TempoMap ()
306 TempoMap::remove_tempo (const TempoSection& tempo, bool complete_operation)
308 bool removed = false;
311 Glib::RWLock::WriterLock lm (lock);
314 for (i = metrics->begin(); i != metrics->end(); ++i) {
315 if (dynamic_cast<TempoSection*> (*i) != 0) {
316 if (tempo.frame() == (*i)->frame()) {
317 if ((*i)->movable()) {
326 if (removed && complete_operation) {
327 recompute_map (false);
331 if (removed && complete_operation) {
332 PropertyChanged (PropertyChange ());
337 TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
339 bool removed = false;
342 Glib::RWLock::WriterLock lm (lock);
345 for (i = metrics->begin(); i != metrics->end(); ++i) {
346 if (dynamic_cast<MeterSection*> (*i) != 0) {
347 if (tempo.frame() == (*i)->frame()) {
348 if ((*i)->movable()) {
357 if (removed && complete_operation) {
358 recompute_map (true);
364 if (removed && complete_operation) {
365 PropertyChanged (PropertyChange ());
370 TempoMap::do_insert (MetricSection* section)
372 /* CALLER MUST HOLD WRITE LOCK */
374 bool reassign_tempo_bbt = false;
376 assert (section->start().ticks == 0);
378 /* we only allow new meters to be inserted on beat 1 of an existing
382 if (dynamic_cast<MeterSection*>(section)) {
384 /* we need to (potentially) update the BBT times of tempo
385 sections based on this new meter.
388 reassign_tempo_bbt = true;
390 if ((section->start().beats != 1) || (section->start().ticks != 0)) {
392 BBT_Time corrected = section->start();
396 warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"),
397 section->start(), corrected) << endmsg;
399 section->set_start (corrected);
405 /* Look for any existing MetricSection that is of the same type and
406 at the same time as the new one, and remove it before adding
410 Metrics::iterator to_remove = metrics->end ();
412 for (i = metrics->begin(); i != metrics->end(); ++i) {
414 int const c = (*i)->compare (*section);
417 /* this section is before the one to be added; go back round */
420 /* this section is after the one to be added; there can't be any at the same time */
424 /* hacky comparison of type */
425 bool const a = dynamic_cast<TempoSection*> (*i) != 0;
426 bool const b = dynamic_cast<TempoSection*> (section) != 0;
434 if (to_remove != metrics->end()) {
435 /* remove the MetricSection at the same time as the one we are about to add */
436 metrics->erase (to_remove);
439 /* Add the given MetricSection */
441 for (i = metrics->begin(); i != metrics->end(); ++i) {
443 if ((*i)->compare (*section) < 0) {
447 metrics->insert (i, section);
451 if (i == metrics->end()) {
452 metrics->insert (metrics->end(), section);
455 recompute_map (reassign_tempo_bbt);
459 TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where)
461 const TempoSection& first (first_tempo());
464 remove_tempo (ts, false);
465 add_tempo (tempo, where);
467 Glib::RWLock::WriterLock lm (lock);
468 /* cannot move the first tempo section */
469 *((Tempo*)&first) = tempo;
470 recompute_map (false);
473 PropertyChanged (PropertyChange ());
477 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where)
480 Glib::RWLock::WriterLock lm (lock);
482 /* new tempos always start on a beat */
485 TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type());
487 /* find the meter to use to set the bar offset of this
491 const Meter* meter = &first_meter();
493 /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing
494 at something, because we insert the default tempo and meter during
495 TempoMap construction.
497 now see if we can find better candidates.
500 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
502 const MeterSection* m;
504 if (where < (*i)->start()) {
508 if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
513 ts->update_bar_offset_from_bbt (*meter);
520 PropertyChanged (PropertyChange ());
524 TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where)
526 const MeterSection& first (first_meter());
529 remove_meter (ms, false);
530 add_meter (meter, where);
532 Glib::RWLock::WriterLock lm (lock);
533 /* cannot move the first meter section */
534 *((Meter*)&first) = meter;
535 recompute_map (true);
538 PropertyChanged (PropertyChange ());
542 TempoMap::add_meter (const Meter& meter, BBT_Time where)
545 Glib::RWLock::WriterLock lm (lock);
547 /* a new meter always starts a new bar on the first beat. so
548 round the start time appropriately. remember that
549 `where' is based on the existing tempo map, not
550 the result after we insert the new meter.
554 if (where.beats != 1) {
559 /* new meters *always* start on a beat. */
562 do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor()));
566 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
571 PropertyChanged (PropertyChange ());
575 TempoMap::change_initial_tempo (double beats_per_minute, double note_type)
577 Tempo newtempo (beats_per_minute, note_type);
580 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
581 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
583 Glib::RWLock::WriterLock lm (lock);
584 *((Tempo*) t) = newtempo;
585 recompute_map (false);
587 PropertyChanged (PropertyChange ());
594 TempoMap::change_existing_tempo_at (framepos_t where, double beats_per_minute, double note_type)
596 Tempo newtempo (beats_per_minute, note_type);
602 /* find the TempoSection immediately preceding "where"
605 for (first = 0, i = metrics->begin(), prev = 0; i != metrics->end(); ++i) {
607 if ((*i)->frame() > where) {
613 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
623 error << string_compose (_("no tempo sections defined in tempo map - cannot change tempo @ %1"), where) << endmsg;
633 Glib::RWLock::WriterLock lm (lock);
634 /* cannot move the first tempo section */
635 *((Tempo*)prev) = newtempo;
636 recompute_map (false);
639 PropertyChanged (PropertyChange ());
643 TempoMap::first_meter () const
645 const MeterSection *m = 0;
647 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
648 if ((m = dynamic_cast<const MeterSection *> (*i)) != 0) {
653 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
659 TempoMap::first_tempo () const
661 const TempoSection *t = 0;
663 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
664 if ((t = dynamic_cast<const TempoSection *> (*i)) != 0) {
669 fatal << _("programming error: no tempo section in tempo map!") << endmsg;
675 TempoMap::timestamp_metrics_from_audio_time ()
678 const MeterSection* meter;
679 const TempoSection* tempo;
683 meter = &first_meter ();
684 tempo = &first_tempo ();
689 // cerr << "\n###################### TIMESTAMP via AUDIO ##############\n" << endl;
692 MetricSection* prev = 0;
694 for (i = metrics->begin(); i != metrics->end(); ++i) {
697 TempoMetric metric (*meter, *tempo);
700 metric.set_start (prev->start());
701 metric.set_frame (prev->frame());
703 // metric will be at frames=0 bbt=1|1|0 by default
704 // which is correct for our purpose
707 bbt_time_unlocked ((*i)->frame(), bbt);
709 // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => ";
715 if (bbt.ticks > BBT_Time::ticks_per_bar_division/2) {
716 /* round up to next beat */
722 if (bbt.beats != 1) {
723 /* round up to next bar */
729 // cerr << bbt << endl;
731 (*i)->set_start (bbt);
733 if ((t = dynamic_cast<TempoSection*>(*i)) != 0) {
735 // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
736 } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) {
738 // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl;
740 fatal << _("programming error: unhandled MetricSection type") << endmsg;
748 if (DEBUG_ENABLED(DEBUG::TempoMap)) {
756 TempoMap::require_map_to (framepos_t pos)
758 if (_map.empty() || _map.back().frame < pos) {
759 recompute_map (false, pos);
764 TempoMap::require_map_to (const BBT_Time& bbt)
766 if (_map.empty() || _map.back().bbt() < bbt) {
767 recompute_map (false, 99);
772 TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
778 double divisions_per_bar;
780 double frames_per_bar;
781 double current_frame;
783 Metrics::iterator next_metric;
787 /* compute 1 mins worth */
788 end = _frame_rate * 60;
790 end = _map.back().frame;
794 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
798 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
799 if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
805 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
806 if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
812 /* assumes that the first meter & tempo are at frame zero */
814 meter->set_frame (0);
815 tempo->set_frame (0);
817 /* assumes that the first meter & tempo are at 1|1|0 */
822 divisions_per_bar = meter->divisions_per_bar ();
823 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
824 beat_frames = meter->frames_per_division (*tempo,_frame_rate);
826 if (reassign_tempo_bbt) {
828 TempoSection* rtempo = tempo;
829 MeterSection* rmeter = meter;
831 DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n");
833 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
835 if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) {
837 /* reassign the BBT time of this tempo section
838 * based on its bar offset position.
841 ts->update_bbt_time_from_bar_offset (*rmeter);
844 } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) {
847 fatal << _("programming error: unhandled MetricSection type") << endmsg;
853 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2 dpb %3 fpb %4\n",
854 *((Meter*)meter), *((Tempo*)tempo), divisions_per_bar, beat_frames));
856 next_metric = metrics->begin();
857 ++next_metric; // skip meter (or tempo)
858 ++next_metric; // skip tempo (or meter)
860 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
861 _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), Bar, 1, 1));
863 while (current_frame < end) {
866 current_frame += beat_frames;
868 if (current.beats > meter->divisions_per_bar()) {
873 if (next_metric != metrics->end()) {
875 /* no operator >= so invert operator < */
877 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("now at %1 next metric @ %2\n", current, (*next_metric)->start()));
879 if (!(current < (*next_metric)->start())) {
882 if (((ts = dynamic_cast<TempoSection*> (*next_metric)) != 0)) {
886 /* new tempo section: if its on a beat,
887 * we don't have to do anything other
888 * than recompute various distances,
889 * done further below as we transition
890 * the next metric section.
892 * if its not on the beat, we have to
893 * compute the duration of the beat it
894 * is within, which will be different
895 * from the preceding following ones
896 * since it takes part of its duration
897 * from the preceding tempo and part
898 * from this new tempo.
901 if (tempo->start().ticks != 0) {
903 double next_beat_frames = meter->frames_per_division (*tempo,_frame_rate);
905 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into non-beat-aligned tempo metric at %1 = %2, adjust next beat using %3\n",
906 tempo->start(), current_frame, tempo->bar_offset()));
908 /* back up to previous beat */
909 current_frame -= beat_frames;
910 /* set tempo section location based on offset from last beat */
911 tempo->set_frame (current_frame + (ts->bar_offset() * beat_frames));
912 /* advance to the location of the new (adjusted) beat */
913 current_frame += (ts->bar_offset() * beat_frames) + ((1.0 - ts->bar_offset()) * next_beat_frames);
914 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Adjusted last beat to %1\n", current_frame));
917 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into beat-aligned tempo metric at %1 = %2\n",
918 tempo->start(), current_frame));
919 tempo->set_frame (current_frame);
922 } else if ((ms = dynamic_cast<MeterSection*>(*next_metric)) != 0) {
926 /* new meter section: always defines the
930 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("bumped into meter section at %1 (%2)\n",
931 meter->start(), current_frame));
933 assert (current.beats == 1);
935 meter->set_frame (current_frame);
938 divisions_per_bar = meter->divisions_per_bar ();
939 frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate);
940 beat_frames = meter->frames_per_division (*tempo, _frame_rate);
942 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("New metric with beat frames = %1 dpb %2 meter %3 tempo %4\n",
943 beat_frames, divisions_per_bar, *((Meter*)meter), *((Tempo*)tempo)));
949 if (current.beats == 1) {
950 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Bar at %1|1 @ %2\n", current.bars, current_frame));
951 _map.push_back (BBTPoint (*meter, *tempo,(framepos_t) llrint(current_frame), Bar, current.bars, 1));
953 DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add Beat at %1|%2 @ %3\n", current.bars, current.beats, current_frame));
954 _map.push_back (BBTPoint (*meter, *tempo, (framepos_t) llrint(current_frame), Beat, current.bars, current.beats));
960 TempoMap::metric_at (framepos_t frame) const
962 Glib::RWLock::ReaderLock lm (lock);
963 TempoMetric m (first_meter(), first_tempo());
967 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
968 at something, because we insert the default tempo and meter during
969 TempoMap construction.
971 now see if we can find better candidates.
974 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
976 // cerr << "Looking at a metric section " << **i << endl;
978 if ((*i)->frame() > frame) {
982 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
983 m.set_tempo (*tempo);
984 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
985 m.set_meter (*meter);
988 m.set_frame ((*i)->frame ());
989 m.set_start ((*i)->start ());
992 // cerr << "for framepos " << frame << " returning " << m.meter() << " @ " << m.tempo() << " location " << m.frame() << " = " << m.start() << endl;
997 TempoMap::metric_at (BBT_Time bbt) const
999 Glib::RWLock::ReaderLock lm (lock);
1000 TempoMetric m (first_meter(), first_tempo());
1004 /* at this point, we are *guaranteed* to have m.meter and m.tempo pointing
1005 at something, because we insert the default tempo and meter during
1006 TempoMap construction.
1008 now see if we can find better candidates.
1011 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1013 BBT_Time section_start ((*i)->start());
1015 if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) {
1019 if ((tempo = dynamic_cast<const TempoSection*>(*i)) != 0) {
1020 m.set_tempo (*tempo);
1021 } else if ((meter = dynamic_cast<const MeterSection*>(*i)) != 0) {
1022 m.set_meter (*meter);
1025 m.set_frame ((*i)->frame ());
1026 m.set_start (section_start);
1033 TempoMap::bbt_time (framepos_t frame, BBT_Time& bbt)
1036 Glib::RWLock::ReaderLock lm (lock);
1037 bbt_time_unlocked (frame, bbt);
1042 TempoMap::bbt_time_unlocked (framepos_t frame, BBT_Time& bbt)
1044 BBTPointList::const_iterator i = bbt_before_or_at (frame);
1046 bbt.bars = (*i).bar;
1047 bbt.beats = (*i).beat;
1049 if ((*i).frame == frame) {
1052 bbt.ticks = llrint (((frame - (*i).frame) / (*i).meter->frames_per_division(*((*i).tempo), _frame_rate)) /
1053 BBT_Time::ticks_per_bar_division);
1058 TempoMap::frame_time (const BBT_Time& bbt)
1060 Glib::RWLock::ReaderLock lm (lock);
1062 BBTPointList::const_iterator s = bbt_point_for (BBT_Time (1, 1, 0));
1063 BBTPointList::const_iterator e = bbt_point_for (BBT_Time (bbt.bars, bbt.beats, 0));
1065 if (bbt.ticks != 0) {
1066 return ((*e).frame - (*s).frame) +
1067 llrint ((*e).meter->frames_per_division (*(*e).tempo, _frame_rate) * (bbt.ticks/BBT_Time::ticks_per_bar_division));
1069 return ((*e).frame - (*s).frame);
1074 TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
1076 Glib::RWLock::ReaderLock lm (lock);
1077 framecnt_t frames = 0;
1080 bbt_time (pos, when);
1081 frames = bbt_duration_at_unlocked (when, bbt,dir);
1087 TempoMap::bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir)
1089 if (bbt.bars == 0 && bbt.beats == 0 && bbt.ticks == 0) {
1093 /* round back to the previous precise beat */
1094 BBTPointList::const_iterator wi = bbt_point_for (BBT_Time (when.bars, when.beats, 0));
1095 BBTPointList::const_iterator start (wi);
1096 double tick_frames = 0;
1098 assert (wi != _map.end());
1100 /* compute how much rounding we did because of non-zero ticks */
1102 if (when.ticks != 0) {
1103 tick_frames = (*wi).meter->frames_per_division (*(*wi).tempo, _frame_rate) * (when.ticks/BBT_Time::ticks_per_bar_division);
1109 while (wi != _map.end() && bars < bbt.bars) {
1111 if ((*wi).type == Bar) {
1115 assert (wi != _map.end());
1117 while (wi != _map.end() && beats < bbt.beats) {
1121 assert (wi != _map.end());
1123 /* add any additional frames related to ticks in the added value */
1125 if (bbt.ticks != 0) {
1126 tick_frames += (*wi).meter->frames_per_division (*(*wi).tempo, _frame_rate) * (bbt.ticks/BBT_Time::ticks_per_bar_division);
1129 return ((*wi).frame - (*start).frame) + llrint (tick_frames);
1133 TempoMap::round_to_bar (framepos_t fr, int dir)
1136 Glib::RWLock::ReaderLock lm (lock);
1137 return round_to_type (fr, dir, Bar);
1142 TempoMap::round_to_beat (framepos_t fr, int dir)
1145 Glib::RWLock::ReaderLock lm (lock);
1146 return round_to_type (fr, dir, Beat);
1151 TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, int dir)
1154 uint32_t ticks_one_half_subdivisions_worth;
1155 uint32_t ticks_one_subdivisions_worth;
1156 uint32_t difference;
1158 bbt_time(fr, the_beat);
1160 ticks_one_subdivisions_worth = (uint32_t)BBT_Time::ticks_per_bar_division / sub_num;
1161 ticks_one_half_subdivisions_worth = ticks_one_subdivisions_worth / 2;
1167 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1170 /* right on the subdivision, so the difference is just the subdivision ticks */
1171 difference = ticks_one_subdivisions_worth;
1174 /* not on subdivision, compute distance to next subdivision */
1176 difference = ticks_one_subdivisions_worth - mod;
1179 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1181 } else if (dir < 0) {
1183 /* round to previous */
1185 uint32_t mod = the_beat.ticks % ticks_one_subdivisions_worth;
1188 /* right on the subdivision, so the difference is just the subdivision ticks */
1189 difference = ticks_one_subdivisions_worth;
1191 /* not on subdivision, compute distance to previous subdivision, which
1192 is just the modulus.
1199 the_beat = bbt_subtract (the_beat, BBT_Time (0, 0, difference));
1201 /* can't go backwards from wherever pos is, so just return it */
1206 /* round to nearest */
1208 if (the_beat.ticks % ticks_one_subdivisions_worth > ticks_one_half_subdivisions_worth) {
1209 difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1210 the_beat = bbt_add (the_beat, BBT_Time (0, 0, difference));
1212 // difference = ticks_one_subdivisions_worth - (the_beat.ticks % ticks_one_subdivisions_worth);
1213 the_beat.ticks -= the_beat.ticks % ticks_one_subdivisions_worth;
1217 return frame_time (the_beat);
1221 TempoMap::round_to_type (framepos_t frame, int dir, BBTPointType type)
1223 BBTPointList::const_iterator fi;
1226 fi = bbt_after_or_at (frame);
1228 fi = bbt_before_or_at (frame);
1231 assert (fi != _map.end());
1233 DEBUG_TRACE(DEBUG::SnapBBT, string_compose ("round from %1 (%3|%4 @ %5) to bars in direction %2\n", frame, dir, (*fi).bar, (*fi).beat, (*fi).frame));
1238 /* find bar previous to 'frame' */
1240 if ((*fi).beat == 1 && (*fi).frame == frame) {
1244 while ((*fi).beat > 1) {
1245 if (fi == _map.begin()) {
1250 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to bar: map iter at %1|%2 %3, return\n",
1251 (*fi).bar, (*fi).beat, (*fi).frame));
1254 } else if (dir > 0) {
1256 /* find bar following 'frame' */
1258 if ((*fi).beat == 1 && (*fi).frame == frame) {
1262 while ((*fi).beat != 1) {
1264 if (fi == _map.end()) {
1270 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to bar: map iter at %1|%2 %3, return\n",
1271 (*fi).bar, (*fi).beat, (*fi).frame));
1276 /* true rounding: find nearest bar */
1278 BBTPointList::const_iterator prev = fi;
1279 BBTPointList::const_iterator next = fi;
1281 while ((*prev).beat != 1) {
1282 if (prev == _map.begin()) {
1288 while ((*next).beat != 1) {
1290 if (next == _map.end()) {
1296 if ((frame - (*prev).frame) < ((*next).frame - frame)) {
1297 return (*prev).frame;
1299 return (*next).frame;
1308 if ((*fi).frame >= frame) {
1309 DEBUG_TRACE (DEBUG::SnapBBT, "requested frame is on beat, step back\n");
1312 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to beat: map iter at %1|%2 %3, return\n",
1313 (*fi).bar, (*fi).beat, (*fi).frame));
1315 } else if (dir > 0) {
1316 if ((*fi).frame <= frame) {
1317 DEBUG_TRACE (DEBUG::SnapBBT, "requested frame is on beat, step forward\n");
1320 DEBUG_TRACE (DEBUG::SnapBBT, string_compose ("rounded to beat: map iter at %1|%2 %3, return\n",
1321 (*fi).bar, (*fi).beat, (*fi).frame));
1324 /* find beat nearest to frame */
1325 if ((*fi).frame == frame) {
1329 BBTPointList::const_iterator prev = fi;
1330 BBTPointList::const_iterator next = fi;
1334 if ((frame - (*prev).frame) < ((*next).frame - frame)) {
1335 return (*prev).frame;
1337 return (*next).frame;
1345 TempoMap::map (TempoMap::BBTPointList& points, framepos_t lower, framepos_t upper)
1347 if (_map.empty() || upper >= _map.back().frame) {
1348 recompute_map (false, upper);
1351 for (BBTPointList::const_iterator i = _map.begin(); i != _map.end(); ++i) {
1352 if ((*i).frame < lower) {
1355 if ((*i).frame >= upper) {
1358 points.push_back (*i);
1363 TempoMap::tempo_section_at (framepos_t frame) const
1365 Glib::RWLock::ReaderLock lm (lock);
1366 Metrics::const_iterator i;
1367 TempoSection* prev = 0;
1369 for (i = metrics->begin(); i != metrics->end(); ++i) {
1372 if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
1374 if ((*i)->frame() > frame) {
1390 TempoMap::tempo_at (framepos_t frame) const
1392 TempoMetric m (metric_at (frame));
1398 TempoMap::meter_at (framepos_t frame) const
1400 TempoMetric m (metric_at (frame));
1405 TempoMap::get_state ()
1407 Metrics::const_iterator i;
1408 XMLNode *root = new XMLNode ("TempoMap");
1411 Glib::RWLock::ReaderLock lm (lock);
1412 for (i = metrics->begin(); i != metrics->end(); ++i) {
1413 root->add_child_nocopy ((*i)->get_state());
1421 TempoMap::set_state (const XMLNode& node, int /*version*/)
1424 Glib::RWLock::WriterLock lm (lock);
1427 XMLNodeConstIterator niter;
1428 Metrics old_metrics (*metrics);
1429 MeterSection* last_meter = 0;
1433 nlist = node.children();
1435 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1436 XMLNode* child = *niter;
1438 if (child->name() == TempoSection::xml_state_node_name) {
1441 TempoSection* ts = new TempoSection (*child);
1442 metrics->push_back (ts);
1444 if (ts->bar_offset() < 0.0) {
1446 ts->update_bar_offset_from_bbt (*last_meter);
1451 catch (failed_constructor& err){
1452 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1453 *metrics = old_metrics;
1457 } else if (child->name() == MeterSection::xml_state_node_name) {
1460 MeterSection* ms = new MeterSection (*child);
1461 metrics->push_back (ms);
1465 catch (failed_constructor& err) {
1466 error << _("Tempo map: could not set new state, restoring old one.") << endmsg;
1467 *metrics = old_metrics;
1473 if (niter == nlist.end()) {
1475 MetricSectionSorter cmp;
1476 metrics->sort (cmp);
1477 recompute_map (true);
1481 PropertyChanged (PropertyChange ());
1487 TempoMap::dump (std::ostream& o) const
1489 const MeterSection* m;
1490 const TempoSection* t;
1492 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1494 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1495 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? "
1496 << t->movable() << ')' << endl;
1497 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1498 o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame()
1499 << " (movable? " << m->movable() << ')' << endl;
1505 TempoMap::n_tempos() const
1507 Glib::RWLock::ReaderLock lm (lock);
1510 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1511 if (dynamic_cast<const TempoSection*>(*i) != 0) {
1520 TempoMap::n_meters() const
1522 Glib::RWLock::ReaderLock lm (lock);
1525 for (Metrics::const_iterator i = metrics->begin(); i != metrics->end(); ++i) {
1526 if (dynamic_cast<const MeterSection*>(*i) != 0) {
1535 TempoMap::insert_time (framepos_t where, framecnt_t amount)
1537 for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) {
1538 if ((*i)->frame() >= where && (*i)->movable ()) {
1539 (*i)->set_frame ((*i)->frame() + amount);
1543 timestamp_metrics_from_audio_time ();
1545 PropertyChanged (PropertyChange ());
1549 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& other) const
1551 TempoMetric metric = metric_at (start);
1552 return bbt_add (start, other, metric);
1556 * add the BBT interval @param increment to @param start and return the result
1559 TempoMap::bbt_add (const BBT_Time& start, const BBT_Time& increment, const TempoMetric& /*metric*/) const
1561 BBT_Time result = start;
1562 BBT_Time op = increment; /* argument is const, but we need to modify it */
1563 uint32_t ticks = result.ticks + op.ticks;
1565 if (ticks >= BBT_Time::ticks_per_bar_division) {
1567 result.ticks = ticks % (uint32_t) BBT_Time::ticks_per_bar_division;
1569 result.ticks += op.ticks;
1572 /* now comes the complicated part. we have to add one beat a time,
1573 checking for a new metric on every beat.
1576 /* grab all meter sections */
1578 list<const MeterSection*> meter_sections;
1580 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1581 const MeterSection* ms;
1582 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1583 meter_sections.push_back (ms);
1587 assert (!meter_sections.empty());
1589 list<const MeterSection*>::const_iterator next_meter;
1590 const Meter* meter = 0;
1592 /* go forwards through the meter sections till we get to the one
1593 covering the current value of result. this positions i to point to
1594 the next meter section too, or the end.
1597 for (next_meter = meter_sections.begin(); next_meter != meter_sections.end(); ++next_meter) {
1599 if (result < (*next_meter)->start()) {
1600 /* this metric is past the result time. stop looking, we have what we need */
1604 if (result == (*next_meter)->start()) {
1605 /* this meter section starts at result, push i beyond it so that it points
1606 to the NEXT section, opwise we will get stuck later, and use this meter section.
1608 meter = *next_meter;
1613 meter = *next_meter;
1616 assert (meter != 0);
1618 /* OK, now have the meter for the bar start we are on, and i is an iterator
1619 that points to the metric after the one we are currently dealing with
1620 (or to metrics->end(), of course)
1625 /* given the current meter, have we gone past the end of the bar ? */
1627 if (result.beats >= meter->divisions_per_bar()) {
1628 /* move to next bar, first beat */
1639 /* check if we need to use a new meter section: has adding beats to result taken us
1640 to or after the start of the next meter section? in which case, use it.
1643 if (next_meter != meter_sections.end() && (((*next_meter)->start () < result) || (result == (*next_meter)->start()))) {
1644 meter = *next_meter;
1649 /* finally, add bars */
1651 result.bars += op.bars++;
1657 * subtract the BBT interval @param decrement from @param start and return the result
1660 TempoMap::bbt_subtract (const BBT_Time& start, const BBT_Time& decrement) const
1662 BBT_Time result = start;
1663 BBT_Time op = decrement; /* argument is const, but we need to modify it */
1665 if (op.ticks > result.ticks) {
1666 /* subtract an extra beat later; meanwhile set ticks to the right "carry" value */
1668 result.ticks = BBT_Time::ticks_per_bar_division - (op.ticks - result.ticks);
1670 result.ticks -= op.ticks;
1674 /* now comes the complicated part. we have to subtract one beat a time,
1675 checking for a new metric on every beat.
1678 /* grab all meter sections */
1680 list<const MeterSection*> meter_sections;
1682 for (Metrics::const_iterator x = metrics->begin(); x != metrics->end(); ++x) {
1683 const MeterSection* ms;
1684 if ((ms = dynamic_cast<const MeterSection*>(*x)) != 0) {
1685 meter_sections.push_back (ms);
1689 assert (!meter_sections.empty());
1691 /* go backwards through the meter sections till we get to the one
1692 covering the current value of result. this positions i to point to
1693 the next (previous) meter section too, or the end.
1696 const MeterSection* meter = 0;
1697 list<const MeterSection*>::reverse_iterator next_meter; // older versions of GCC don't
1698 // support const_reverse_iterator::operator!=()
1700 for (next_meter = meter_sections.rbegin(); next_meter != meter_sections.rend(); ++next_meter) {
1702 /* when we find the first meter section that is before or at result, use it,
1703 and set next_meter to the previous one
1706 if ((*next_meter)->start() < result || (*next_meter)->start() == result) {
1707 meter = *next_meter;
1713 assert (meter != 0);
1715 /* OK, now have the meter for the bar start we are on, and i is an iterator
1716 that points to the metric after the one we are currently dealing with
1717 (or to metrics->end(), of course)
1722 /* have we reached the start of the bar? if so, move to the last beat of the previous
1723 bar. opwise, just step back 1 beat.
1726 if (result.beats == 1) {
1728 /* move to previous bar, last beat */
1730 if (result.bars <= 1) {
1731 /* i'm sorry dave, i can't do that */
1732 throw std::out_of_range ("illegal BBT subtraction");
1736 result.beats = meter->divisions_per_bar();
1747 /* check if we need to use a new meter section: has subtracting beats to result taken us
1748 to before the start of the current meter section? in which case, use the prior one.
1751 if (result < meter->start() && next_meter != meter_sections.rend()) {
1752 meter = *next_meter;
1757 /* finally, subtract bars */
1759 if (op.bars >= result.bars) {
1760 /* i'm sorry dave, i can't do that */
1761 throw std::out_of_range ("illegal BBT subtraction");
1764 result.bars -= op.bars;
1768 /** Add some (fractional) beats to a session frame position, and return the result in frames.
1769 * pos can be -ve, if required.
1772 TempoMap::framepos_plus_beats (framepos_t pos, Evoral::MusicalTime beats)
1774 Metrics::const_iterator i;
1775 const TempoSection* tempo;
1777 /* Find the starting tempo */
1779 for (i = metrics->begin(); i != metrics->end(); ++i) {
1781 /* This is a bit of a hack, but pos could be -ve, and if it is,
1782 we consider the initial metric changes (at time 0) to actually
1783 be in effect at pos.
1785 framepos_t f = (*i)->frame ();
1786 if (pos < 0 && f == 0) {
1794 const TempoSection* t;
1796 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1803 tempo -> the Tempo for "pos"
1804 i -> for first new metric after "pos", possibly metrics->end()
1809 /* Distance to the end of this section in frames */
1810 framecnt_t distance_frames = i == metrics->end() ? max_framepos : ((*i)->frame() - pos);
1812 /* Distance to the end in beats */
1813 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
1815 /* Amount to subtract this time */
1816 double const sub = min (distance_beats, beats);
1820 pos += sub * tempo->frames_per_beat (_frame_rate);
1822 /* Move on if there's anything to move to */
1823 if (i != metrics->end ()) {
1824 const TempoSection* t;
1826 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1837 /** Subtract some (fractional) beats to a frame position, and return the result in frames */
1839 TempoMap::framepos_minus_beats (framepos_t pos, Evoral::MusicalTime beats)
1841 Metrics::const_iterator i;
1842 const TempoSection* tempo = 0;
1843 const TempoSection* t;
1845 /* Find the starting tempo */
1847 for (i = metrics->begin(); i != metrics->end(); ++i) {
1849 /* This is a bit of a hack, but pos could be -ve, and if it is,
1850 we consider the initial metric changes (at time 0) to actually
1851 be in effect at pos.
1853 framepos_t f = (*i)->frame ();
1854 if (pos < 0 && f == 0) {
1858 if ((*i)->frame() > pos) {
1862 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1867 bool no_more_tempos = false;
1869 /* Move i back to the tempo before "pos" */
1870 if (i != metrics->begin ()) {
1871 while (i != metrics->begin ()) {
1873 t = dynamic_cast<TempoSection*> (*i);
1879 no_more_tempos = true;
1884 tempo -> the Tempo for "pos"
1885 i -> the first metric before "pos", unless no_more_tempos is true
1890 /* Distance to the end of this section in frames */
1891 framecnt_t distance_frames = no_more_tempos ? max_framepos : (pos - (*i)->frame());
1893 /* Distance to the end in beats */
1894 Evoral::MusicalTime distance_beats = distance_frames / tempo->frames_per_beat (_frame_rate);
1896 /* Amount to subtract this time */
1897 double const sub = min (distance_beats, beats);
1901 pos -= sub * tempo->frames_per_beat (_frame_rate);
1903 /* Move i and tempo back, if there's anything to move to */
1904 if (i != metrics->begin ()) {
1905 while (i != metrics->begin ()) {
1907 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1913 no_more_tempos = true;
1920 /** Add the BBT interval op to pos and return the result */
1922 TempoMap::framepos_plus_bbt (framepos_t pos, BBT_Time op)
1924 Metrics::const_iterator i;
1925 const MeterSection* meter;
1926 const MeterSection* m;
1927 const TempoSection* tempo;
1928 const TempoSection* t;
1929 double frames_per_beat;
1931 meter = &first_meter ();
1932 tempo = &first_tempo ();
1937 /* find the starting metrics for tempo & meter */
1939 for (i = metrics->begin(); i != metrics->end(); ++i) {
1941 if ((*i)->frame() > pos) {
1945 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1947 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1954 meter -> the Meter for "pos"
1955 tempo -> the Tempo for "pos"
1956 i -> for first new metric after "pos", possibly metrics->end()
1959 /* now comes the complicated part. we have to add one beat a time,
1960 checking for a new metric on every beat.
1963 frames_per_beat = tempo->frames_per_beat (_frame_rate);
1972 /* check if we need to use a new metric section: has adding frames moved us
1973 to or after the start of the next metric section? in which case, use it.
1976 if (i != metrics->end()) {
1977 if ((*i)->frame() <= pos) {
1979 /* about to change tempo or meter, so add the
1980 * number of frames for the bars we've just
1981 * traversed before we change the
1982 * frames_per_beat value.
1985 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
1988 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
1990 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
1994 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2001 pos += llrint (frames_per_beat * (bars * meter->divisions_per_bar()));
2007 /* given the current meter, have we gone past the end of the bar ? */
2012 /* check if we need to use a new metric section: has adding frames moved us
2013 to or after the start of the next metric section? in which case, use it.
2016 if (i != metrics->end()) {
2017 if ((*i)->frame() <= pos) {
2019 /* about to change tempo or meter, so add the
2020 * number of frames for the beats we've just
2021 * traversed before we change the
2022 * frames_per_beat value.
2025 pos += llrint (beats * frames_per_beat);
2028 if ((t = dynamic_cast<const TempoSection*>(*i)) != 0) {
2030 } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) {
2034 frames_per_beat = tempo->frames_per_beat (_frame_rate);
2039 pos += llrint (beats * frames_per_beat);
2042 if (op.ticks >= BBT_Time::ticks_per_bar_division) {
2043 pos += llrint (frames_per_beat + /* extra beat */
2044 (frames_per_beat * ((op.ticks % (uint32_t) BBT_Time::ticks_per_bar_division) /
2045 (double) BBT_Time::ticks_per_bar_division)));
2047 pos += llrint (frames_per_beat * (op.ticks / (double) BBT_Time::ticks_per_bar_division));
2054 /** Count the number of beats that are equivalent to distance when going forward,
2058 TempoMap::framewalk_to_beats (framepos_t pos, framecnt_t distance)
2060 BBTPointList::const_iterator i = bbt_after_or_at (pos);
2061 Evoral::MusicalTime beats = 0;
2062 framepos_t end = pos + distance;
2064 require_map_to (end);
2066 /* if our starting BBTPoint is after pos, add a fractional beat
2067 to represent that distance.
2070 if ((*i).frame != pos) {
2071 beats += ((*i).frame - pos) / (*i).meter->frames_per_division (*(*i).tempo, _frame_rate);
2074 while (i != _map.end() && (*i).frame < end) {
2078 assert (i != _map.end());
2080 /* if our ending BBTPoint is after the end, subtract a fractional beat
2081 to represent that distance.
2084 if ((*i).frame > end) {
2085 beats -= ((*i).frame - end) / (*i).meter->frames_per_division (*(*i).tempo, _frame_rate);
2091 TempoMap::BBTPointList::const_iterator
2092 TempoMap::bbt_before_or_at (framepos_t pos)
2094 require_map_to (pos);
2095 BBTPointList::const_iterator i = lower_bound (_map.begin(), _map.end(), pos);
2096 assert (i != _map.end());
2100 TempoMap::BBTPointList::const_iterator
2101 TempoMap::bbt_after_or_at (framepos_t pos)
2103 require_map_to (pos);
2104 BBTPointList::const_iterator i = upper_bound (_map.begin(), _map.end(), pos);
2105 assert (i != _map.end());
2110 bool operator() (const BBT_Time& a, const BBT_Time& b) {
2115 TempoMap::BBTPointList::const_iterator
2116 TempoMap::bbt_point_for (const BBT_Time& bbt)
2119 int additional_minutes = 1;
2121 while (_map.empty() || _map.back().bar < (bbt.bars + 1)) {
2122 /* add some more distance, using bigger steps each time */
2123 require_map_to (_map.back().frame + (_frame_rate * 60 * additional_minutes));
2124 additional_minutes *= 2;
2127 BBTPointList::const_iterator i = lower_bound (_map.begin(), _map.end(), bbt, cmp);
2128 assert (i != _map.end());
2133 /** Compare the time of this with that of another MetricSection.
2134 * @param with_bbt True to compare using start(), false to use frame().
2135 * @return -1 for less than, 0 for equal, 1 for greater than.
2139 MetricSection::compare (const MetricSection& other) const
2141 if (start() == other.start()) {
2143 } else if (start() < other.start()) {
2154 MetricSection::operator== (const MetricSection& other) const
2156 return compare (other) == 0;
2160 MetricSection::operator!= (const MetricSection& other) const
2162 return compare (other) != 0;
2166 operator<< (std::ostream& o, const Meter& m) {
2167 return o << m.divisions_per_bar() << '/' << m.note_divisor();
2171 operator<< (std::ostream& o, const Tempo& t) {
2172 return o << t.beats_per_minute() << " 1/" << t.note_type() << "'s per minute";
2176 operator<< (std::ostream& o, const MetricSection& section) {
2178 o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' ';
2180 const TempoSection* ts;
2181 const MeterSection* ms;
2183 if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) {
2184 o << *((Tempo*) ts);
2185 } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) {
2186 o << *((Meter*) ms);