summaryrefslogtreecommitdiff
path: root/libs/ardour/tempo.cc
diff options
context:
space:
mode:
authornick_m <mainsbridge@gmail.com>2015-12-29 16:51:10 +1100
committernick_m <mainsbridge@gmail.com>2016-05-27 23:38:10 +1000
commit772683d2df7ba96d27943140fe59c8797fd7bed3 (patch)
tree3c96af683138474461f43bdd26078c38c3722e89 /libs/ardour/tempo.cc
parent2f5b6b6b85f0f518aa702925946bac2a0589b563 (diff)
Tempo ramps - improve the performance of recompute_map().
Diffstat (limited to 'libs/ardour/tempo.cc')
-rw-r--r--libs/ardour/tempo.cc247
1 files changed, 87 insertions, 160 deletions
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 6112fb7c54..1715aadf06 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -712,81 +712,77 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const doubl
void
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);
+ {
+ Glib::Threads::RWLock::WriterLock lm (lock);
- MetricSectionFrameSorter fcmp;
- metrics.sort (fcmp);
+ /* currently this is always done in audio time */
+ //if (ts.position_lock_style() == MusicTime) {
+ if (0) {
+ /* MusicTime */
+ ts.set_start (beat_where);
+ MetricSectionSorter cmp;
+ metrics.sort (cmp);
+ } else {
+ /*AudioTime*/
+ ts.set_frame (frame);
- Metrics::const_iterator i;
- TempoSection* prev_ts = 0;
- TempoSection* next_ts = 0;
+ MetricSectionFrameSorter fcmp;
+ metrics.sort (fcmp);
- for (i = metrics.begin(); i != metrics.end(); ++i) {
- TempoSection* t;
- if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ Metrics::const_iterator i;
+ TempoSection* prev_ts = 0;
+ TempoSection* next_ts = 0;
- if (t->frame() >= frame) {
- break;
- }
+ for (i = metrics.begin(); i != metrics.end(); ++i) {
+ TempoSection* t;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
- prev_ts = t;
+ if (t->frame() >= frame) {
+ break;
}
+
+ prev_ts = t;
}
+ }
- for (i = metrics.begin(); i != metrics.end(); ++i) {
- TempoSection* t;
- if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ for (i = metrics.begin(); i != metrics.end(); ++i) {
+ TempoSection* t;
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
- if (t->frame() > frame) {
- next_ts = t;
- break;
- }
+ if (t->frame() > frame) {
+ next_ts = t;
+ break;
}
}
+ }
- 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);
- }
+ 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
+ */
+ } else if (prev_ts->start() > beats) {
+ ts.set_start (prev_ts->start());
} else {
ts.set_start (beats);
}
- MetricSectionSorter cmp;
- metrics.sort (cmp);
+ } else {
+ ts.set_start (beats);
}
+ MetricSectionSorter cmp;
+ metrics.sort (cmp);
}
-
- recompute_map (false);
}
+
+ recompute_map (false);
}
MetricPositionChanged (); // Emit Signal
@@ -1020,12 +1016,6 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
{
/* CALLER MUST HOLD WRITE LOCK */
- MeterSection* meter = 0;
- TempoSection* tempo = 0;
- double current_frame;
- BBT_Time current;
- Metrics::iterator next_metric;
-
if (end < 0) {
/* we will actually stop once we hit
@@ -1037,122 +1027,59 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
- for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
- MeterSection* ms;
-
- if ((ms = dynamic_cast<MeterSection *> (*i)) != 0) {
- meter = ms;
- break;
- }
- }
-
- assert(meter);
-
- for (Metrics::iterator i = metrics.begin(); i != metrics.end(); ++i) {
- TempoSection* ts;
-
- if ((ts = dynamic_cast<TempoSection *> (*i)) != 0) {
- tempo = ts;
- break;
- }
- }
-
- assert(tempo);
-
- /* assumes that the first meter & tempo are at frame zero */
- current_frame = 0;
- meter->set_frame (0);
- tempo->set_frame (0);
-
- /* assumes that the first meter & tempo are at 1|1|0 */
- current.bars = 1;
- current.beats = 1;
- current.ticks = 0;
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("start with meter = %1 tempo = %2\n", *((Meter*)meter), *((Tempo*)tempo)));
-
- next_metric = metrics.begin();
- ++next_metric; // skip meter (or tempo)
- ++next_metric; // skip tempo (or meter)
-
- DEBUG_TRACE (DEBUG::TempoMath, string_compose ("Add first bar at 1|1 @ %2\n", current.bars, current_frame));
-
if (end == 0) {
/* silly call from Session::process() during startup
*/
return;
}
- _extend_map (tempo, meter, next_metric, current, current_frame, end);
-}
-
-void
-TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
- Metrics::iterator next_metric,
- BBT_Time current, framepos_t current_frame, framepos_t end)
-{
- /* CALLER MUST HOLD WRITE LOCK */
-
Metrics::const_iterator i;
- Metrics::const_iterator mi;
- TempoSection* prev_ts = tempo;
-
- for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
- MeterSection* m = 0;
-
- if ((m = dynamic_cast<MeterSection*> (*mi)) != 0) {
-
- for (i = metrics.begin(); i != metrics.end(); ++i) {
- TempoSection* t;
+ TempoSection* prev_ts = 0;
- if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
+ for (i = metrics.begin(); i != metrics.end(); ++i) {
+ TempoSection* t;
- if (t->start() > prev_ts->start()) {
+ if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
- /*tempo section (t) lies in the previous meter */
- 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;
+ if (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 const t_fpb = t->frames_per_beat (_frame_rate);
- double const av_fpb = (prev_ts->frames_per_beat (_frame_rate) + t_fpb) / 2.0;
- /* this walk shouldn't be needed as given c, time a = log (Ta / T0) / c. what to do? */
- double length_estimate = beats_relative_to_prev_ts * av_fpb;
+ /* assume (falsely) that the target tempo is constant */
+ 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;
+ /* this walk shouldn't be needed as given c, time a = log (Ta / T0) / c. what to do? */
+ double length_estimate = beats_relative_to_prev_ts * av_fpb;
- if (prev_ts->type() == TempoSection::Type::Constant) {
- length_estimate = beats_relative_to_prev_ts * prev_ts->frames_per_beat (_frame_rate);
- }
+ if (prev_ts->type() == TempoSection::Type::Constant) {
+ length_estimate = beats_relative_to_prev_ts * prev_ts->frames_per_beat (_frame_rate);
+ }
- 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
+ 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 * (t->ticks_per_minute() / _frame_rate);
- }
+ 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 * (t->ticks_per_minute() / _frame_rate);
+ }
- t->set_frame (length_estimate + prev_ts->frame());
+ t->set_frame (length_estimate + prev_ts->frame());
+ }
+ prev_ts = t;
+ }
+ }
- double const meter_start_beats = m->start();
- if (meter_start_beats < t->start() && meter_start_beats == prev_ts->start()) {
+ Metrics::const_iterator mi;
+ MeterSection* meter = 0;
- m->set_frame (prev_ts->frame());
- } else if (meter_start_beats < t->start() && meter_start_beats > prev_ts->start()) {
- framepos_t new_frame = prev_ts->frame_at_beat (m->start() - prev_ts->start(),
- t->beats_per_minute(),
- t->frame() - prev_ts->frame(),
- _frame_rate) + prev_ts->frame();
- m->set_frame (new_frame);
- }
- }
- prev_ts = t;
- }
- }
- meter = m;
+ for (mi = metrics.begin(); mi != metrics.end(); ++mi) {
+ /* we can do this beacuse we have the tempo section frames set */
+ if ((meter = dynamic_cast<MeterSection*> (*mi)) != 0) {
+ meter->set_frame (frame_at_tick (meter->start() * BBT_Time::ticks_per_beat));
}
}
}