#[deny(missing_copy_implementations)]
#[deny(missing_docs)]
extern crate envelope_detector;
extern crate time_calc as time;
use envelope_detector::{EnvelopeDetector, Frame, Sample};
use std::marker::PhantomData;
use time::Ms;
pub mod detector;
pub mod even_gain_fn;
#[cfg(feature = "dsp-chain")]
pub mod dsp_node;
pub use detector::{Detector, PeakEnvelopeDetector, RmsEnvelopeDetector};
pub use even_gain_fn::{EvenGainFunction, Average, Minimum};
#[derive(Clone, Debug)]
pub struct Compressor<F, D, EGF> {
envelope_detector: D,
attack_ms: Ms,
release_ms: Ms,
pub threshold: f32,
slope: f32,
even_gain_fn: PhantomData<EGF>,
frame: PhantomData<F>,
}
pub type PeakCompressor<F, EGF> = Compressor<F, PeakEnvelopeDetector<F>, EGF>;
pub type PeakAvgCompressor<F> = PeakCompressor<F, Average>;
pub type PeakMinCompressor<F> = PeakCompressor<F, Minimum>;
pub type RmsCompressor<F, EGF> = Compressor<F, RmsEnvelopeDetector<F>, EGF>;
pub type RmsAvgCompressor<F> = RmsCompressor<F, Average>;
pub type RmsMinCompressor<F> = RmsCompressor<F, Minimum>;
fn calc_slope(ratio: f32) -> f32 {
1.0 - (1.0 / ratio)
}
impl<F, D, EGF> Compressor<F, D, EGF>
where F: Frame,
D: Detector<F>,
EGF: EvenGainFunction,
{
fn new(detector: D, attack_ms: Ms, release_ms: Ms, threshold: f32, ratio: f32) -> Self {
let slope = calc_slope(ratio);
Compressor {
envelope_detector: detector,
attack_ms: attack_ms,
release_ms: release_ms,
threshold: threshold,
slope: slope,
even_gain_fn: std::marker::PhantomData,
frame: std::marker::PhantomData,
}
}
pub fn set_attack_ms<M: Into<Ms>>(&mut self, ms: M, sample_hz: f64) {
let ms: Ms = ms.into();
self.attack_ms = ms;
self.update_attack_to_sample_hz(sample_hz);
}
pub fn set_release_ms<M: Into<Ms>>(&mut self, ms: M, sample_hz: f64) {
let ms: Ms = ms.into();
self.release_ms = ms;
self.update_release_to_sample_hz(sample_hz);
}
pub fn update_attack_to_sample_hz(&mut self, sample_hz: f64) {
let frames = self.attack_ms.samples(sample_hz) as f32;
self.envelope_detector.detector().set_attack_frames(frames);
}
pub fn update_release_to_sample_hz(&mut self, sample_hz: f64) {
let frames = self.release_ms.samples(sample_hz) as f32;
self.envelope_detector.detector().set_release_frames(frames);
}
pub fn next_gain_per_channel(&mut self, next_frame: F) -> F::Float {
let threshold = self.threshold.to_sample();
let slope = self.slope.to_sample();
let identity = <F::Sample as Sample>::identity();
let env_frame = self.envelope_detector.detector().next(next_frame).to_float_frame();
env_frame.map(|s| {
let s = if s > identity { identity } else { s }; if s > threshold { identity - (s - threshold) * slope } else { identity }
})
}
#[inline]
pub fn next_gain(&mut self, next_frame: F) -> <F::Sample as Sample>::Float {
EGF::next_gain(self, next_frame)
}
#[inline]
pub fn next_frame(&mut self, next_frame: F) -> F {
let gain = self.next_gain(next_frame);
next_frame.scale_amp(gain)
}
}
impl<F, EGF> PeakCompressor<F, EGF>
where F: Frame,
EGF: EvenGainFunction,
{
pub fn peak<A, R>(attack_ms: A,
release_ms: R,
sample_hz: f64,
threshold: f32,
ratio: f32) -> Self
where A: Into<Ms>,
R: Into<Ms>,
{
let attack_ms: Ms = attack_ms.into();
let release_ms: Ms = release_ms.into();
let attack_frames = attack_ms.samples(sample_hz) as f32;
let release_frames = release_ms.samples(sample_hz) as f32;
let envelope_detector = EnvelopeDetector::peak(attack_frames, release_frames);
Compressor::new(envelope_detector, attack_ms, release_ms, threshold, ratio)
}
}
impl<F> PeakAvgCompressor<F>
where F: Frame,
{
pub fn peak_avg<A, R>(attack_ms: A,
release_ms: R,
sample_hz: f64,
threshold: f32,
ratio: f32) -> Self
where A: Into<Ms>,
R: Into<Ms>,
{
Self::peak(attack_ms, release_ms, sample_hz, threshold, ratio)
}
}
impl<F> PeakMinCompressor<F>
where F: Frame,
{
pub fn peak_min<A, R>(attack_ms: A,
release_ms: R,
sample_hz: f64,
threshold: f32,
ratio: f32) -> Self
where A: Into<Ms>,
R: Into<Ms>,
{
Self::peak(attack_ms, release_ms, sample_hz, threshold, ratio)
}
}
impl<F, EGF> RmsCompressor<F, EGF>
where F: Frame,
EGF: EvenGainFunction,
{
pub fn rms<W, A, R>(window_ms: W,
attack_ms: A,
release_ms: R,
sample_hz: f64,
threshold: f32,
ratio: f32) -> Self
where W: Into<Ms>,
A: Into<Ms>,
R: Into<Ms>,
{
let window_ms: Ms = window_ms.into();
let attack_ms: Ms = attack_ms.into();
let release_ms: Ms = release_ms.into();
let window_frames = window_ms.samples(sample_hz) as usize;
let attack_frames = attack_ms.samples(sample_hz) as f32;
let release_frames = release_ms.samples(sample_hz) as f32;
let envelope_detector = EnvelopeDetector::rms(window_frames, attack_frames, release_frames);
let rms_envelope_detector = RmsEnvelopeDetector {
rms: envelope_detector,
window_ms: window_ms,
};
Compressor::new(rms_envelope_detector, attack_ms, release_ms, threshold, ratio)
}
pub fn set_window_ms<M: Into<Ms>>(&mut self, ms: M, sample_hz: f64) {
let ms: Ms = ms.into();
self.envelope_detector.window_ms = ms;
self.update_window_to_sample_hz(sample_hz);
}
pub fn update_window_to_sample_hz(&mut self, sample_hz: f64) {
let frames = self.envelope_detector.window_ms.samples(sample_hz) as usize;
self.envelope_detector.rms.set_window_frames(frames);
}
}
impl<F> RmsAvgCompressor<F>
where F: Frame,
{
pub fn rms_avg<W, A, R>(window_ms: W,
attack_ms: A,
release_ms: R,
sample_hz: f64,
threshold: f32,
ratio: f32) -> Self
where W: Into<Ms>,
A: Into<Ms>,
R: Into<Ms>,
{
Self::rms(window_ms, attack_ms, release_ms, sample_hz, threshold, ratio)
}
}
impl<F> RmsMinCompressor<F>
where F: Frame,
{
pub fn rms_min<W, A, R>(window_ms: W,
attack_ms: A,
release_ms: R,
sample_hz: f64,
threshold: f32,
ratio: f32) -> Self
where W: Into<Ms>,
A: Into<Ms>,
R: Into<Ms>,
{
Self::rms(window_ms, attack_ms, release_ms, sample_hz, threshold, ratio)
}
}