use serde::{Deserialize, Serialize};
use crate::error::{GhurniError, Result};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct DcBlocker {
x_prev: f32,
y_prev: f32,
r: f32,
}
impl DcBlocker {
#[inline]
pub fn new(sample_rate: f32) -> Self {
Self {
x_prev: 0.0,
y_prev: 0.0,
r: (1.0 - (core::f32::consts::TAU * 10.0 / sample_rate)).clamp(0.9, 0.9999),
}
}
#[inline]
pub fn process(&mut self, x: f32) -> f32 {
let y = x - self.x_prev + self.r * self.y_prev;
self.x_prev = x;
self.y_prev = y;
y
}
}
#[inline]
pub(crate) fn validate_sample_rate(sample_rate: f32) -> Result<()> {
if sample_rate <= 0.0 || sample_rate.is_nan() || sample_rate.is_infinite() {
#[cfg(feature = "logging")]
tracing::warn!(%sample_rate, "invalid sample rate");
return Err(GhurniError::InvalidParameter(alloc::format!(
"sample_rate must be positive and finite, got {sample_rate}"
)));
}
Ok(())
}
#[inline]
pub(crate) fn validate_duration(duration: f32) -> Result<()> {
if duration <= 0.0 || duration.is_nan() || duration.is_infinite() {
#[cfg(feature = "logging")]
tracing::warn!(%duration, "invalid duration");
return Err(GhurniError::InvalidParameter(alloc::format!(
"duration must be positive and finite, got {duration}"
)));
}
Ok(())
}
#[cfg(feature = "naad-backend")]
#[allow(unused_variables, dead_code)]
pub(crate) fn naad_init_error(
synth_name: &str,
component: &str,
err: impl core::fmt::Display,
) -> GhurniError {
#[cfg(feature = "logging")]
tracing::error!(synth = synth_name, component, %err, "naad backend error");
GhurniError::SynthesisFailed(alloc::format!("{err}"))
}