Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameters as shared values #8

Merged
merged 12 commits into from
Feb 12, 2024
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ repository = "https://github.com/SolarLiner/valib"
keywords = ["virtual-analog", "audio", "plugin", "va-modeling", "dsp"]

[workspace.dependencies]
enum-map = "2.7.3"
nih_plug = { git = "https://github.com/geom3trik/nih-plug.git", branch = "vizia-update" }
nih_plug_vizia = { git = "https://github.com/geom3trik/nih-plug.git", branch = "vizia-update" }
nalgebra = "0.32.3"


[dependencies]
az = "1.2.1"
enum-map.workspace = true
nalgebra.workspace = true
num-traits = "0.2.17"
numeric_literals = "0.2.0"
portable-atomic = { version = "1.6.0", features = ["float"] }
simba = { version = "0.8.1", features = ["wide"] }

[dev-dependencies]
Expand Down
4 changes: 3 additions & 1 deletion examples/svfmixer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ keywords.workspace = true
crate-type = ["cdylib"]

[dependencies]
nih_plug = { workspace = true }
enum-map.workspace = true
nalgebra.workspace = true
nih_plug.workspace = true
valib = { path = "../.." }
129 changes: 129 additions & 0 deletions examples/svfmixer/src/dsp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use enum_map::{enum_map, Enum, EnumMap};
use nalgebra::SMatrix;
use nih_plug::util::db_to_gain_fast;
use valib::dsp::blocks::ModMatrix;
use valib::dsp::parameter::{HasParameters, Parameter, SmoothedParam};
use valib::dsp::DSP;
use valib::filters::svf::Svf;
use valib::oversample::Oversampled;
use valib::saturators::{Clipper, Saturator, Slew};
use valib::simd::{AutoSimd, SimdValue};
use valib::Scalar;

type Sample = AutoSimd<[f32; 2]>;

pub type Dsp = Oversampled<Sample, DspInner>;

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Enum)]
pub enum DspParam {
Drive,
Cutoff,
Resonance,
LpGain,
BpGain,
HpGain,
}

type Filter = Svf<Sample, OpAmp<Sample>>;

pub struct DspInner {
params: EnumMap<DspParam, SmoothedParam>,
filter: Filter,
mod_matrix: ModMatrix<Sample, 3, 1>,
}

impl DspInner {
pub(crate) fn set_samplerate(&mut self, samplerate: f32) {
for (_, param) in self.params.iter_mut() {
param.set_samplerate(samplerate);
}
self.filter.set_samplerate(samplerate);
}
}

impl DspInner {
pub fn new(samplerate: f32) -> Self {
let params = enum_map! {
DspParam::Drive => Parameter::new(1.0).named("Drive").smoothed_linear(samplerate, 10.0),
DspParam::Cutoff => Parameter::new(3000.0).named("Cutoff").smoothed_linear(samplerate, 1e-6),
DspParam::Resonance => Parameter::new(0.5).named("Resonance").smoothed_linear(samplerate, 10.0),
DspParam::LpGain => Parameter::new(1.0).named("LP Gain").smoothed_linear(samplerate, 10.0),
DspParam::BpGain => Parameter::new(0.0).named("BP Gain").smoothed_linear(samplerate, 10.0),
DspParam::HpGain => Parameter::new(0.0).named("HP Gain").smoothed_linear(samplerate, 10.0),
};
let filter = Filter::new(
Sample::splat(samplerate),
Sample::splat(3000.0),
Sample::splat(0.5),
);
let mod_matrix = ModMatrix {
weights: SMatrix::<_, 1, 3>::new(
Sample::splat(1.0),
Sample::splat(0.0),
Sample::splat(0.0),
),
..ModMatrix::default()
};
Self {
params,
filter,
mod_matrix,
}
}
}

impl HasParameters for DspInner {
type Enum = DspParam;

fn get_parameter(&self, param: Self::Enum) -> &Parameter {
&self.params[param].param
}
}

impl DSP<1, 1> for DspInner {
type Sample = Sample;

fn process(&mut self, [x]: [Self::Sample; 1]) -> [Self::Sample; 1] {
self.filter
.set_cutoff(Sample::splat(self.params[DspParam::Cutoff].next_sample()));
self.filter.set_r(Sample::splat(
1.0 - self.params[DspParam::Resonance].next_sample(),
));
self.mod_matrix.weights.x = Sample::splat(self.params[DspParam::LpGain].next_sample());
self.mod_matrix.weights.y = Sample::splat(self.params[DspParam::BpGain].next_sample());
self.mod_matrix.weights.z = Sample::splat(self.params[DspParam::HpGain].next_sample());

let drive = Sample::splat(db_to_gain_fast(self.params[DspParam::Drive].next_sample()));
let [out] = self.mod_matrix.process(self.filter.process([x * drive]));
[out / drive]
}
}

#[derive(Debug, Clone, Copy)]
struct OpAmp<T>(Clipper, Slew<T>);

impl<T: Scalar> Default for OpAmp<T> {
fn default() -> Self {
Self(Default::default(), Default::default())
}
}

impl<T: Scalar> Saturator<T> for OpAmp<T>
where
Clipper: Saturator<T>,
Slew<T>: Saturator<T>,
{
fn saturate(&self, x: T) -> T {
self.1.saturate(self.0.saturate(x))
}

fn sat_diff(&self, x: T) -> T {
self.0.sat_diff(x) * self.1.sat_diff(self.0.saturate(x))
}

fn update_state(&mut self, x: T, y: T) {
let xc = self.0.saturate(x);
self.0.update_state(x, xc);
self.1.update_state(xc, y);
}
}
Loading
Loading