101 lines
2.4 KiB
Rust
101 lines
2.4 KiB
Rust
//! Drive effects: waveshapers and bit crusher.
|
|
|
|
use super::Effect;
|
|
|
|
pub struct Distortion {
|
|
drive: f32,
|
|
output: f32,
|
|
}
|
|
|
|
impl Distortion {
|
|
pub fn new(drive: f32, output: f32) -> Self {
|
|
Self { drive, output }
|
|
}
|
|
}
|
|
|
|
impl Effect for Distortion {
|
|
fn process(&mut self, mono: &mut [f32]) {
|
|
for s in mono.iter_mut() {
|
|
*s = (*s * self.drive).tanh() * self.output;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Overdrive {
|
|
drive: f32,
|
|
output: f32,
|
|
}
|
|
|
|
impl Overdrive {
|
|
pub fn new(drive: f32, output: f32) -> Self {
|
|
Self {
|
|
drive: drive.max(0.01),
|
|
output,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Effect for Overdrive {
|
|
fn process(&mut self, mono: &mut [f32]) {
|
|
let d = self.drive;
|
|
let o = self.output;
|
|
for s in mono.iter_mut() {
|
|
*s = ((*s * d).atan() / d) * o;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Bitcrush {
|
|
bits: u8,
|
|
sample_rate_div: u32,
|
|
/// Max boost applied to quiet input (auto-level normalization).
|
|
max_gain: f32,
|
|
/// Target peak level after normalization.
|
|
target: f32,
|
|
gain_smooth: f32,
|
|
hold: f32,
|
|
count: u32,
|
|
}
|
|
|
|
impl Bitcrush {
|
|
/// `max_gain`/`target` normalize each block before quantization so the
|
|
/// effect works on quiet mics without clipping loud ones.
|
|
pub fn new(bits: u8, sample_rate_div: u32, max_gain: f32, target: f32) -> Self {
|
|
Self {
|
|
bits: bits.max(2),
|
|
sample_rate_div: sample_rate_div.max(1),
|
|
max_gain: max_gain.max(1.0),
|
|
target: target.clamp(0.1, 1.0),
|
|
gain_smooth: 1.0,
|
|
hold: 0.0,
|
|
count: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Effect for Bitcrush {
|
|
fn process(&mut self, mono: &mut [f32]) {
|
|
if mono.is_empty() {
|
|
return;
|
|
}
|
|
let levels = (1i32 << (self.bits - 1)) as f32;
|
|
|
|
let peak = mono.iter().fold(0.0f32, |m, s| m.max(s.abs()));
|
|
let gain = if peak > 1e-6 {
|
|
(self.target / peak).clamp(1.0, self.max_gain)
|
|
} else {
|
|
self.max_gain
|
|
};
|
|
self.gain_smooth += (gain - self.gain_smooth) * 0.3;
|
|
let g = self.gain_smooth;
|
|
|
|
for s in mono.iter_mut() {
|
|
self.count = (self.count + 1) % self.sample_rate_div;
|
|
if self.count == 0 {
|
|
self.hold = *s;
|
|
}
|
|
let q = (self.hold * g * levels).round();
|
|
*s = (q / levels).clamp(-1.0, 1.0);
|
|
}
|
|
}
|
|
}
|