1
0
Fork 0

Optimize block smoothing

This commit is contained in:
Robbert van der Helm 2022-09-04 19:52:17 +02:00
parent cd02ebb839
commit 99437c6011

View file

@ -333,7 +333,8 @@ impl<T: Smoothable> Smoother<T> {
} }
/// The same as [`next_block()`][Self::next_block()], but with a function applied to each /// The same as [`next_block()`][Self::next_block()], but with a function applied to each
/// produced value. Useful when applying modulation to a smoothed parameter. /// produced value. Useful when applying modulation to a smoothed parameter. The mapping
/// function is only applied once for the final target value.
pub fn next_block_mapped(&self, block_values: &mut [T], block_len: usize, f: impl Fn(T) -> T) { pub fn next_block_mapped(&self, block_values: &mut [T], block_len: usize, f: impl Fn(T) -> T) {
self.next_block_exact_mapped(&mut block_values[..block_len], f) self.next_block_exact_mapped(&mut block_values[..block_len], f)
} }
@ -346,12 +347,34 @@ impl<T: Smoothable> Smoother<T> {
// values in `block_values` would require smoothing and the rest don't. Instead, we'll just // values in `block_values` would require smoothing and the rest don't. Instead, we'll just
// smooth the values as necessary, and then reuse the target value for the rest of the // smooth the values as necessary, and then reuse the target value for the rest of the
// block. // block.
let num_smoothed_values = block_values let steps_left = self.steps_left.load(Ordering::Relaxed) as usize;
.len() let num_smoothed_values = block_values.len().min(steps_left);
.min(self.steps_left.load(Ordering::Relaxed) as usize); if num_smoothed_values > 0 {
// This is the same as calling `next()` `num_smoothed_values` times, but with some
// conditionals optimized out
let mut current = self.current.load(Ordering::Relaxed);
let target = self.target.to_f32();
block_values[..num_smoothed_values].fill_with(|| {
current = self.style.next(current, target, self.step_size);
f(T::from_f32(current))
});
block_values[..num_smoothed_values].fill_with(|| f(self.next())); // In `next()` the last step snaps the value to the target value. Since we're computing
block_values[num_smoothed_values..].fill(self.target); // many values in a row, we'll just overwrite the last value with the target value
// instead to avoid the conditional.
if num_smoothed_values == steps_left {
current = target.to_f32();
block_values[num_smoothed_values - 1..].fill(f(self.target));
} else {
block_values[num_smoothed_values..].fill(f(self.target));
}
self.current.store(current, Ordering::Relaxed);
self.steps_left
.fetch_sub(num_smoothed_values as i32, Ordering::Relaxed);
} else {
block_values.fill(f(self.target));
}
} }
} }