#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub mod auto_pan;
pub mod barrel_lens;
pub mod blend;
pub mod chorus;
pub mod color_grade;
pub mod composite;
pub mod compressor;
pub mod compressor_look;
pub mod deesser;
pub mod delay;
pub mod delay_line;
pub mod distort;
pub mod distortion;
pub mod ducking;
pub mod dynamics;
pub mod eq;
pub mod filter;
pub mod filter_bank;
pub mod flanger;
pub mod glitch;
pub mod keying;
pub mod luma_key;
pub mod modulation;
pub mod pitch;
pub mod reverb;
pub mod reverb_hall;
pub mod ring_mod;
pub mod room_reverb;
pub mod saturation;
pub mod spatial_audio;
pub mod stereo_widener;
pub mod tape_echo;
pub mod time_stretch;
pub mod transient_shaper;
pub mod tremolo;
pub mod utils;
pub mod vibrato;
pub mod video;
pub mod vocoder;
pub mod warp;
pub mod waveshaper;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum EffectError {
#[error("Invalid parameter: {0}")]
InvalidParameter(String),
#[error("Invalid sample rate: {0}")]
InvalidSampleRate(f32),
#[error("Buffer size mismatch: expected {expected}, got {actual}")]
BufferSizeMismatch {
expected: usize,
actual: usize,
},
#[error("Insufficient buffer size: need at least {required}, got {actual}")]
InsufficientBuffer {
required: usize,
actual: usize,
},
#[error("Effect not initialized")]
NotInitialized,
#[error("Processing error: {0}")]
ProcessingError(String),
}
pub type Result<T> = std::result::Result<T, EffectError>;
pub trait AudioEffect {
fn process_sample(&mut self, input: f32) -> f32;
fn process(&mut self, buffer: &mut [f32]) {
for sample in buffer {
*sample = self.process_sample(*sample);
}
}
fn process_stereo(&mut self, left: &mut [f32], right: &mut [f32]) {
let len = left.len().min(right.len());
for i in 0..len {
let (l, r) = self.process_sample_stereo(left[i], right[i]);
left[i] = l;
right[i] = r;
}
}
fn process_sample_stereo(&mut self, left: f32, right: f32) -> (f32, f32) {
(self.process_sample(left), self.process_sample(right))
}
fn reset(&mut self);
fn latency_samples(&self) -> usize {
0
}
fn set_sample_rate(&mut self, _sample_rate: f32) {}
}
#[derive(Debug, Clone)]
pub struct ReverbConfig {
pub room_size: f32,
pub damping: f32,
pub wet: f32,
pub dry: f32,
pub width: f32,
pub predelay_ms: f32,
}
impl Default for ReverbConfig {
fn default() -> Self {
Self {
room_size: 0.5,
damping: 0.5,
wet: 0.33,
dry: 0.67,
width: 1.0,
predelay_ms: 0.0,
}
}
}
impl ReverbConfig {
#[must_use]
pub fn new(room_size: f32, damping: f32, wet: f32) -> Self {
Self {
room_size: room_size.clamp(0.0, 1.0),
damping: damping.clamp(0.0, 1.0),
wet: wet.clamp(0.0, 1.0),
dry: (1.0 - wet).clamp(0.0, 1.0),
width: 1.0,
predelay_ms: 0.0,
}
}
#[must_use]
pub fn with_room_size(mut self, room_size: f32) -> Self {
self.room_size = room_size.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn with_damping(mut self, damping: f32) -> Self {
self.damping = damping.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn with_wet(mut self, wet: f32) -> Self {
self.wet = wet.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn with_dry(mut self, dry: f32) -> Self {
self.dry = dry.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn with_width(mut self, width: f32) -> Self {
self.width = width.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn with_predelay(mut self, predelay_ms: f32) -> Self {
self.predelay_ms = predelay_ms.max(0.0);
self
}
#[must_use]
pub fn small_room() -> Self {
Self::new(0.3, 0.4, 0.2)
}
#[must_use]
pub fn medium_room() -> Self {
Self::new(0.5, 0.5, 0.3)
}
#[must_use]
pub fn hall() -> Self {
Self::new(0.8, 0.6, 0.4).with_predelay(20.0)
}
#[must_use]
pub fn cathedral() -> Self {
Self::new(0.95, 0.7, 0.5).with_predelay(40.0)
}
#[must_use]
pub fn chamber() -> Self {
Self::new(0.6, 0.4, 0.35).with_predelay(10.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reverb_config_defaults() {
let config = ReverbConfig::default();
assert_eq!(config.room_size, 0.5);
assert_eq!(config.damping, 0.5);
assert_eq!(config.wet, 0.33);
}
#[test]
fn test_reverb_config_builder() {
let config = ReverbConfig::default()
.with_room_size(0.8)
.with_damping(0.6)
.with_wet(0.4);
assert_eq!(config.room_size, 0.8);
assert_eq!(config.damping, 0.6);
assert_eq!(config.wet, 0.4);
}
#[test]
fn test_reverb_config_clamping() {
let config = ReverbConfig::new(1.5, -0.5, 2.0);
assert_eq!(config.room_size, 1.0);
assert_eq!(config.damping, 0.0);
assert_eq!(config.wet, 1.0);
}
#[test]
fn test_reverb_presets() {
let small = ReverbConfig::small_room();
assert!(small.room_size < 0.5);
let hall = ReverbConfig::hall();
assert!(hall.room_size > 0.7);
assert!(hall.predelay_ms > 0.0);
}
}