137 lines
2.8 KiB
Rust
137 lines
2.8 KiB
Rust
use std::fmt;
|
|
|
|
use crate::{
|
|
Smooth,
|
|
SmoothStatus
|
|
};
|
|
|
|
const DECLICK_SETTLE: f32 = 0.001;
|
|
|
|
pub struct DeclickOutput<'a, T> {
|
|
pub from: &'a T,
|
|
pub to: &'a T,
|
|
|
|
pub fade: &'a [f32],
|
|
pub status: SmoothStatus
|
|
}
|
|
|
|
pub struct Declick<T: Sized + Clone> {
|
|
current: T,
|
|
next: Option<T>,
|
|
staged: Option<T>,
|
|
|
|
fade: Smooth<f32>
|
|
}
|
|
|
|
impl<T> Declick<T>
|
|
where T: Sized + Clone + Eq
|
|
{
|
|
pub fn new(initial: T) -> Self {
|
|
Self {
|
|
current: initial,
|
|
next: None,
|
|
staged: None,
|
|
|
|
fade: Smooth::new(0.0)
|
|
}
|
|
}
|
|
|
|
pub fn reset(&mut self, to: T) {
|
|
self.current = to;
|
|
self.next = None;
|
|
self.staged = None;
|
|
|
|
self.fade.reset(0.0);
|
|
}
|
|
|
|
pub fn set(&mut self, to: T) {
|
|
if self.dest() == &to {
|
|
return
|
|
}
|
|
|
|
if self.next.is_none() {
|
|
self.next = Some(to);
|
|
|
|
self.fade.reset(0.0);
|
|
self.fade.set(1.0);
|
|
} else {
|
|
self.staged = Some(to);
|
|
}
|
|
}
|
|
|
|
pub fn set_speed_ms(&mut self, sample_rate: f32, ms: f32) {
|
|
self.fade.set_speed_ms(sample_rate, ms);
|
|
}
|
|
|
|
#[inline]
|
|
pub fn output(&self) -> DeclickOutput<T> {
|
|
let fade = self.fade.output();
|
|
|
|
DeclickOutput {
|
|
from: &self.current,
|
|
to: self.next.as_ref().unwrap_or(&self.current),
|
|
|
|
fade: fade.values,
|
|
status: fade.status
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn current_value(&self) -> DeclickOutput<T> {
|
|
let fade = self.fade.current_value();
|
|
|
|
DeclickOutput {
|
|
from: &self.current,
|
|
to: self.next.as_ref().unwrap_or(&self.current),
|
|
|
|
fade: fade.values,
|
|
status: fade.status
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn dest(&self) -> &T {
|
|
self.staged.as_ref()
|
|
.or_else(|| self.next.as_ref())
|
|
.unwrap_or(&self.current)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn is_active(&self) -> bool {
|
|
self.next.is_some()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn process(&mut self, nframes: usize) {
|
|
self.fade.process(nframes);
|
|
}
|
|
|
|
pub fn update_status(&mut self) {
|
|
if !self.is_active() {
|
|
return;
|
|
}
|
|
|
|
self.fade.update_status_with_epsilon(DECLICK_SETTLE);
|
|
|
|
if self.fade.is_active() {
|
|
return;
|
|
}
|
|
|
|
self.current = self.next.take().unwrap();
|
|
self.next = self.staged.take();
|
|
}
|
|
}
|
|
|
|
impl<T> fmt::Debug for Declick<T>
|
|
where T: fmt::Debug + Sized + Clone
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct(concat!("Declick<", stringify!(T), ">"))
|
|
.field("current", &self.current)
|
|
.field("next", &self.next)
|
|
.field("staged", &self.staged)
|
|
.field("fade", &self.fade)
|
|
.finish()
|
|
}
|
|
}
|