Restructured project for separate plugins

This commit is contained in:
Ebu
2025-12-04 09:34:55 +01:00
parent 3cf22b7189
commit 28f14ba713
29 changed files with 364 additions and 248 deletions

127
dsp/src/comp.rs Normal file
View File

@@ -0,0 +1,127 @@
use crate::{
Ratio, SampleRate, amplitude::Amplitude, decibel::Decibel, ring_buffer::RingBuffer, rms, smoother::Smoother, traits::Processor
};
use std::time::Duration;
#[derive(Debug, Default, Clone, Copy)]
pub enum CompressorPeakMode {
#[default]
Sample,
RMS,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct CompressorState {
pub peak_mode: CompressorPeakMode,
pub threshold: Decibel,
pub ratio: Ratio,
pub gain: Decibel,
pub attack: Duration,
pub release: Duration,
pub last_rms: f64,
pub input_db: Decibel,
pub output_static_db: Decibel,
pub gain_db: Decibel,
pub gain_smoothed_db: Decibel,
pub final_gain_db: Decibel,
}
impl CompressorState {
pub fn new() -> Self {
Self {
peak_mode: CompressorPeakMode::Sample,
threshold: Decibel::from(-24.0),
ratio: Ratio(1.0, 3.0),
gain: Decibel::from(0.0),
attack: Duration::from_millis(25),
release: Duration::from_millis(100),
last_rms: 0.0,
input_db: Decibel::from(0.0),
output_static_db: Decibel::from(0.0),
gain_db: Decibel::from(0.0),
gain_smoothed_db: Decibel::from(0.0),
final_gain_db: Decibel::from(0.0),
}
}
}
pub struct Compressor {
pub state: CompressorState,
sample_buffer: RingBuffer<f64, 2048>,
smoother: Smoother,
}
impl Compressor {
pub fn new(sample_rate: SampleRate) -> Self {
Self::from_state(sample_rate, CompressorState::default())
}
pub fn from_state(sample_rate: SampleRate, state: CompressorState) -> Self {
Self {
sample_buffer: RingBuffer::new(0.0),
smoother: Smoother::new(sample_rate),
state,
}
}
pub fn set_threshold<T>(&mut self, threshold: T)
where
T: Into<Decibel>,
{
self.state.threshold = threshold.into();
}
pub fn set_attack<T>(&mut self, attack: T)
where
T: Into<Duration>,
{
self.smoother.set_attack(attack);
}
pub fn set_release<T>(&mut self, release: T)
where
T: Into<Duration>,
{
self.smoother.set_release(release);
}
pub fn set_ratio<R>(&mut self, ratio: R)
where
R: Into<Ratio>,
{
self.state.ratio = ratio.into();
}
pub fn set_gain<T>(&mut self, gain: T)
where
T: Into<Decibel>,
{
self.state.gain = gain.into();
}
}
impl Processor for Compressor {
fn process(&mut self, sample: f64) -> f64 {
self.sample_buffer[0] = sample;
self.state.input_db = Decibel::from(Amplitude(match self.state.peak_mode {
CompressorPeakMode::Sample => sample.abs() + f64::EPSILON,
CompressorPeakMode::RMS => {
self.state.last_rms = rms(&self.sample_buffer, self.state.last_rms);
self.state.last_rms.abs().sqrt() + f64::EPSILON
}
}));
self.state.output_static_db = if self.state.input_db < self.state.threshold {
self.state.input_db
} else {
self.state.threshold
+ (self.state.input_db - self.state.threshold) * self.state.ratio.multiplier()
};
self.state.gain_db = self.state.output_static_db - self.state.input_db;
self.state.gain_smoothed_db = if self.state.gain_db < self.state.gain_smoothed_db {
self.smoother.attack(self.state.gain_db)
} else {
self.smoother.release(self.state.gain_db)
};
self.state.final_gain_db = self.state.gain_smoothed_db + self.state.gain;
self.sample_buffer.shift();
sample * self.state.final_gain_db
}
}