diff options
author | nick_m <mainsbridge@gmail.com> | 2015-12-28 05:33:04 +1100 |
---|---|---|
committer | nick_m <mainsbridge@gmail.com> | 2016-05-27 23:38:09 +1000 |
commit | 5c6e18e6a087823e4a3719177c92238b206e3aeb (patch) | |
tree | 25f7faefa65e630e68da70bf4378b825e7c29312 /libs | |
parent | 41c8b534b70e220b4d4b940aed8a98d9a57003ab (diff) |
Tempo ramps - remove the concept of bars from tempo sections.
- this helps where tempo and meter have a somewhat circular
dependency.
MetricSection now has a musical position expressed in beats (a double).
MeterSection still has a bbt, but it really isn't needed as we have
enough information to discover the number of bars at a given beat without it.
TempoSection now has a hack to enable loading of legacy sessions, which will
ultimately be a lot cleaner than the current code.
Removing bars from tempo sections also allows us to place them
at arbitrary frames (implemented here).
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/tempo.h | 77 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 664 | ||||
-rw-r--r-- | libs/ardour/test/bbt_test.cc | 2 | ||||
-rw-r--r-- | libs/ardour/test/framepos_minus_beats_test.cc | 18 | ||||
-rw-r--r-- | libs/ardour/test/framepos_plus_beats_test.cc | 18 | ||||
-rw-r--r-- | libs/ardour/test/framewalk_to_beats_test.cc | 18 | ||||
-rw-r--r-- | libs/ardour/test/midi_clock_slave_test.h | 4 | ||||
-rw-r--r-- | libs/ardour/test/tempo_test.cc | 8 |
8 files changed, 398 insertions, 411 deletions
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index e8f40e4236..f27622c91f 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -99,26 +99,24 @@ class LIBARDOUR_API Meter { /** A section of timeline with a certain Tempo or Meter. */ class LIBARDOUR_API MetricSection { public: - MetricSection (const Timecode::BBT_Time& start) - : _start (start), _frame (0), _movable (true), _position_lock_style (MusicTime) {} - MetricSection (framepos_t start) - : _frame (start), _movable (true), _position_lock_style (MusicTime) {} + MetricSection (double start) + : _beat (start), _frame (0), _movable (true), _position_lock_style (MusicTime) {} + MetricSection (framepos_t frame) + : _beat (0), _frame (frame), _movable (true), _position_lock_style (MusicTime) {} virtual ~MetricSection() {} + const double start () const { return _beat; } - const Timecode::BBT_Time& start() const { return _start; } - framepos_t frame() const { return _frame; } - - void set_movable (bool yn) { _movable = yn; } - bool movable() const { return _movable; } + const double& beat() const { return _beat; } + void set_beat (double beat) { _beat = beat;} + framepos_t frame() const { return _frame; } virtual void set_frame (framepos_t f) { _frame = f; } - virtual void set_start (const Timecode::BBT_Time& w) { - _start = w; - } + void set_movable (bool yn) { _movable = yn; } + bool movable() const { return _movable; } /* MeterSections are not stateful in the full sense, but we do want them to control their own @@ -129,8 +127,7 @@ class LIBARDOUR_API MetricSection { void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; } private: - - Timecode::BBT_Time _start; + double _beat; framepos_t _frame; bool _movable; PositionLockStyle _position_lock_style; @@ -139,15 +136,23 @@ private: /** A section of timeline with a certain Meter. */ class LIBARDOUR_API MeterSection : public MetricSection, public Meter { public: - MeterSection (const Timecode::BBT_Time& start, double bpb, double note_type) - : MetricSection (start), Meter (bpb, note_type) {} - MeterSection (framepos_t start, double bpb, double note_type) - : MetricSection (start), Meter (bpb, note_type) {} + MeterSection (double start, const Timecode::BBT_Time& bbt, double bpb, double note_type) + : MetricSection (start), Meter (bpb, note_type), _bbt (bbt) {} + MeterSection (framepos_t frame, double bpb, double note_type) + : MetricSection (frame), Meter (bpb, note_type) {} MeterSection (const XMLNode&); static const std::string xml_state_node_name; XMLNode& get_state() const; + + void set_start (std::pair<double, Timecode::BBT_Time>& w) { + set_beat (w.first); + _bbt = w.second; + } + const Timecode::BBT_Time& bbt() const { return _bbt; } +private: + Timecode::BBT_Time _bbt; }; /** A section of timeline with a certain Tempo. */ @@ -158,16 +163,20 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { Constant, }; - TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type, Type tempo_type) + TempoSection (const double& start, double qpm, double note_type, Type tempo_type) : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} - TempoSection (framepos_t start, double qpm, double note_type, Type tempo_type) - : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} + TempoSection (framepos_t frame, double qpm, double note_type, Type tempo_type) + : MetricSection (frame), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} TempoSection (const XMLNode&); static const std::string xml_state_node_name; XMLNode& get_state() const; + void set_start (const double& w) { + set_beat (w); + } + void update_bar_offset_from_bbt (const Meter&); void update_bbt_time_from_bar_offset (const Meter&); double bar_offset() const { return _bar_offset; } @@ -184,6 +193,8 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { double beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; framepos_t frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; + Timecode::BBT_Time legacy_bbt () { return _legacy_bbt; } + private: framecnt_t minute_to_frame (double time, framecnt_t frame_rate) const; @@ -217,6 +228,7 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { */ double _bar_offset; Type _type; + Timecode::BBT_Time _legacy_bbt; }; typedef std::list<MetricSection*> Metrics; @@ -232,7 +244,7 @@ class LIBARDOUR_API TempoMetric { void set_tempo (const Tempo& t) { _tempo = &t; } void set_meter (const Meter& m) { _meter = &m; } void set_frame (framepos_t f) { _frame = f; } - void set_start (const Timecode::BBT_Time& t) { _start = t; } + void set_start (const double& t) { _start = t; } void set_metric (const MetricSection* section) { const MeterSection* meter; @@ -250,13 +262,13 @@ class LIBARDOUR_API TempoMetric { const Meter& meter() const { return *_meter; } const Tempo& tempo() const { return *_tempo; } framepos_t frame() const { return _frame; } - const Timecode::BBT_Time& start() const { return _start; } + const double& start() const { return _start; } private: const Meter* _meter; const Tempo* _tempo; framepos_t _frame; - Timecode::BBT_Time _start; + double _start; }; /** Tempo Map - mapping of timecode to musical time. @@ -346,18 +358,17 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible const Meter& meter_at (framepos_t) const; const TempoSection& tempo_section_at (framepos_t) const; - TempoSection* tempo_section_after (framepos_t) const; const MeterSection& meter_section_at (framepos_t) const; - void add_tempo (const Tempo&, Timecode::BBT_Time where, TempoSection::Type type); - void add_meter (const Meter&, Timecode::BBT_Time where); + void add_tempo (const Tempo&, double where, TempoSection::Type type); + void add_meter (const Meter&, double start, Timecode::BBT_Time where); void remove_tempo (const TempoSection&, bool send_signal); void remove_meter (const MeterSection&, bool send_signal); - void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where, TempoSection::Type type); - void gui_set_tempo_frame (TempoSection&, framepos_t where); - void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where); + void replace_tempo (const TempoSection&, const Tempo&, const double& where, TempoSection::Type type); + void gui_set_tempo_frame (TempoSection&, framepos_t where, double beat); + void replace_meter (const MeterSection&, const Meter&, const double& start, const Timecode::BBT_Time& where); framepos_t round_to_bar (framepos_t frame, RoundMode dir); framepos_t round_to_beat (framepos_t frame, RoundMode dir); @@ -393,6 +404,8 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible PBD::Signal0<void> MetricPositionChanged; + double bbt_to_beats (Timecode::BBT_Time bbt); + private: friend class ::BBTTest; @@ -424,8 +437,8 @@ private: void do_insert (MetricSection* section); - void add_tempo_locked (const Tempo&, Timecode::BBT_Time where, bool recompute, TempoSection::Type type); - void add_meter_locked (const Meter&, Timecode::BBT_Time where, bool recompute); + void add_tempo_locked (const Tempo&, double where, bool recompute, TempoSection::Type type); + void add_meter_locked (const Meter&, double start, Timecode::BBT_Time where, bool recompute); bool remove_tempo_locked (const TempoSection&); bool remove_meter_locked (const MeterSection&); diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 8dd2e28073..ba4b40a17e 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -71,23 +71,26 @@ Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const const string TempoSection::xml_state_node_name = "Tempo"; TempoSection::TempoSection (const XMLNode& node) - : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo()) + : MetricSection (0.0), Tempo (TempoMap::default_tempo()) { const XMLProperty *prop; BBT_Time start; LocaleGuard lg; if ((prop = node.property ("start")) == 0) { - error << _("TempoSection XML node has no \"start\" property") << endmsg; + error << _("MeterSection XML node has no \"start\" property") << endmsg; throw failed_constructor(); } if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, - &start.bars, - &start.beats, - &start.ticks) < 3) { + &bbt.bars, + &bbt.beats, + &bbt.ticks) == 3) { + /* legacy session - start used to be in bbt*/ + _legacy_bbt = bbt; + start = -1.0; + } else if (sscanf (prop->value().c_str(), "%lf", &start) != 1 || start < 0.0) { error << _("TempoSection XML node has an illegal \"start\" value") << endmsg; - throw failed_constructor(); } set_start (start); @@ -146,10 +149,7 @@ TempoSection::get_state() const char buf[256]; LocaleGuard lg; - snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, - start().bars, - start().beats, - start().ticks); + snprintf (buf, sizeof (buf), "%f", beat()); root->add_property ("start", buf); snprintf (buf, sizeof (buf), "%f", _beats_per_minute); root->add_property ("beats-per-minute", buf); @@ -170,7 +170,7 @@ void TempoSection::update_bar_offset_from_bbt (const Meter& m) { - _bar_offset = ((start().beats - 1) * BBT_Time::ticks_per_beat + start().ticks) / + _bar_offset = (start() * BBT_Time::ticks_per_beat) / (m.divisions_per_bar() * BBT_Time::ticks_per_beat); DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Tempo set bar offset to %1 from %2 w/%3\n", _bar_offset, start(), m.divisions_per_bar())); @@ -316,24 +316,20 @@ TempoSection::time_at_beat (double beat, double end_tpm, double end_time) const void TempoSection::update_bbt_time_from_bar_offset (const Meter& meter) { - BBT_Time new_start; + double new_start; if (_bar_offset < 0.0) { /* not set yet */ return; } - new_start.bars = start().bars; + new_start = start(); double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset; - new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat); - //new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */ - new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); + new_start = ticks / BBT_Time::ticks_per_beat; - /* remember the 1-based counting properties of beats */ - new_start.beats += 1; DEBUG_TRACE (DEBUG::TempoMath, string_compose ("from bar offset %1 and dpb %2, ticks = %3->%4 beats = %5\n", - _bar_offset, meter.divisions_per_bar(), ticks, new_start.ticks, new_start.beats)); + _bar_offset, meter.divisions_per_bar(), ticks, new_start, new_start)); set_start (new_start); } @@ -343,24 +339,42 @@ TempoSection::update_bbt_time_from_bar_offset (const Meter& meter) const string MeterSection::xml_state_node_name = "Meter"; MeterSection::MeterSection (const XMLNode& node) - : MetricSection (BBT_Time()), Meter (TempoMap::default_meter()) + : MetricSection (0.0), Meter (TempoMap::default_meter()) { XMLProperty const * prop; BBT_Time start; LocaleGuard lg; + const XMLProperty *prop; + BBT_Time bbt; + double beat = 0.0; + pair<double, BBT_Time> start; if ((prop = node.property ("start")) == 0) { error << _("MeterSection XML node has no \"start\" property") << endmsg; throw failed_constructor(); } - if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, - &start.bars, - &start.beats, - &start.ticks) < 3) { + &bbt.bars, + &bbt.beats, + &bbt.ticks) == 3) { + /* legacy session - start used to be in bbt*/ + beat = -1.0; + } else if (sscanf (prop->value().c_str(), "%lf", &beat) != 1 || beat < 0.0) { error << _("MeterSection XML node has an illegal \"start\" value") << endmsg; throw failed_constructor(); } + start.first = beat; + + if ((prop = node.property ("bbt")) == 0) { + error << _("MeterSection XML node has no \"bbt\" property") << endmsg; + } else if (sscanf (prop->value().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, + &bbt.bars, + &bbt.beats, + &bbt.ticks) < 3) { + error << _("MeterSection XML node has an illegal \"bbt\" value") << endmsg; + throw failed_constructor(); + } + start.second = bbt; set_start (start); @@ -404,9 +418,11 @@ MeterSection::get_state() const LocaleGuard lg; snprintf (buf, sizeof (buf), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, - start().bars, - start().beats, - start().ticks); + bbt().bars, + bbt().beats, + bbt().ticks); + root->add_property ("bbt", buf); + snprintf (buf, sizeof (buf), "%f", start()); root->add_property ("start", buf); snprintf (buf, sizeof (buf), "%f", _note_type); root->add_property ("note-type", buf); @@ -441,8 +457,8 @@ TempoMap::TempoMap (framecnt_t fr) start.beats = 1; start.ticks = 0; - TempoSection *t = new TempoSection (start, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Type::Ramp); - MeterSection *m = new MeterSection (start, _default_meter.divisions_per_bar(), _default_meter.note_divisor()); + TempoSection *t = new TempoSection (0.0, _default_tempo.beats_per_minute(), _default_tempo.note_type(), TempoSection::Type::Ramp); + MeterSection *m = new MeterSection (0.0, start, _default_meter.divisions_per_bar(), _default_meter.note_divisor()); t->set_movable (false); m->set_movable (false); @@ -542,24 +558,24 @@ TempoMap::do_insert (MetricSection* section) /* we only allow new meters to be inserted on beat 1 of an existing * measure. */ - - if (dynamic_cast<MeterSection*>(section)) { - assert (section->start().ticks == 0); + MeterSection* m = 0; + if ((m = dynamic_cast<MeterSection*>(section)) != 0) { + assert (m->bbt().ticks == 0); /* we need to (potentially) update the BBT times of tempo sections based on this new meter. */ - if ((section->start().beats != 1) || (section->start().ticks != 0)) { + if ((m->bbt().beats != 1) || (m->bbt().ticks != 0)) { - BBT_Time corrected = section->start(); - corrected.beats = 1; - corrected.ticks = 0; + pair<double, BBT_Time> corrected = make_pair (m->start(), m->bbt()); + corrected.second.beats = 1; + corrected.second.ticks = 0; warning << string_compose (_("Meter changes can only be positioned on the first beat of a bar. Moving from %1 to %2"), - section->start(), corrected) << endmsg; + m->bbt(), corrected.second) << endmsg; - section->set_start (corrected); + m->set_start (corrected); } } @@ -574,24 +590,23 @@ TempoMap::do_insert (MetricSection* section) for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) { - bool const iter_is_tempo = dynamic_cast<TempoSection*> (*i) != 0; - bool const insert_is_tempo = dynamic_cast<TempoSection*> (section) != 0; + TempoSection* const tempo = dynamic_cast<TempoSection*> (*i); + TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section); - if (iter_is_tempo && insert_is_tempo) { + if (tempo && insert_tempo) { /* Tempo sections */ - if ((*i)->start().bars == section->start().bars && - (*i)->start().beats == section->start().beats) { + if (tempo->start() == insert_tempo->start()) { - if (!(*i)->movable()) { + if (!tempo->movable()) { /* can't (re)move this section, so overwrite * its data content (but not its properties as * a section). */ - *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(section)); + *(dynamic_cast<Tempo*>(*i)) = *(dynamic_cast<Tempo*>(insert_tempo)); need_add = false; } else { metrics.erase (i); @@ -599,11 +614,12 @@ TempoMap::do_insert (MetricSection* section) break; } - } else if (!iter_is_tempo && !insert_is_tempo) { + } else if (!tempo && !insert_tempo) { /* Meter Sections */ - - if ((*i)->start().bars == section->start().bars) { + MeterSection* const meter = dynamic_cast<MeterSection*> (*i); + MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section); + if (meter->start() == insert_meter->start()) { if (!(*i)->movable()) { @@ -612,7 +628,7 @@ TempoMap::do_insert (MetricSection* section) * a section */ - *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(section)); + *(dynamic_cast<Meter*>(*i)) = *(dynamic_cast<Meter*>(insert_meter)); need_add = false; } else { metrics.erase (i); @@ -631,12 +647,27 @@ TempoMap::do_insert (MetricSection* section) */ if (need_add) { + MeterSection* const insert_meter = dynamic_cast<MeterSection*> (section); + TempoSection* const insert_tempo = dynamic_cast<TempoSection*> (section); Metrics::iterator i; + if (insert_meter) { + for (i = metrics.begin(); i != metrics.end(); ++i) { + MeterSection* const meter = dynamic_cast<MeterSection*> (*i); - for (i = metrics.begin(); i != metrics.end(); ++i) { - if ((*i)->start() > section->start()) { - break; + if (meter && meter->start() > insert_meter->start()) { + break; + } + } + } else if (insert_tempo) { + for (i = metrics.begin(); i != metrics.end(); ++i) { + TempoSection* const tempo = dynamic_cast<TempoSection*> (*i); + + if (tempo) { + if (tempo->start() > insert_tempo->start()) { + break; + } + } } } @@ -645,7 +676,7 @@ TempoMap::do_insert (MetricSection* section) } void -TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_Time& where, TempoSection::Type type) +TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const double& where, TempoSection::Type type) { { Glib::Threads::RWLock::WriterLock lm (lock); @@ -668,15 +699,21 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T } void -TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame) -{ - { - TempoSection& first (first_tempo()); - if (ts.frame() != first.frame()) { - BBT_Time bbt; - { - Glib::Threads::RWLock::WriterLock lm (lock); - +TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame, double beat_where) +{ + TempoSection& first (first_tempo()); + if (ts.frame() != first.frame()) { + { + Glib::Threads::RWLock::WriterLock lm (lock); + /* currently this is always done in audio time */ + if (0) { + //if (ts.position_lock_style() == AudioTime) { + /* MusicTime */ + ts.set_start (beat_where); + MetricSectionSorter cmp; + metrics.sort (cmp); + } else { + /*AudioTime*/ ts.set_frame (frame); MetricSectionFrameSorter fcmp; @@ -684,64 +721,60 @@ TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame) Metrics::const_iterator i; TempoSection* prev_ts = 0; - MeterSection* meter = 0; + TempoSection* next_ts = 0; for (i = metrics.begin(); i != metrics.end(); ++i) { TempoSection* t; - MeterSection* m; - if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { - if ((*i)->frame() > frame - 1) { + if (t->frame() >= frame) { break; } prev_ts = t; } + } - if ((m = dynamic_cast<MeterSection*> (*i)) != 0) { + for (i = metrics.begin(); i != metrics.end(); ++i) { + TempoSection* t; + if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { - if ((*i)->frame() > frame) { + if (t->frame() > frame) { + next_ts = t; break; } - - meter = m; } } - if (prev_ts && meter) { - - /* set the start bbt */ - double const ticks_to_ts = prev_ts->tick_at_frame (frame - prev_ts->frame(), ts.beats_per_minute(), frame - prev_ts->frame(), _frame_rate); - double beats = ticks_to_ts / BBT_Time::ticks_per_beat; - Timecode::BBT_Time bbt; - - bbt.bars = (uint32_t) floor (beats / meter->divisions_per_bar()); - beats -= bbt.bars * meter->divisions_per_bar(); - bbt.beats = (uint32_t) floor (beats); - beats -= bbt.beats; - bbt.ticks = (uint32_t) floor (beats * BBT_Time::ticks_per_beat); - - /* now add the prev ts bbt */ - bbt.bars += prev_ts->start().bars; - bbt.beats += prev_ts->start().beats; - - if (bbt.beats > meter->divisions_per_bar()) { - ++bbt.bars; - bbt.beats -= meter->divisions_per_bar(); - } - bbt.ticks += prev_ts->start().ticks; - if (bbt.ticks > BBT_Time::ticks_per_beat) { - ++bbt.beats; - bbt.ticks -= BBT_Time::ticks_per_beat; + if (prev_ts) { + /* set the start beat */ + double beats_to_ts = prev_ts->beat_at_frame (frame - prev_ts->frame(), ts.beats_per_minute(), frame - prev_ts->frame(), _frame_rate); + double beats = beats_to_ts + prev_ts->start(); + + if (next_ts) { + if (next_ts->start() < beats) { + /* with frame-based editing, it is possible to get in a + situation where if the tempo was placed at the mouse pointer frame, + the following music-based tempo would jump to an earlier frame, + changing the start beat of the moved tempo. + in this case, we have to do some beat-based comparison TODO + */ + + ts.set_start (next_ts->start()); + } else if (prev_ts->start() > beats) { + ts.set_start (prev_ts->start()); + } else { + ts.set_start (beats); + } + } else { + ts.set_start (beats); } - ts.set_start (bbt); + MetricSectionSorter cmp; + metrics.sort (cmp); } - - MetricSectionSorter cmp; - metrics.sort (cmp); - recompute_map (false); } + + recompute_map (false); } } @@ -749,7 +782,7 @@ TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame) } void -TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type) +TempoMap::add_tempo (const Tempo& tempo, double where, ARDOUR::TempoSection::Type type) { { Glib::Threads::RWLock::WriterLock lm (lock); @@ -761,40 +794,10 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::T } void -TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, ARDOUR::TempoSection::Type type) +TempoMap::add_tempo_locked (const Tempo& tempo, double where, bool recompute, ARDOUR::TempoSection::Type type) { TempoSection* ts = new TempoSection (where, tempo.beats_per_minute(), tempo.note_type(), type); - /* find the meter to use to set the bar offset of this - * tempo section. - */ - - const Meter* meter = &first_meter(); - - /* as we start, we are *guaranteed* to have m.meter and m.tempo pointing - at something, because we insert the default tempo and meter during - TempoMap construction. - - now see if we can find better candidates. - */ - - for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) { - - const MeterSection* m; - - if (where < (*i)->start()) { - break; - } - - if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { - meter = m; - } - } - - //ts->update_bar_offset_from_bbt (*meter); - - /* and insert it */ - do_insert (ts); if (recompute) { @@ -803,15 +806,14 @@ TempoMap::add_tempo_locked (const Tempo& tempo, BBT_Time where, bool recompute, } void -TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_Time& where) +TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const double& start, const BBT_Time& where) { { Glib::Threads::RWLock::WriterLock lm (lock); MeterSection& first (first_meter()); - if (ms.start() != first.start()) { remove_meter_locked (ms); - add_meter_locked (meter, where, true); + add_meter_locked (meter, start, where, true); } else { /* cannot move the first meter section */ *static_cast<Meter*>(&first) = meter; @@ -823,11 +825,11 @@ TempoMap::replace_meter (const MeterSection& ms, const Meter& meter, const BBT_T } void -TempoMap::add_meter (const Meter& meter, BBT_Time where) +TempoMap::add_meter (const Meter& meter, double start, BBT_Time where) { { Glib::Threads::RWLock::WriterLock lm (lock); - add_meter_locked (meter, where, true); + add_meter_locked (meter, start, where, true); } @@ -841,7 +843,7 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where) } void -TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute) +TempoMap::add_meter_locked (const Meter& meter, double start, BBT_Time where, bool recompute) { /* a new meter always starts a new bar on the first beat. so round the start time appropriately. remember that @@ -858,7 +860,7 @@ TempoMap::add_meter_locked (const Meter& meter, BBT_Time where, bool recompute) /* new meters *always* start on a beat. */ where.ticks = 0; - do_insert (new MeterSection (where, meter.divisions_per_bar(), meter.note_divisor())); + do_insert (new MeterSection (start, where, meter.divisions_per_bar(), meter.note_divisor())); if (recompute) { recompute_map (true); @@ -1055,33 +1057,6 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end) current.bars = 1; current.beats = 1; current.ticks = 0; - if (reassign_tempo_bbt) { - - MeterSection* rmeter = meter; - - DEBUG_TRACE (DEBUG::TempoMath, "\tUpdating tempo marks BBT time from bar offset\n"); - - for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) { - - TempoSection* ts; - MeterSection* ms; - - if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) { - - /* reassign the BBT time of this tempo section - * based on its bar offset position. - */ - - //ts->update_bbt_time_from_bar_offset (*rmeter); - - } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) { - rmeter = ms; - } else { - fatal << _("programming error: unhandled MetricSection type") << endmsg; - abort(); /*NOTREACHED*/ - } - } - } DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo))); @@ -1107,7 +1082,6 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter, { /* CALLER MUST HOLD WRITE LOCK */ - uint32_t first_tick_in_new_meter = 0; Metrics::const_iterator i; Metrics::const_iterator mi; @@ -1119,78 +1093,43 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter, if ((m = dynamic_cast<MeterSection*> (*mi)) != 0) { if (m->start() >= prev_ts->start()) { - first_tick_in_new_meter = ((((m->start().bars - 1) * meter->divisions_per_bar()) + (m->start().beats - 1)) * BBT_Time::ticks_per_beat) + m->start().ticks; // expressed in ticks from the previous meter for (i = metrics.begin(); i != metrics.end(); ++i) { TempoSection* t; if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { - if (t->position_lock_style() == AudioTime) { - /* set the start bbt */ - double const ticks_at_ts = prev_ts->tick_at_frame (t->frame(), t->beats_per_minute(), t->frame(), _frame_rate); - double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1)) * BBT_Time::ticks_per_beat) + prev_ts->start().ticks; - - double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts; - double beats = ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat; - - Timecode::BBT_Time bbt; - bbt.bars = (uint32_t) floor (beats / meter->divisions_per_bar()); - beats -= bbt.bars * meter->divisions_per_bar(); - bbt.beats = (uint32_t) floor (beats); - beats -= bbt.beats; - bbt.ticks = (uint32_t) floor (beats * BBT_Time::ticks_per_beat); - /* now add the prev ts bbt */ - bbt.bars += prev_ts->start().bars; - bbt.beats += prev_ts->start().beats; - - if (bbt.beats > meter->divisions_per_bar()) { - ++bbt.bars; - bbt.beats -= meter->divisions_per_bar(); - } - bbt.ticks += prev_ts->start().ticks; - if (bbt.ticks > BBT_Time::ticks_per_beat) { - ++bbt.beats; - bbt.ticks -= BBT_Time::ticks_per_beat; - } - t->set_start (bbt); - - if (m->start() < t->start() && m->start() == prev_ts->start()) { - m->set_frame (prev_ts->frame()); - } else if (m->start() < t->start() && m->start() > prev_ts->start()) { - m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), t->frame(), _frame_rate) + prev_ts->frame()); - } - - } else if (t->start() >= m->start() && t->start() > prev_ts->start()) { - //cerr << "new ts start bars = " << t->start().bars << " beats = " << t->start().beats << " ticks = " << t->start().ticks << endl; - //cerr << "prev ts start bars = " << prev_ts->start().bars << " beats = " << prev_ts->start().beats << " ticks = " << prev_ts->start().ticks << endl; + if (t->start() >= m->start() && t->start() > prev_ts->start()) { /*tempo section (t) lies in the previous meter */ - double const ticks_at_ts = ((((t->start().bars - 1 ) * meter->divisions_per_bar()) + (t->start().beats - 1) ) * BBT_Time::ticks_per_beat) + t->start().ticks; - double const ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1)) * BBT_Time::ticks_per_beat) + prev_ts->start().ticks; - double const ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts; + double const beats_relative_to_prev_ts = t->start() - prev_ts->start(); + double const ticks_relative_to_prev_ts = beats_relative_to_prev_ts * BBT_Time::ticks_per_beat; + /* assume (falsely) that the target tempo is constant */ - double length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate); + double const t_fpb = t->frames_per_beat (_frame_rate); + double const av_fpb = (prev_ts->frames_per_beat (_frame_rate) + t_fpb) / 2.0; + + double length_estimate = beats_relative_to_prev_ts * av_fpb; + if (prev_ts->type() == TempoSection::Type::Constant) { - length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate); + length_estimate = beats_relative_to_prev_ts * prev_ts->frames_per_beat (_frame_rate); } - cerr<< "initial length extimate = " << length_estimate << " ticks_relative_to_prev_ts " << ticks_relative_to_prev_ts << endl; - double const system_precision_at_target_tempo = (_frame_rate / t->ticks_per_minute()); - cerr << " system_precision_at_target_tempo = " << system_precision_at_target_tempo << endl; + + double const system_precision_at_target_tempo = (_frame_rate / t->ticks_per_minute()) * 1.5; double tick_error = system_precision_at_target_tempo + 1.0; // sorry for the wtf - while (fabs (tick_error) >= system_precision_at_target_tempo) { + while (fabs (tick_error) > system_precision_at_target_tempo) { double const actual_ticks = prev_ts->tick_at_frame (length_estimate, t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate); tick_error = ticks_relative_to_prev_ts - actual_ticks; - length_estimate += (tick_error / BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate); + length_estimate += tick_error * (t->ticks_per_minute() / _frame_rate); } + t->set_frame (length_estimate + prev_ts->frame()); - if (m->start() < t->start() && m->start() == prev_ts->start()) { + double const meter_start_beats = m->start(); + if (meter_start_beats < t->start() && meter_start_beats == prev_ts->start()) { m->set_frame (prev_ts->frame()); - } else if (m->start() < t->start() && m->start() > prev_ts->start()) { - cerr << "recompute map - music lock style setting meter frame to " << prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) << " ticks = " << first_tick_in_new_meter - ticks_at_prev_ts << endl; - - m->set_frame (prev_ts->frame_at_tick ((first_tick_in_new_meter - ticks_at_prev_ts), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) + prev_ts->frame()); + } else if (meter_start_beats < t->start() && meter_start_beats > prev_ts->start()) { + m->set_frame (prev_ts->frame_at_tick (((m->start() * BBT_Time::ticks_per_beat) - (prev_ts->start() * BBT_Time::ticks_per_beat)), t->beats_per_minute(), (framepos_t) length_estimate, _frame_rate) + prev_ts->frame()); } } prev_ts = t; @@ -1231,7 +1170,7 @@ TempoMap::metric_at (framepos_t frame, Metrics::const_iterator* last) const return m; } - +/* XX meters only */ TempoMetric TempoMap::metric_at (BBT_Time bbt) const { @@ -1246,14 +1185,16 @@ TempoMap::metric_at (BBT_Time bbt) const */ for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) { + MeterSection* mw; + if ((mw = dynamic_cast<MeterSection*> (*i)) != 0) { + BBT_Time section_start (mw->bbt()); - BBT_Time section_start ((*i)->start()); + if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) { + break; + } - if (section_start.bars > bbt.bars || (section_start.bars == bbt.bars && section_start.beats > bbt.beats)) { - break; + m.set_metric (*i); } - - m.set_metric (*i); } return m; @@ -1303,15 +1244,46 @@ TempoMap::bars_in_meter_section (MeterSection* ms) const return -1; } +double +TempoMap::bbt_to_beats (Timecode::BBT_Time bbt) +{ + double accumulated_ticks = 0.0; + MeterSection* prev_ms = 0; + Metrics::const_iterator i; + + for (i = metrics.begin(); i != metrics.end(); ++i) { + MeterSection* m; + if ((m = dynamic_cast<MeterSection*> (*i)) != 0) { + + if (m->bbt() > bbt) { + break; + } + if (prev_ms) { + accumulated_ticks += (m->bbt().bars - prev_ms->bbt().bars) * prev_ms->divisions_per_bar() * BBT_Time::ticks_per_beat; + } + prev_ms = m; + + } + + } + double const remaining_ticks_in_bbt = ((bbt.bars - prev_ms->bbt().bars) * prev_ms->divisions_per_bar() * BBT_Time::ticks_per_beat) + + ((bbt.beats - prev_ms->bbt().beats) * BBT_Time::ticks_per_beat) + + (bbt.ticks - prev_ms->bbt().ticks); + double const total_ticks = remaining_ticks_in_bbt + accumulated_ticks; + + return total_ticks / BBT_Time::ticks_per_beat; +} + Timecode::BBT_Time TempoMap::beats_to_bbt (double beats) { /* CALLER HOLDS READ LOCK */ - BBT_Time ret; MeterSection* prev_ms = &first_meter(); - framecnt_t frame = frame_at_beat (beats); + //framecnt_t frame = frame_at_beat (beats); uint32_t cnt = 0; + BBT_Time ret; + /* XX most of this is utter crap */ if (n_meters() == 1) { uint32_t bars = (uint32_t) floor (beats / prev_ms->note_divisor()); @@ -1339,87 +1311,58 @@ TempoMap::beats_to_bbt (double beats) return ret; } - uint32_t first_beat_in_meter = 0; uint32_t accumulated_bars = 0; + double accumulated_beats = 0; + Metrics::const_iterator i; for (i = metrics.begin(); i != metrics.end(); ++i) { MeterSection* m = 0; if ((m = dynamic_cast<MeterSection*> (*i)) != 0) { - first_beat_in_meter = beat_at_frame (m->frame()); - if (beats < first_beat_in_meter) { + if (beats < ((m->bbt().bars - prev_ms->bbt().bars) * prev_ms->divisions_per_bar()) + accumulated_beats) { /* this is the meter after the one our beat is on*/ break; } - int32_t const bars_in_ms = bars_in_meter_section (m); - if (bars_in_ms > 0) { - accumulated_bars += bars_in_ms; + if (prev_ms) { + accumulated_bars += m->bbt().bars - prev_ms->bbt().bars; + accumulated_beats += (m->bbt().bars - prev_ms->bbt().bars) * prev_ms->divisions_per_bar(); } prev_ms = m; ++cnt; } } - //cerr << "beats to bbr with beats = " << beats << " first_beat_in_meter = " << first_beat_in_meter << " accumulated_bars = " << accumulated_bars << endl; - - if (beats > first_beat_in_meter) { - /* prev_ms is the relevant one here */ - - /* now get the ticks at frame */ - double ticks_at_frame = tick_at_frame (frame); - - /* find the number of ticks at the beginning of the meter section (bar 1)*/ - double ticks_at_ms = tick_at_frame (prev_ms->frame()); - - double beats_used_by_ms = (ticks_at_frame - ticks_at_ms) / BBT_Time::ticks_per_beat; - - uint32_t bars = (uint32_t) floor (beats_used_by_ms / prev_ms->note_divisor()); - double remaining_beats = beats_used_by_ms - (bars * prev_ms->note_divisor()); - double remaining_ticks = (remaining_beats - floor (remaining_beats)) * BBT_Time::ticks_per_beat; - ret.bars = bars + accumulated_bars; - ret.beats = (uint32_t) floor (remaining_beats); - ret.ticks = (uint32_t) floor (remaining_ticks + 0.5); + /* now find all tempo sections between prev_ms and beat */ + TempoSection* prev_ts = &first_tempo(); - /* now ensure we srtart at 1 1 0 */ - ++ret.bars; - ++ret.beats; - //cerr << "part 1 ret bars = " << ret.bars << " ret beats = " << ret.beats << " ret ticks = " << ret.ticks << endl; - if (ret.ticks >= BBT_Time::ticks_per_beat) { - ++ret.beats; - ret.ticks -= BBT_Time::ticks_per_beat; - } + for (i = metrics.begin(); i != metrics.end(); ++i) { + TempoSection* t; - if (ret.beats > prev_ms->note_divisor()) { - ++ret.bars; - ret.beats = 1; + if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + if (beats < t->start()) { + break; + } + prev_ts = t; } - - return ret; } - /* find the number of ticks at the beginning of the meter section (bar 1)*/ - double ticks_at_ms = tick_at_frame (prev_ms->frame()); - - /* now get the ticks at frame */ - double ticks_at_frame = tick_at_frame (frame); + double beats_in_ts = beats - prev_ts->start(); + uint32_t bars_in_prev_ts = (uint32_t) floor (beats_in_ts / prev_ms->note_divisor()); + uint32_t beats_after_prev_ts_bar = (uint32_t) floor (beats_in_ts - (bars_in_prev_ts * prev_ms->note_divisor())); + double remaining_ticks = (beats_in_ts - (bars_in_prev_ts * prev_ms->note_divisor()) + beats_after_prev_ts_bar) * BBT_Time::ticks_per_beat; - double ticks_within_ms = ticks_at_frame - ticks_at_ms; - - ret.bars = (uint32_t) floor (((ticks_within_ms / BBT_Time::ticks_per_beat) / prev_ms->note_divisor())) + accumulated_bars; - uint32_t remaining_ticks = ticks_within_ms - (ret.bars * prev_ms->note_divisor() * BBT_Time::ticks_per_beat); - ret.beats = (uint32_t) floor (remaining_ticks); - remaining_ticks -= ret.beats * BBT_Time::ticks_per_beat; - - /* only round ticks */ ret.ticks = (uint32_t) floor (remaining_ticks + 0.5); + ret.beats = beats_after_prev_ts_bar; + ret.bars = bars_in_prev_ts + accumulated_bars; - /* now ensure we srtart at 1 1 0 */ + /* 0 0 0 to 1 1 0 - based mapping*/ ++ret.bars; ++ret.beats; + if (ret.ticks >= BBT_Time::ticks_per_beat) { ++ret.beats; ret.ticks -= BBT_Time::ticks_per_beat; @@ -1841,30 +1784,6 @@ TempoMap::get_grid (vector<TempoMap::BBTPoint>& points, } } -TempoSection* -TempoMap::tempo_section_after (framepos_t frame) const -{ - Glib::Threads::RWLock::ReaderLock lm (lock); - - Metrics::const_iterator i; - TempoSection* next = 0; - - for (i = metrics.begin(); i != metrics.end(); ++i) { - TempoSection* t; - - if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { - - if ((*i)->frame() > frame) { - next = t; - break; - } - } - } - - return next; -} - - const TempoSection& TempoMap::tempo_section_at (framepos_t frame) const { @@ -1903,7 +1822,20 @@ TempoMap::frames_per_beat_at (framepos_t frame, framecnt_t sr) const Glib::Threads::RWLock::ReaderLock lm (lock); const TempoSection* ts_at = &tempo_section_at (frame); - const TempoSection* ts_after = tempo_section_after (frame); + const TempoSection* ts_after = 0; + Metrics::const_iterator i; + + for (i = metrics.begin(); i != metrics.end(); ++i) { + TempoSection* t; + + if ((t = dynamic_cast<TempoSection*> (*i)) != 0) { + + if ((*i)->frame() > frame) { + ts_after = t; + break; + } + } + } if (ts_after) { return (60.0 * _frame_rate) / (ts_at->tempo_at_frame (frame - ts_at->frame(), ts_after->beats_per_minute(), ts_after->frame(), _frame_rate)); @@ -2049,7 +1981,24 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) MetricSectionSorter cmp; metrics.sort (cmp); } + /* check for legacy sessions where bbt was the base musical unit for tempo */ + for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) { + MeterSection* prev_ms; + TempoSection* prev_ts; + if ((prev_ms = dynamic_cast<MeterSection*>(*i)) != 0) { + if (prev_ms->start() < 0.0) { + /*XX we cannot possibly make this work??. */ + pair<double, BBT_Time> start = make_pair (((prev_ms->bbt().bars - 1) * 4.0) + (prev_ms->bbt().beats - 1) + (prev_ms->bbt().ticks / BBT_Time::ticks_per_beat), prev_ms->bbt()); + prev_ms->set_start (start); + } + } else if ((prev_ts = dynamic_cast<TempoSection*>(*i)) != 0) { + if (prev_ts->start() < 0.0) { + double const start = ((prev_ts->legacy_bbt().bars - 1) * 4.0) + (prev_ts->legacy_bbt().beats - 1) + (prev_ts->legacy_bbt().ticks / BBT_Time::ticks_per_beat); + prev_ts->set_start (start); + } + } + } /* check for multiple tempo/meters at the same location, which ardour2 somehow allowed. */ @@ -2057,16 +2006,20 @@ TempoMap::set_state (const XMLNode& node, int /*version*/) Metrics::iterator prev = metrics.end(); for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) { if (prev != metrics.end()) { - if (dynamic_cast<MeterSection*>(*prev) && dynamic_cast<MeterSection*>(*i)) { - if ((*prev)->start() == (*i)->start()) { - cerr << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg; - error << string_compose (_("Multiple meter definitions found at %1"), (*prev)->start()) << endmsg; + MeterSection* ms; + MeterSection* prev_ms; + TempoSection* ts; + TempoSection* prev_ts; + if ((prev_ms = dynamic_cast<MeterSection*>(*prev)) != 0 && (ms = dynamic_cast<MeterSection*>(*i)) != 0) { + if (prev_ms->start() == ms->start()) { + cerr << string_compose (_("Multiple meter definitions found at %1"), prev_ms->start()) << endmsg; + error << string_compose (_("Multiple meter definitions found at %1"), prev_ms->start()) << endmsg; return -1; } - } else if (dynamic_cast<TempoSection*>(*prev) && dynamic_cast<TempoSection*>(*i)) { - if ((*prev)->start() == (*i)->start()) { - cerr << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg; - error << string_compose (_("Multiple tempo definitions found at %1"), (*prev)->start()) << endmsg; + } else if ((prev_ts = dynamic_cast<TempoSection*>(*prev)) != 0 && (ts = dynamic_cast<TempoSection*>(*i)) != 0) { + if (prev_ts->start() == ts->start()) { + cerr << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->start()) << endmsg; + error << string_compose (_("Multiple tempo definitions found at %1"), prev_ts->start()) << endmsg; return -1; } } @@ -2095,7 +2048,7 @@ TempoMap::dump (std::ostream& o) const 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? " << t->movable() << ')' << endl; } else if ((m = dynamic_cast<const MeterSection*>(*i)) != 0) { - o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->start() << " frame= " << m->frame() + o << "Meter @ " << *i << ' ' << m->divisions_per_bar() << '/' << m->note_divisor() << " at " << m->bbt() << " frame= " << m->frame() << " (movable? " << m->movable() << ')' << endl; } } @@ -2167,46 +2120,67 @@ TempoMap::insert_time (framepos_t where, framecnt_t amount) for (i = metrics.begin(); i != metrics.end(); ++i) { BBT_Time bbt; - TempoMetric metric (*meter, *tempo); - + //TempoMetric metric (*meter, *tempo); + MeterSection* ms = const_cast<MeterSection*>(meter); + TempoSection* ts = const_cast<TempoSection*>(tempo); if (prev) { - metric.set_start (prev->start()); - metric.set_frame (prev->frame()); - } else { - // metric will be at frames=0 bbt=1|1|0 by default - // which is correct for our purpose - } - - bbt_time ((*i)->frame(), bbt); - - // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => "; - - if (first) { - first = false; - } else { + if (ts){ + if ((t = dynamic_cast<TempoSection*>(prev)) != 0) { + ts->set_start (t->start()); + } + if ((m = dynamic_cast<MeterSection*>(prev)) != 0) { + ts->set_start (m->start()); + } + ts->set_frame (prev->frame()); - if (bbt.ticks > BBT_Time::ticks_per_beat/2) { - /* round up to next beat */ - bbt.beats += 1; } - - bbt.ticks = 0; - - if (bbt.beats != 1) { - /* round up to next bar */ - bbt.bars += 1; - bbt.beats = 1; + if (ms) { + if ((m = dynamic_cast<MeterSection*>(prev)) != 0) { + pair<double, BBT_Time> start = make_pair (m->start(), m->bbt()); + ms->set_start (start); + } + if ((t = dynamic_cast<TempoSection*>(prev)) != 0) { + pair<double, BBT_Time> start = make_pair (t->start(), beats_to_bbt (t->start())); + ms->set_start (start); + } + ms->set_frame (prev->frame()); } + + } else { + // metric will be at frames=0 bbt=1|1|0 by default + // which is correct for our purpose } // cerr << bbt << endl; - (*i)->set_start (bbt); - if ((t = dynamic_cast<TempoSection*>(*i)) != 0) { + t->set_start (beat_at_frame (m->frame())); tempo = t; // cerr << "NEW TEMPO, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl; } else if ((m = dynamic_cast<MeterSection*>(*i)) != 0) { + bbt_time (m->frame(), bbt); + + // cerr << "timestamp @ " << (*i)->frame() << " with " << bbt.bars << "|" << bbt.beats << "|" << bbt.ticks << " => "; + + if (first) { + first = false; + } else { + + if (bbt.ticks > BBT_Time::ticks_per_beat/2) { + /* round up to next beat */ + bbt.beats += 1; + } + + bbt.ticks = 0; + + if (bbt.beats != 1) { + /* round up to next bar */ + bbt.bars += 1; + bbt.beats = 1; + } + } + pair<double, BBT_Time> start = make_pair (beat_at_frame (m->frame()), bbt); + m->set_start (start); meter = m; // cerr << "NEW METER, frame = " << (*i)->frame() << " start = " << (*i)->start() <<endl; } else { @@ -2497,7 +2471,7 @@ operator<< (std::ostream& o, const Tempo& t) { std::ostream& operator<< (std::ostream& o, const MetricSection& section) { - o << "MetricSection @ " << section.frame() << " aka " << section.start() << ' '; + o << "MetricSection @ " << section.frame() << ' '; const TempoSection* ts; const MeterSection* ms; @@ -2505,7 +2479,7 @@ operator<< (std::ostream& o, const MetricSection& section) { if ((ts = dynamic_cast<const TempoSection*> (§ion)) != 0) { o << *((const Tempo*) ts); } else if ((ms = dynamic_cast<const MeterSection*> (§ion)) != 0) { - o << *((const Meter*) ms); + //o << *((const Meter*) ms); } return o; diff --git a/libs/ardour/test/bbt_test.cc b/libs/ardour/test/bbt_test.cc index 416d02ba14..507af574d2 100644 --- a/libs/ardour/test/bbt_test.cc +++ b/libs/ardour/test/bbt_test.cc @@ -16,7 +16,7 @@ BBTTest::addTest () Tempo tempo(120); Meter meter(4.0, 4.0); - map.add_meter (meter, BBT_Time(1, 1, 0)); + map.add_meter (meter, 0.0, BBT_Time(1, 1, 0)); /* add some good stuff here */ } diff --git a/libs/ardour/test/framepos_minus_beats_test.cc b/libs/ardour/test/framepos_minus_beats_test.cc index 6f1bba53b2..588a38c097 100644 --- a/libs/ardour/test/framepos_minus_beats_test.cc +++ b/libs/ardour/test/framepos_minus_beats_test.cc @@ -22,8 +22,8 @@ FrameposMinusBeatsTest::singleTempoTest () Tempo tempo (bpm); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); - map.add_tempo (tempo, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); + map.add_tempo (tempo, 0.0, TempoSection::Type::Constant); /* Subtract 1 beat from beat 3 of the first bar */ framepos_t r = map.framepos_minus_beats (frames_per_beat * 2, Beats(1)); @@ -42,7 +42,7 @@ FrameposMinusBeatsTest::doubleTempoTest () TempoMap map (sampling_rate); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 4 @@ -63,9 +63,9 @@ FrameposMinusBeatsTest::doubleTempoTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (4, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 12.0, TempoSection::Type::Constant); /* Now some tests */ @@ -94,7 +94,7 @@ FrameposMinusBeatsTest::doubleTempoWithMeterTest () TempoMap map (sampling_rate); Meter meterA (4, 4); - map.add_meter (meterA, BBT_Time (1, 1, 0)); + map.add_meter (meterA, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 4 @@ -115,11 +115,11 @@ FrameposMinusBeatsTest::doubleTempoWithMeterTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (4, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 12.0, TempoSection::Type::Constant); Meter meterB (3, 4); - map.add_meter (meterB, BBT_Time (4, 1, 0)); + map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0)); /* Now some tests */ diff --git a/libs/ardour/test/framepos_plus_beats_test.cc b/libs/ardour/test/framepos_plus_beats_test.cc index 425ae84343..ab52861f50 100644 --- a/libs/ardour/test/framepos_plus_beats_test.cc +++ b/libs/ardour/test/framepos_plus_beats_test.cc @@ -21,8 +21,8 @@ FrameposPlusBeatsTest::singleTempoTest () Tempo tempo (bpm); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); - map.add_tempo (tempo, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); + map.add_tempo (tempo, 0.0, TempoSection::Type::Constant); /* Add 1 beat to beat 3 of the first bar */ framepos_t r = map.framepos_plus_beats (frames_per_beat * 2, Evoral::Beats(1)); @@ -41,7 +41,7 @@ FrameposPlusBeatsTest::doubleTempoTest () TempoMap map (sampling_rate); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 4 @@ -62,9 +62,9 @@ FrameposPlusBeatsTest::doubleTempoTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (4, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 12.0, TempoSection::Type::Constant); /* Now some tests */ @@ -93,7 +93,7 @@ FrameposPlusBeatsTest::doubleTempoWithMeterTest () TempoMap map (sampling_rate); Meter meterA (4, 4); - map.add_meter (meterA, BBT_Time (1, 1, 0)); + map.add_meter (meterA, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 4 @@ -114,11 +114,11 @@ FrameposPlusBeatsTest::doubleTempoWithMeterTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (4, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 12.0, TempoSection::Type::Constant); Meter meterB (3, 4); - map.add_meter (meterB, BBT_Time (4, 1, 0)); + map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0)); /* Now some tests */ diff --git a/libs/ardour/test/framewalk_to_beats_test.cc b/libs/ardour/test/framewalk_to_beats_test.cc index 84ddf6fc30..f6e84ddfad 100644 --- a/libs/ardour/test/framewalk_to_beats_test.cc +++ b/libs/ardour/test/framewalk_to_beats_test.cc @@ -20,8 +20,8 @@ FramewalkToBeatsTest::singleTempoTest () Tempo tempo (bpm); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); - map.add_tempo (tempo, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); + map.add_tempo (tempo, 0.0, TempoSection::Type::Constant); /* Walk 1 beats-worth of frames from beat 3 */ double r = map.framewalk_to_beats (frames_per_beat * 2, frames_per_beat * 1).to_double(); @@ -47,7 +47,7 @@ FramewalkToBeatsTest::doubleTempoTest () TempoMap map (sampling_rate); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 4 @@ -70,9 +70,9 @@ FramewalkToBeatsTest::doubleTempoTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (4, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 12.0, TempoSection::Type::Constant); /* Now some tests */ @@ -103,7 +103,7 @@ FramewalkToBeatsTest::tripleTempoTest () TempoMap map (sampling_rate); Meter meter (4, 4); - map.add_meter (meter, BBT_Time (1, 1, 0)); + map.add_meter (meter, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 2, 160bpm at bar 3 @@ -125,11 +125,11 @@ FramewalkToBeatsTest::tripleTempoTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (2, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 4.0, TempoSection::Type::Constant); Tempo tempoC (160); - map.add_tempo (tempoC, BBT_Time (3, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoC, 8.0, TempoSection::Type::Constant); /* Walk from 1|3 to 4|1 */ double r = map.framewalk_to_beats (2 * 24e3, (2 * 24e3) + (4 * 12e3) + (4 * 18e3)).to_double(); diff --git a/libs/ardour/test/midi_clock_slave_test.h b/libs/ardour/test/midi_clock_slave_test.h index 392e2876e9..ba87f8892a 100644 --- a/libs/ardour/test/midi_clock_slave_test.h +++ b/libs/ardour/test/midi_clock_slave_test.h @@ -48,8 +48,8 @@ class TestSlaveSessionProxy : public ISlaveSessionProxy { meter (4.0, 4.0) { _tempo_map = new TempoMap (FRAME_RATE); - _tempo_map->add_tempo (tempo, Timecode::BBT_Time(1, 1, 0), TempoSection::Type::Constant); - _tempo_map->add_meter (meter, Timecode::BBT_Time(1, 1, 0)); + _tempo_map->add_tempo (tempo, 0.0, TempoSection::Type::Constant); + _tempo_map->add_meter (meter, 0.0, Timecode::BBT_Time(1, 1, 0)); } // Controlling the mock object diff --git a/libs/ardour/test/tempo_test.cc b/libs/ardour/test/tempo_test.cc index 04b24f6d73..a7f9c1d405 100644 --- a/libs/ardour/test/tempo_test.cc +++ b/libs/ardour/test/tempo_test.cc @@ -14,7 +14,7 @@ TempoTest::recomputeMapTest () TempoMap map (sampling_rate); Meter meterA (4, 4); - map.add_meter (meterA, BBT_Time (1, 1, 0)); + map.add_meter (meterA, 0.0, BBT_Time (1, 1, 0)); /* 120bpm at bar 1, 240bpm at bar 4 @@ -35,11 +35,11 @@ TempoTest::recomputeMapTest () */ Tempo tempoA (120); - map.add_tempo (tempoA, BBT_Time (1, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoA, 0.0, TempoSection::Type::Constant); Tempo tempoB (240); - map.add_tempo (tempoB, BBT_Time (4, 1, 0), TempoSection::Type::Constant); + map.add_tempo (tempoB, 12.0, TempoSection::Type::Constant); Meter meterB (3, 4); - map.add_meter (meterB, BBT_Time (4, 1, 0)); + map.add_meter (meterB, 12.0, BBT_Time (4, 1, 0)); list<MetricSection*>::iterator i = map.metrics.begin(); CPPUNIT_ASSERT_EQUAL (framepos_t (0), (*i)->frame ()); |