1
0
Fork 0

Split up set_target and reset in smoothers

This makes it a bit less awkward to use in user code, if you need a
separate smoother there.
This commit is contained in:
Robbert van der Helm 2022-02-04 15:14:47 +01:00
parent 15d0e69d46
commit 073fe743c2
2 changed files with 61 additions and 53 deletions

View file

@ -164,7 +164,11 @@ macro_rules! impl_plainparam {
type Plain = $plain; type Plain = $plain;
fn update_smoother(&mut self, sample_rate: f32, reset: bool) { fn update_smoother(&mut self, sample_rate: f32, reset: bool) {
self.smoothed.set_target(sample_rate, self.value, reset); if reset {
self.smoothed.reset(self.value);
} else {
self.smoothed.set_target(sample_rate, self.value);
}
} }
fn set_from_string(&mut self, string: &str) -> bool { fn set_from_string(&mut self, string: &str) -> bool {

View file

@ -82,30 +82,32 @@ impl<T: Default> Smoother<T> {
// These are not iterators for the sole reason that this will always yield a value, and needing to // These are not iterators for the sole reason that this will always yield a value, and needing to
// unwrap all of those options is not going to be very fun. // unwrap all of those options is not going to be very fun.
impl Smoother<f32> { impl Smoother<f32> {
/// Reset the smoother the specified value.
pub fn reset(&mut self, value: f32) {
self.target = value;
self.current = value;
self.steps_left = 0;
}
/// Set the target value. /// Set the target value.
pub fn set_target(&mut self, sample_rate: f32, target: f32, reset: bool) { pub fn set_target(&mut self, sample_rate: f32, target: f32) {
self.target = target; self.target = target;
if reset { self.steps_left = match self.style {
self.current = self.target; SmoothingStyle::None => 1,
self.steps_left = 0; SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => {
} else { (sample_rate * time / 1000.0).round() as u32
self.steps_left = match self.style { }
SmoothingStyle::None => 1, };
SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => { self.step_size = match self.style {
(sample_rate * time / 1000.0).round() as u32 SmoothingStyle::None => 0.0,
} SmoothingStyle::Linear(_) => (self.target - self.current) / self.steps_left as f32,
}; SmoothingStyle::Logarithmic(_) => {
self.step_size = match self.style { // We need to solve `current * (step_size ^ steps_left) = target` for
SmoothingStyle::None => 0.0, // `step_size`
SmoothingStyle::Linear(_) => (self.target - self.current) / self.steps_left as f32, nih_debug_assert_ne!(self.current, 0.0);
SmoothingStyle::Logarithmic(_) => { (self.target / self.current).powf((self.steps_left as f32).recip())
// We need to solve `current * (step_size ^ steps_left) = target` for }
// `step_size` };
nih_debug_assert_ne!(self.current, 0.0);
(self.target / self.current).powf((self.steps_left as f32).recip())
}
};
}
} }
// Yes, Clippy, like I said, this was intentional // Yes, Clippy, like I said, this was intentional
@ -133,29 +135,31 @@ impl Smoother<f32> {
} }
impl Smoother<i32> { impl Smoother<i32> {
pub fn set_target(&mut self, sample_rate: f32, target: i32, reset: bool) { /// Reset the smoother the specified value.
pub fn reset(&mut self, value: i32) {
self.target = value;
self.current = value as f32;
self.steps_left = 0;
}
pub fn set_target(&mut self, sample_rate: f32, target: i32) {
self.target = target; self.target = target;
if reset { self.steps_left = match self.style {
self.current = self.target as f32; SmoothingStyle::None => 1,
self.steps_left = 0; SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => {
} else { (sample_rate * time / 1000.0).round() as u32
self.steps_left = match self.style { }
SmoothingStyle::None => 1, };
SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => { self.step_size = match self.style {
(sample_rate * time / 1000.0).round() as u32 SmoothingStyle::None => 0.0,
} SmoothingStyle::Linear(_) => {
}; (self.target as f32 - self.current) / self.steps_left as f32
self.step_size = match self.style { }
SmoothingStyle::None => 0.0, SmoothingStyle::Logarithmic(_) => {
SmoothingStyle::Linear(_) => { nih_debug_assert_ne!(self.current, 0.0);
(self.target as f32 - self.current) / self.steps_left as f32 (self.target as f32 / self.current).powf((self.steps_left as f32).recip())
} }
SmoothingStyle::Logarithmic(_) => { };
nih_debug_assert_ne!(self.current, 0.0);
(self.target as f32 / self.current).powf((self.steps_left as f32).recip())
}
};
}
} }
#[allow(clippy::should_implement_trait)] #[allow(clippy::should_implement_trait)]
@ -186,12 +190,12 @@ mod tests {
#[test] #[test]
fn linear_f32_smoothing() { fn linear_f32_smoothing() {
let mut smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Linear(100.0)); let mut smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Linear(100.0));
smoother.set_target(100.0, 10.0, true); smoother.reset(10.0);
assert_eq!(smoother.next(), 10.0); assert_eq!(smoother.next(), 10.0);
// Instead of testing the actual values, we'll make sure that we reach the target values at // Instead of testing the actual values, we'll make sure that we reach the target values at
// the expected time. // the expected time.
smoother.set_target(100.0, 20.0, false); smoother.set_target(100.0, 20.0);
for _ in 0..(10 - 2) { for _ in 0..(10 - 2) {
dbg!(smoother.next()); dbg!(smoother.next());
} }
@ -202,11 +206,11 @@ mod tests {
#[test] #[test]
fn linear_i32_smoothing() { fn linear_i32_smoothing() {
let mut smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Linear(100.0)); let mut smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Linear(100.0));
smoother.set_target(100.0, 10, true); smoother.reset(10);
assert_eq!(smoother.next(), 10); assert_eq!(smoother.next(), 10);
// Integers are rounded, but with these values we can still test this // Integers are rounded, but with these values we can still test this
smoother.set_target(100.0, 20, false); smoother.set_target(100.0, 20);
for _ in 0..(10 - 2) { for _ in 0..(10 - 2) {
dbg!(smoother.next()); dbg!(smoother.next());
} }
@ -217,12 +221,12 @@ mod tests {
#[test] #[test]
fn logarithmic_f32_smoothing() { fn logarithmic_f32_smoothing() {
let mut smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Logarithmic(100.0)); let mut smoother: Smoother<f32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
smoother.set_target(100.0, 10.0, true); smoother.reset(10.0);
assert_eq!(smoother.next(), 10.0); assert_eq!(smoother.next(), 10.0);
// Instead of testing the actual values, we'll make sure that we reach the target values at // Instead of testing the actual values, we'll make sure that we reach the target values at
// the expected time. // the expected time.
smoother.set_target(100.0, 20.0, false); smoother.set_target(100.0, 20.0);
for _ in 0..(10 - 2) { for _ in 0..(10 - 2) {
dbg!(smoother.next()); dbg!(smoother.next());
} }
@ -233,11 +237,11 @@ mod tests {
#[test] #[test]
fn logarithmic_i32_smoothing() { fn logarithmic_i32_smoothing() {
let mut smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Logarithmic(100.0)); let mut smoother: Smoother<i32> = Smoother::new(SmoothingStyle::Logarithmic(100.0));
smoother.set_target(100.0, 10, true); smoother.reset(10);
assert_eq!(smoother.next(), 10); assert_eq!(smoother.next(), 10);
// Integers are rounded, but with these values we can still test this // Integers are rounded, but with these values we can still test this
smoother.set_target(100.0, 20, false); smoother.set_target(100.0, 20);
for _ in 0..(10 - 2) { for _ in 0..(10 - 2) {
dbg!(smoother.next()); dbg!(smoother.next());
} }