Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Commit

Permalink
feat: add crossover distortion to clipping stage
Browse files Browse the repository at this point in the history
  • Loading branch information
SolarLiner committed Sep 2, 2024
1 parent ed7f164 commit bc10077
Show file tree
Hide file tree
Showing 4 changed files with 4,257 additions and 4,101 deletions.
60 changes: 56 additions & 4 deletions src/dsp/clipping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use nih_plug::prelude::AtomicF32;
use nih_plug::util::db_to_gain_fast;
use num_traits::{Float, ToPrimitive};
use std::sync::{atomic::Ordering, Arc};
use valib::math::smooth_clamp;
use numeric_literals::replace_float_literals;
use valib::math::{smooth_clamp, smooth_max, smooth_min};
use valib::saturators::clippers::DiodeClipper;
use valib::saturators::Slew;
use valib::simd::SimdComplexField;
use valib::saturators::{Saturator, Slew};
use valib::simd::{SimdComplexField, SimdValue};
use valib::util::lerp;
use valib::wdf::dsl::*;
use valib::{
Expand All @@ -16,6 +17,41 @@ use valib::{
Scalar,
};

struct CrossoverDistortion<T> {
pub t: T,
pub drift: T,
}

impl<T: Scalar> CrossoverDistortion<T> {
pub fn new(drift: T) -> Self {
Self {
t: T::from_f64(1e-1),
drift,
}
}

pub fn from_age(age: T) -> Self {
Self::new(Self::drift_from_age(age))
}

pub fn set_age(&mut self, age: T) {
self.drift = Self::drift_from_age(age);
}

#[replace_float_literals(T::from_f64(literal))]
fn drift_from_age(age: T) -> T {
2.96e-3 * age.simd_powf(1./3.)
}
}

impl<T: Scalar> Saturator<T> for CrossoverDistortion<T> {
fn saturate(&self, x: T) -> T {
let l0 = x + self.drift;
let l1 = x - self.drift;
l0.simd_min(T::zero().simd_max(l1))
}
}

type Stage1Module<T> = WdfModule<
ResistiveVoltageSource<T>,
Series<Capacitor<T>, Series<Resistor<T>, ResistiveVoltageSource<T>>>,
Expand Down Expand Up @@ -181,6 +217,7 @@ pub struct ClippingStage<T: Scalar<Element: Float>> {
pub(crate) led_rms: Rms<f32>,
pub(crate) led_display: Arc<AtomicF32>,
samplerate: T,
crossover: CrossoverDistortion<T>,
}

impl<T: Scalar<Element: Float>> ClippingStage<T> {
Expand All @@ -196,11 +233,13 @@ impl<T: Scalar<Element: Float>> ClippingStage<T> {
stage3: Stage3::new(samplerate),
led_rms: Rms::new(rms_samples),
led_display: Arc::new(AtomicF32::new(0.0)),
crossover: CrossoverDistortion::new(T::zero()),
samplerate,
}
}

pub fn set_age(&mut self, age: T) {
self.crossover.set_age(age);
self.out_slew.max_diff =
component_matching_slew_rate(self.samplerate, age);
}
Expand Down Expand Up @@ -244,11 +283,13 @@ impl<T: Scalar<Element: ToPrimitive + Float>> DSPProcess<1, 1> for ClippingStage
.to_f32()
.unwrap_or_default()
* 0.5;
let led_value = led_value.select(led_value.is_finite(), 0.);
let led_value = self.led_rms.add_element(led_value);
self.led_display.store(led_value, Ordering::Relaxed);
let vout = self.crossover.saturate(vplus + vf - T::from_f64(4.5)) + T::from_f64(4.5);
self.out_slew.process([smooth_clamp(
T::from_f64(0.1),
vplus + vf,
vout,
T::zero(),
T::from_f64(9.),
)])
Expand All @@ -267,6 +308,17 @@ mod tests {
use valib::dsp::buffer::{AudioBufferMut, AudioBufferRef};
use valib::dsp::{BlockAdapter, DSPProcessBlock};

#[test]
fn crossover_dc_sweep() {
const N: usize = 100;
let crossover = CrossoverDistortion::new(1.);
let output: [f32; N] = std::array::from_fn(|i| {
let x = lerp(i as f32 / N as f32, -5., 5.);
crossover.saturate(x)
});
insta::assert_csv_snapshot!(&output as &[_], { "[]" => insta::rounded_redaction(4) });
}

#[test]
fn drive_test() {
const SAMPLERATE: f64 = 1024.;
Expand Down
104 changes: 104 additions & 0 deletions src/dsp/snapshots/ts404__dsp__clipping__tests__crossover_dc_sweep.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
source: src/dsp/clipping.rs
expression: "&output as &[_]"
---
-4.0
-3.9
-3.8
-3.7
-3.6
-3.5
-3.4
-3.3
-3.2
-3.1
-3.0
-2.9
-2.8
-2.7
-2.6
-2.5
-2.4
-2.3
-2.2
-2.1
-2.0
-1.9
-1.8
-1.7
-1.6
-1.5
-1.4
-1.3
-1.2
-1.1
-1.0
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.1
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
2.0
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
3.0
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
Loading

0 comments on commit bc10077

Please sign in to comment.