use core::num::NonZeroU32;
#[cfg(not(feature = "std"))]
use bevy_platform::prelude::Vec;
use crate::{
dsp::filter::smoothing_filter::{self, SmoothingFilter, SmoothingFilterCoeff},
StreamInfo,
};
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SmootherConfig {
pub smooth_seconds: f32,
pub settle_epsilon: f32,
}
impl Default for SmootherConfig {
fn default() -> Self {
Self {
smooth_seconds: smoothing_filter::DEFAULT_SMOOTH_SECONDS,
settle_epsilon: smoothing_filter::DEFAULT_SETTLE_EPSILON,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SmoothedParam {
target_value: f32,
target_times_a: f32,
filter: SmoothingFilter,
coeff: SmoothingFilterCoeff,
smooth_secs: f32,
settle_epsilon: f32,
}
impl SmoothedParam {
pub fn new(value: f32, config: SmootherConfig, sample_rate: NonZeroU32) -> Self {
let smooth_secs = config.smooth_seconds.max(0.00001);
let settle_epsilon = config.settle_epsilon.max(f32::EPSILON);
let coeff = SmoothingFilterCoeff::new(sample_rate, smooth_secs);
Self {
target_value: value,
target_times_a: value * coeff.a0,
filter: SmoothingFilter::new(value),
coeff,
smooth_secs,
settle_epsilon,
}
}
pub fn target_value(&self) -> f32 {
self.target_value
}
pub fn set_value(&mut self, value: f32) {
self.target_value = value;
self.target_times_a = value * self.coeff.a0;
}
pub fn settle(&mut self) -> bool {
self.filter.settle(self.target_value, self.settle_epsilon)
}
pub fn is_smoothing(&self) -> bool {
!self.filter.has_settled(self.target_value)
}
pub fn has_settled(&self) -> bool {
self.filter.has_settled(self.target_value)
}
pub fn has_settled_at(&self, value: f32) -> bool {
self.target_value == value && self.filter.has_settled(self.target_value)
}
pub fn has_settled_at_or_below(&self, value: f32) -> bool {
self.target_value <= value && self.filter.has_settled(self.target_value)
}
pub fn reset_to_target(&mut self) {
self.filter = SmoothingFilter::new(self.target_value);
}
#[inline(always)]
pub fn next_smoothed(&mut self) -> f32 {
self.filter
.process_sample_a(self.target_times_a, self.coeff.b1)
}
pub fn process_into_buffer(&mut self, buffer: &mut [f32]) {
if self.is_smoothing() {
self.filter
.process_into_buffer(buffer, self.target_value, self.coeff);
self.filter.settle(self.target_value, self.settle_epsilon);
} else {
buffer.fill(self.target_value);
}
}
pub fn set_smooth_seconds(&mut self, seconds: f32, sample_rate: NonZeroU32) {
self.coeff = SmoothingFilterCoeff::new(sample_rate, seconds);
self.smooth_secs = seconds;
}
pub fn update_sample_rate(&mut self, sample_rate: NonZeroU32) {
self.coeff = SmoothingFilterCoeff::new(sample_rate, self.smooth_secs);
}
}
#[derive(Debug, Clone)]
pub struct SmoothedParamBuffer {
smoother: SmoothedParam,
buffer: Vec<f32>,
buffer_is_constant: bool,
}
impl SmoothedParamBuffer {
pub fn new(value: f32, config: SmootherConfig, stream_info: &StreamInfo) -> Self {
let mut buffer = Vec::new();
buffer.reserve_exact(stream_info.max_block_frames.get() as usize);
buffer.resize(stream_info.max_block_frames.get() as usize, value);
Self {
smoother: SmoothedParam::new(value, config, stream_info.sample_rate),
buffer,
buffer_is_constant: true,
}
}
pub fn target_value(&self) -> f32 {
self.smoother.target_value()
}
pub fn set_value(&mut self, value: f32) {
self.smoother.set_value(value);
}
pub fn reset(&mut self) {
if self.smoother.is_smoothing() || !self.buffer_is_constant {
self.buffer.fill(self.smoother.target_value);
self.buffer_is_constant = true;
}
self.smoother.reset_to_target();
}
pub fn get_buffer(&mut self, frames: usize) -> (&[f32], bool) {
self.buffer_is_constant = !self.smoother.is_smoothing();
self.smoother
.process_into_buffer(&mut self.buffer[..frames]);
(
&self.buffer[..frames],
self.buffer_is_constant || frames < 2,
)
}
pub fn is_smoothing(&self) -> bool {
self.smoother.is_smoothing()
}
pub fn has_settled(&self) -> bool {
self.smoother.has_settled()
}
pub fn has_settled_at(&self, value: f32) -> bool {
self.smoother.has_settled_at(value)
}
pub fn has_settled_at_or_below(&self, value: f32) -> bool {
self.smoother.has_settled_at_or_below(value)
}
pub fn update_stream(&mut self, stream_info: &StreamInfo) {
self.smoother.update_sample_rate(stream_info.sample_rate);
let max_block_frames = stream_info.max_block_frames.get() as usize;
if self.buffer.len() > max_block_frames {
self.buffer.resize(max_block_frames, 0.0);
} else if self.buffer.len() < max_block_frames {
self.buffer
.reserve_exact(max_block_frames - self.buffer.len());
self.buffer
.resize(max_block_frames, self.smoother.target_value());
}
}
}