#![forbid(unsafe_code)]
pub mod limiter;
pub mod meter;
pub mod resample;
pub use limiter::{Config, Limiter, Link, Output, limit};
pub use meter::{
ChannelSamplePeak, SamplePeak, TruePeak, sample_peak, sample_peak_with_control, true_peak,
true_peak_per_channel, true_peak_per_channel_with_control, true_peak_with_control,
};
pub use resample::{Downsampler, Upsampler};
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum Error {
#[error("operation cancelled")]
Cancelled,
#[error("invalid configuration: {0}")]
InvalidConfig(String),
#[error("invalid input: {0}")]
InvalidInput(String),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Progress {
pub pass: u32,
pub done_samples: usize,
pub total_samples: usize,
}
pub(crate) const BLOCK: usize = 1024;
pub(crate) fn validate_rate(sample_rate_hz: u32) -> Result<(), Error> {
if matches!(
sample_rate_hz,
44100 | 48000 | 88200 | 96000 | 176400 | 192000
) {
Ok(())
} else {
Err(Error::InvalidInput(format!(
"unsupported sample_rate_hz: {sample_rate_hz}"
)))
}
}
pub(crate) fn validate_layout(channels: &[&[f32]]) -> Result<usize, Error> {
if !(1..=8).contains(&channels.len()) {
return Err(Error::InvalidInput("channel count must be 1 to 8".into()));
}
let len = channels[0].len();
if channels.iter().any(|channel| channel.len() != len) {
return Err(Error::InvalidInput("channel lengths differ".into()));
}
Ok(len)
}
pub(crate) fn quantize_sample(sample: f32, bit_depth: u8) -> f32 {
let scale = 2.0_f64.powi(bit_depth as i32 - 1);
((sample as f64 * scale).round().clamp(-scale, scale - 1.0) / scale) as f32
}