summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authornick_m <mainsbridge@gmail.com>2016-04-26 03:21:48 +1000
committernick_m <mainsbridge@gmail.com>2016-05-27 23:38:15 +1000
commite0607ca913bde8f3551cb8e7dc0d3bec5203159c (patch)
tree5e5619a966f086b3ea7590cfe4ac515c44a57e5a /libs
parent54758ddd4a339b5d2e2e8bedfb4187f2f98ce51c (diff)
Tempo ramps - add gui dilation of tempos.
- a meter can be dragged using the constraint modifier, which sets the previous tempo accordingly. This could be added to the bbt ruler to allow direct dragging of beats and bars, but the exact behavior of that is still undecided. comments? - also preliminary work on the necessary tempos locked to audio-locked meters.
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/tempo.h26
-rw-r--r--libs/ardour/tempo.cc253
2 files changed, 242 insertions, 37 deletions
diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h
index c8c6af5247..25180b8eb3 100644
--- a/libs/ardour/ardour/tempo.h
+++ b/libs/ardour/ardour/tempo.h
@@ -178,26 +178,29 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
};
TempoSection (const double& beat, double qpm, double note_type, Type tempo_type)
- : MetricSection (beat), Tempo (qpm, note_type), _type (tempo_type), _c_func (0.0), _active (true) {}
+ : MetricSection (beat), Tempo (qpm, note_type), _type (tempo_type), _c_func (0.0), _active (true), _locked_to_meter (false) {}
TempoSection (framepos_t frame, double qpm, double note_type, Type tempo_type)
- : MetricSection (frame), Tempo (qpm, note_type), _type (tempo_type), _c_func (0.0), _active (true) {}
+ : MetricSection (frame), Tempo (qpm, note_type), _type (tempo_type), _c_func (0.0), _active (true), _locked_to_meter (false) {}
TempoSection (const XMLNode&);
static const std::string xml_state_node_name;
XMLNode& get_state() const;
- bool active () const { return _active; }
- void set_active (bool yn) { _active = yn; }
+ double c_func () const { return _c_func; }
+ void set_c_func (double c_func) { _c_func = c_func; }
void set_type (Type type);
Type type () const { return _type; }
- double c_func () const { return _c_func; }
- void set_c_func (double c_func) { _c_func = c_func; }
+ bool active () const { return _active; }
+ void set_active (bool yn) { _active = yn; }
+
+ bool locked_to_meter () const { return _locked_to_meter; }
+ void set_locked_to_meter (bool yn) { _locked_to_meter = yn; }
- double tempo_at_frame (const framepos_t& frame, const framecnt_t& frame_rate) const;
- framepos_t frame_at_tempo (const double& ppm, const double& beat, const framecnt_t& frame_rate) const;
+ double tempo_at_frame (const frameoffset_t& frame, const framecnt_t& frame_rate) const;
+ frameoffset_t frame_at_tempo (const double& ppm, const double& beat, const framecnt_t& frame_rate) const;
double tempo_at_pulse (const double& pulse) const;
double pulse_at_tempo (const double& ppm, const framepos_t& frame, const framecnt_t& frame_rate) const;
@@ -212,8 +215,8 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
private:
- framecnt_t minute_to_frame (const double& time, const framecnt_t& frame_rate) const;
- double frame_to_minute (const framecnt_t& frame, const framecnt_t& frame_rate) const;
+ frameoffset_t minute_to_frame (const double& time, const framecnt_t& frame_rate) const;
+ double frame_to_minute (const frameoffset_t& frame, const framecnt_t& frame_rate) const;
/* tempo ramp functions. zero-based with time in minutes,
* 'tick tempo' in ticks per minute and tempo in bpm.
@@ -242,6 +245,7 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
Type _type;
double _c_func;
bool _active;
+ bool _locked_to_meter;
Timecode::BBT_Time _legacy_bbt;
};
@@ -393,6 +397,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
void gui_move_meter (MeterSection*, const framepos_t& frame);
void gui_move_meter (MeterSection*, const double& pulse);
bool gui_change_tempo (TempoSection*, const Tempo& bpm);
+ void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
@@ -463,6 +468,7 @@ private:
const TempoSection& tempo_section_at_locked (const Metrics& metrics, framepos_t frame) const;
const MeterSection& meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
const TempoSection& tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
+ const TempoSection& tempo_section_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
const Tempo tempo_at_locked (const Metrics& metrics, const framepos_t& frame) const;
bool check_solved (const Metrics& metrics, bool by_frame) const;
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index c9176847c9..c9242d1f92 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -77,6 +77,7 @@ TempoSection::TempoSection (const XMLNode& node)
, Tempo (TempoMap::default_tempo())
, _c_func (0.0)
, _active (true)
+ , _locked_to_meter (false)
{
const XMLProperty *prop;
LocaleGuard lg;
@@ -163,6 +164,12 @@ TempoSection::TempoSection (const XMLNode& node)
} else {
set_position_lock_style (PositionLockStyle (string_2_enum (prop->value(), position_lock_style())));
}
+
+ if ((prop = node.property ("locked-to-meter")) == 0) {
+ set_locked_to_meter (false);
+ } else {
+ set_locked_to_meter (string_is_affirmative (prop->value()));
+ }
}
XMLNode&
@@ -186,6 +193,7 @@ TempoSection::get_state() const
root->add_property ("active", buf);
root->add_property ("tempo-type", enum_2_string (_type));
root->add_property ("lock-style", enum_2_string (position_lock_style()));
+ root->add_property ("locked-to-meter", locked_to_meter()?"yes":"no");
return *root;
}
@@ -199,14 +207,14 @@ TempoSection::set_type (Type type)
/** returns the tempo in whole pulses per minute at the zero-based (relative to session) frame.
*/
double
-TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
+TempoSection::tempo_at_frame (const frameoffset_t& f, const framecnt_t& frame_rate) const
{
if (_type == Constant || _c_func == 0.0) {
return pulses_per_minute();
}
- return pulse_tempo_at_time (frame_to_minute (f - frame(), frame_rate));
+ return pulse_tempo_at_time (frame_to_minute (f - (frameoffset_t) frame(), frame_rate));
}
/** returns the zero-based frame (relative to session)
@@ -214,7 +222,7 @@ TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate)
beat b is only used for constant tempos.
note that the tempo map may have multiple such values.
*/
-framepos_t
+frameoffset_t
TempoSection::frame_at_tempo (const double& ppm, const double& b, const framecnt_t& frame_rate) const
{
if (_type == Constant || _c_func == 0.0) {
@@ -308,7 +316,7 @@ The integral over t of our Tempo function (the beat function, which is the durat
b(t) = T0(e^(ct) - 1) / c
To find the time t at beat duration b, we use the inverse function of the beat function (the time function) which can be shown to be:
-t(b) = log((cb / T0) + 1) / c
+t(b) = log((c.b / T0) + 1) / c
The time t at which Tempo T occurs is a as above:
t(T) = log(T / T0) / c
@@ -372,30 +380,30 @@ TempoSection::compute_c_func_frame (const double& end_bpm, const framepos_t& end
return c_func (end_bpm, frame_to_minute (end_frame - frame(), frame_rate));
}
-framecnt_t
+frameoffset_t
TempoSection::minute_to_frame (const double& time, const framecnt_t& frame_rate) const
{
return (framecnt_t) floor ((time * 60.0 * frame_rate) + 0.5);
}
double
-TempoSection::frame_to_minute (const framecnt_t& frame, const framecnt_t& frame_rate) const
+TempoSection::frame_to_minute (const frameoffset_t& frame, const framecnt_t& frame_rate) const
{
return (frame / (double) frame_rate) / 60.0;
}
/* position function */
double
-TempoSection::a_func (double end_bpm, double c_func) const
+TempoSection::a_func (double end_ppm, double c_func) const
{
- return log (end_bpm / pulses_per_minute()) / c_func;
+ return log (end_ppm / pulses_per_minute()) / c_func;
}
/*function constant*/
double
-TempoSection::c_func (double end_bpm, double end_time) const
+TempoSection::c_func (double end_ppm, double end_time) const
{
- return log (end_bpm / pulses_per_minute()) / end_time;
+ return log (end_ppm / pulses_per_minute()) / end_time;
}
/* tempo in ppm at time in minutes */
@@ -676,6 +684,7 @@ TempoMap::remove_tempo_locked (const TempoSection& tempo)
if (dynamic_cast<TempoSection*> (*i) != 0) {
if (tempo.frame() == (*i)->frame()) {
if ((*i)->movable()) {
+ delete (*i);
_metrics.erase (i);
return true;
}
@@ -706,14 +715,28 @@ TempoMap::remove_meter (const MeterSection& tempo, bool complete_operation)
}
bool
-TempoMap::remove_meter_locked (const MeterSection& tempo)
+TempoMap::remove_meter_locked (const MeterSection& meter)
{
Metrics::iterator i;
for (i = _metrics.begin(); i != _metrics.end(); ++i) {
+ TempoSection* t = 0;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (meter.frame() == (*i)->frame()) {
+ if (t->locked_to_meter()) {
+ delete (*i);
+ _metrics.erase (i);
+ break;
+ }
+ }
+ }
+ }
+
+ for (i = _metrics.begin(); i != _metrics.end(); ++i) {
if (dynamic_cast<MeterSection*> (*i) != 0) {
- if (tempo.frame() == (*i)->frame()) {
+ if (meter.frame() == (*i)->frame()) {
if ((*i)->movable()) {
+ delete (*i);
_metrics.erase (i);
return true;
}
@@ -782,6 +805,7 @@ TempoMap::do_insert (MetricSection* section)
}
need_add = false;
} else {
+ delete (*i);
_metrics.erase (i);
}
break;
@@ -806,6 +830,7 @@ TempoMap::do_insert (MetricSection* section)
(*i)->set_position_lock_style (AudioTime);
need_add = false;
} else {
+ delete (*i);
_metrics.erase (i);
}
@@ -937,6 +962,7 @@ TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, bool recompute, AR
if (recompute) {
solve_map (_metrics, t, t->pulse());
+ recompute_meters (_metrics);
}
return t;
@@ -951,6 +977,7 @@ TempoMap::add_tempo_locked (const Tempo& tempo, framepos_t frame, bool recompute
if (recompute) {
solve_map (_metrics, t, t->frame());
+ recompute_meters (_metrics);
}
return t;
@@ -1082,12 +1109,16 @@ MeterSection*
TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, double beat, Timecode::BBT_Time where, bool recompute)
{
MeterSection* new_meter = new MeterSection (frame, beat, where, meter.divisions_per_bar(), meter.note_divisor());
-
+ TempoSection* t = 0;
double pulse = pulse_at_frame_locked (_metrics, frame);
new_meter->set_pulse (pulse);
do_insert (new_meter);
+ /* add meter-locked tempo */
+ t = add_tempo_locked (tempo_at_locked (_metrics, frame), frame, true, TempoSection::Ramp);
+ t->set_locked_to_meter (true);
+
if (recompute) {
solve_map (_metrics, new_meter, frame);
}
@@ -1259,9 +1290,11 @@ TempoMap::recompute_tempos (Metrics& metrics)
continue;
}
if (!t->movable()) {
- t->set_pulse (0.0);
- prev_t = t;
- continue;
+ if (!prev_t) {
+ t->set_pulse (0.0);
+ prev_t = t;
+ continue;
+ }
}
if (prev_t) {
if (t->position_lock_style() == AudioTime) {
@@ -1920,7 +1953,6 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t
}
if (check_solved (imaginary, true)) {
- recompute_meters (imaginary);
return true;
}
@@ -1936,7 +1968,6 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t
}
if (check_solved (imaginary, true)) {
- recompute_meters (imaginary);
return true;
}
@@ -1995,7 +2026,6 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const double& pu
}
if (check_solved (imaginary, false)) {
- recompute_meters (imaginary);
return true;
}
@@ -2011,7 +2041,6 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const double& pu
}
if (check_solved (imaginary, false)) {
- recompute_meters (imaginary);
return true;
}
@@ -2029,7 +2058,6 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
return;
}
MeterSection* prev_m = 0;
-
if (!section->movable()) {
/* lock the first tempo to our first meter */
if (!set_active_tempos (imaginary, frame)) {
@@ -2053,11 +2081,33 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
}
}
+ TempoSection* meter_locked_tempo = 0;
+
+ if ((meter_locked_tempo = const_cast<TempoSection*>(&tempo_section_at_locked (imaginary, section->frame())))->frame() == section->frame()) {
+ if (meter_locked_tempo->locked_to_meter()) {
+ std::cout << "locked to meter " << std::endl;
+ Metrics future_map;
+ TempoSection* new_section = copy_metrics_and_point (future_map, meter_locked_tempo);
+
+ new_section->set_frame (frame);
+ new_section->set_active (true);
+
+ if (solve_map (future_map, new_section, frame)) {
+ meter_locked_tempo->set_frame (frame);
+ meter_locked_tempo->set_active (true);
+ solve_map (imaginary, meter_locked_tempo, frame);
+ } else {
+ return;
+ }
+ } else {
+ meter_locked_tempo = 0;
+ }
+ }
+
for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
MeterSection* m;
if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
if (m == section){
- double new_pulse = 0.0;
if (prev_m && section->movable()) {
const double beats = ((pulse_at_frame_locked (imaginary, frame) - prev_m->pulse()) * prev_m->note_divisor());
if (beats + prev_m->beat() < section->beat()) {
@@ -2067,18 +2117,25 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
this is what the user would actually want.
here we set the frame/pulse corresponding to its musical position.
*/
- new_pulse = ((section->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
+ const double new_pulse = ((section->beat() - prev_m->beat()) / prev_m->note_divisor()) + prev_m->pulse();
section->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
section->set_pulse (new_pulse);
+ if (meter_locked_tempo) {
+ meter_locked_tempo->set_frame (section->frame());
+ /* XX need to fake the pulse and prevent it from changing */
+ //meter_locked_tempo->set_pulse (pulse_at_frame_locked (imaginary, section->frame()));
+ }
break;
+ } else {
+ section->set_pulse (pulse_at_frame_locked (imaginary, frame));
}
- new_pulse = pulse_at_frame_locked (imaginary, frame);
} else {
pair<double, BBT_Time> b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
section->set_beat (b_bbt);
+ section->set_pulse (0.0);
+
}
section->set_frame (frame);
- section->set_pulse (new_pulse);
break;
}
@@ -2157,6 +2214,7 @@ TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
ret = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
ret->set_pulse (t->pulse());
}
+ ret->set_c_func (t->c_func());
ret->set_active (t->active());
ret->set_movable (t->movable());
copy.push_back (ret);
@@ -2170,6 +2228,7 @@ TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
cp = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
cp->set_pulse (t->pulse());
}
+ cp->set_c_func (t->c_func());
cp->set_active (t->active());
cp->set_movable (t->movable());
copy.push_back (cp);
@@ -2202,8 +2261,8 @@ TempoMap::can_solve_bbt (TempoSection* ts, const BBT_Time& bbt)
new_section = copy_metrics_and_point (copy, ts);
}
- double const beat = bbt_to_beats_locked (copy, bbt);
- bool ret = solve_map (copy, new_section, pulse_at_beat_locked (copy, beat));
+ const double beat = bbt_to_beats_locked (copy, bbt);
+ const bool ret = solve_map (copy, new_section, pulse_at_beat_locked (copy, beat));
Metrics::const_iterator d = copy.begin();
while (d != copy.end()) {
@@ -2277,6 +2336,7 @@ TempoMap::gui_move_tempo_frame (TempoSection* ts, const framepos_t& frame)
TempoSection* new_section = copy_metrics_and_point (future_map, ts);
if (solve_map (future_map, new_section, frame)) {
solve_map (_metrics, ts, frame);
+ recompute_meters (_metrics);
}
}
@@ -2298,6 +2358,7 @@ TempoMap::gui_move_tempo_beat (TempoSection* ts, const double& beat)
TempoSection* new_section = copy_metrics_and_point (future_map, ts);
if (solve_map (future_map, new_section, pulse_at_beat_locked (future_map, beat))) {
solve_map (_metrics, ts, pulse_at_beat_locked (_metrics, beat));
+ recompute_meters (_metrics);
}
}
@@ -2361,6 +2422,126 @@ TempoMap::gui_change_tempo (TempoSection* ts, const Tempo& bpm)
return can_solve;
}
+void
+TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
+{
+ Metrics future_map;
+ TempoSection* ts = 0;
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
+ ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, ms->frame() - 1));
+ TempoSection* prev_t = copy_metrics_and_point (future_map, ts);
+ TempoSection* prev_to_prev_t = 0;
+ const frameoffset_t fr_off = frame - ms->frame();
+ double new_bpm = 0.0;
+
+ if (prev_t) {
+ prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
+ }
+
+ /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
+ constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
+ */
+ if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
+ if (prev_t->position_lock_style() == MusicTime) {
+ if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ /* prev to prev_t's position will remain constant in terms of frame and pulse. lets use frames. */
+ const double contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (ms->frame() - prev_to_prev_t->frame());
+ const frameoffset_t frame_contribution = contribution * (double) fr_off;
+ const frameoffset_t prev_t_frame_contribution = fr_off - frame_contribution;
+ new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
+ / (double) (ms->frame() + prev_t_frame_contribution - prev_t->frame()));
+
+ } else {
+ /* prev to prev is irrelevant */
+ const double meter_pulse = prev_t->pulse_at_frame (ms->frame(), _frame_rate);
+ const double frame_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
+
+ if (frame_pulse != prev_t->pulse()) {
+ new_bpm = prev_t->beats_per_minute() * ((meter_pulse - prev_t->pulse()) / (frame_pulse - prev_t->pulse()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
+ }
+ } else {
+ /* AudioTime */
+ if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ /* prev to prev_t's position will remain constant in terms of frame and pulse. lets use frames. */
+ const double contribution = (prev_t->frame() - prev_to_prev_t->frame())
+ / (double) (ms->frame() - prev_to_prev_t->frame());
+ const frameoffset_t frame_contribution = contribution * (double) fr_off;
+ const frameoffset_t prev_t_frame_contribution = fr_off - frame_contribution;
+ new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame())
+ / (double) (ms->frame() + prev_t_frame_contribution - prev_t->frame()));
+ } else {
+ /* prev_to_prev_t is irrelevant */
+
+ if (frame != prev_t->frame()) {
+ new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame()) / (double) (frame - prev_t->frame()));
+ } else {
+ new_bpm = prev_t->beats_per_minute();
+ }
+ }
+ }
+ } else if (prev_t->c_func() < 0.0) {
+ if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ const double contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (ms->frame() - prev_to_prev_t->frame());
+ const frameoffset_t frame_contribution = contribution * (double) fr_off;
+ new_bpm = prev_t->tempo_at_frame (prev_t->frame() + frame_contribution, _frame_rate) * (double) prev_t->note_type();
+ } else {
+ /* prev_to_prev_t is irrelevant */
+ new_bpm = prev_t->tempo_at_frame (prev_t->frame() + fr_off, _frame_rate) * (double) prev_t->note_type();
+ }
+
+ const double diff = prev_t->beats_per_minute() - new_bpm;
+ if (diff > -0.1 && diff < 0.1) {
+ new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame()) / (double) (frame - prev_t->frame()));
+ }
+
+ } else if (prev_t->c_func() > 0.0) {
+ if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
+ const double contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (ms->frame() - prev_to_prev_t->frame());
+ const frameoffset_t frame_contribution = contribution * (double) fr_off;
+ new_bpm = prev_t->tempo_at_frame (prev_t->frame() - frame_contribution, _frame_rate) * (double) prev_t->note_type();
+ } else {
+ /* prev_to_prev_t is irrelevant */
+ new_bpm = prev_t->tempo_at_frame (prev_t->frame() - fr_off, _frame_rate) * (double) prev_t->note_type();
+ }
+ /* limits - a bit clunky, but meh */
+ const double diff = prev_t->beats_per_minute() - new_bpm;
+ if (diff > -0.1 && diff < 0.1) {
+ new_bpm = prev_t->beats_per_minute() * ((ms->frame() - prev_t->frame()) / (double) (frame - prev_t->frame()));
+ }
+ }
+
+ prev_t->set_beats_per_minute (new_bpm);
+ recompute_tempos (future_map);
+
+ if (check_solved (future_map, true)) {
+
+ prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, ms->frame() - 1));
+ prev_t->set_beats_per_minute (new_bpm);
+ recompute_tempos (_metrics);
+
+ if (ms->position_lock_style() == AudioTime) {
+ ms->set_frame (frame);
+ } else {
+ ms->set_pulse (prev_t->pulse_at_frame (frame, _frame_rate));
+ }
+ recompute_meters (_metrics);
+ }
+ }
+
+ Metrics::const_iterator d = future_map.begin();
+ while (d != future_map.end()) {
+ delete (*d);
+ ++d;
+ }
+
+ MetricPositionChanged (); // Emit Signal
+ return;
+}
+
framecnt_t
TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
{
@@ -2662,6 +2843,24 @@ TempoMap::tempo_section_at_beat_locked (const Metrics& metrics, const double& be
return *prev_t;
}
+const TempoSection&
+TempoMap::tempo_section_at_pulse_locked (const Metrics& metrics, const double& pulse) const
+{
+ TempoSection* prev_t = 0;
+
+ for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
+ TempoSection* t;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ if (prev_t && t->pulse() > pulse) {
+ break;
+ }
+ prev_t = t;
+ }
+
+ }
+ return *prev_t;
+}
+
/* don't use this to calculate length (the tempo is only correct for this frame).
do that stuff based on the beat_at_frame and frame_at_beat api
*/