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;
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 {

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
// unwrap all of those options is not going to be very fun.
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.
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;
if reset {
self.current = self.target;
self.steps_left = 0;
} else {
self.steps_left = match self.style {
SmoothingStyle::None => 1,
SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => {
(sample_rate * time / 1000.0).round() as u32
}
};
self.step_size = match self.style {
SmoothingStyle::None => 0.0,
SmoothingStyle::Linear(_) => (self.target - self.current) / self.steps_left as f32,
SmoothingStyle::Logarithmic(_) => {
// 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())
}
};
}
self.steps_left = match self.style {
SmoothingStyle::None => 1,
SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => {
(sample_rate * time / 1000.0).round() as u32
}
};
self.step_size = match self.style {
SmoothingStyle::None => 0.0,
SmoothingStyle::Linear(_) => (self.target - self.current) / self.steps_left as f32,
SmoothingStyle::Logarithmic(_) => {
// 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
@ -133,29 +135,31 @@ impl Smoother<f32> {
}
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;
if reset {
self.current = self.target as f32;
self.steps_left = 0;
} else {
self.steps_left = match self.style {
SmoothingStyle::None => 1,
SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => {
(sample_rate * time / 1000.0).round() as u32
}
};
self.step_size = match self.style {
SmoothingStyle::None => 0.0,
SmoothingStyle::Linear(_) => {
(self.target as f32 - self.current) / self.steps_left as f32
}
SmoothingStyle::Logarithmic(_) => {
nih_debug_assert_ne!(self.current, 0.0);
(self.target as f32 / self.current).powf((self.steps_left as f32).recip())
}
};
}
self.steps_left = match self.style {
SmoothingStyle::None => 1,
SmoothingStyle::Linear(time) | SmoothingStyle::Logarithmic(time) => {
(sample_rate * time / 1000.0).round() as u32
}
};
self.step_size = match self.style {
SmoothingStyle::None => 0.0,
SmoothingStyle::Linear(_) => {
(self.target as f32 - self.current) / self.steps_left as f32
}
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)]
@ -186,12 +190,12 @@ mod tests {
#[test]
fn linear_f32_smoothing() {
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);
// Instead of testing the actual values, we'll make sure that we reach the target values at
// the expected time.
smoother.set_target(100.0, 20.0, false);
smoother.set_target(100.0, 20.0);
for _ in 0..(10 - 2) {
dbg!(smoother.next());
}
@ -202,11 +206,11 @@ mod tests {
#[test]
fn linear_i32_smoothing() {
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);
// 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) {
dbg!(smoother.next());
}
@ -217,12 +221,12 @@ mod tests {
#[test]
fn logarithmic_f32_smoothing() {
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);
// Instead of testing the actual values, we'll make sure that we reach the target values at
// the expected time.
smoother.set_target(100.0, 20.0, false);
smoother.set_target(100.0, 20.0);
for _ in 0..(10 - 2) {
dbg!(smoother.next());
}
@ -233,11 +237,11 @@ mod tests {
#[test]
fn logarithmic_i32_smoothing() {
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);
// 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) {
dbg!(smoother.next());
}