summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authornick_m <mainsbridge@gmail.com>2015-12-28 05:33:04 +1100
committernick_m <mainsbridge@gmail.com>2016-05-27 23:38:09 +1000
commit5c6e18e6a087823e4a3719177c92238b206e3aeb (patch)
tree25f7faefa65e630e68da70bf4378b825e7c29312 /libs
parent41c8b534b70e220b4d4b940aed8a98d9a57003ab (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.h77
-rw-r--r--libs/ardour/tempo.cc664
-rw-r--r--libs/ardour/test/bbt_test.cc2
-rw-r--r--libs/ardour/test/framepos_minus_beats_test.cc18
-rw-r--r--libs/ardour/test/framepos_plus_beats_test.cc18
-rw-r--r--libs/ardour/test/framewalk_to_beats_test.cc18
-rw-r--r--libs/ardour/test/midi_clock_slave_test.h4
-rw-r--r--libs/ardour/test/tempo_test.cc8
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*> (&section)) != 0) {
o << *((const Tempo*) ts);
} else if ((ms = dynamic_cast<const MeterSection*> (&section)) != 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 ());