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

set_samplerate method on DSP/DSPBlock #9

Merged
merged 3 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 19 additions & 20 deletions examples/ladder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,18 @@ enum Dsp {
Transistor(DspTransistor),
}
impl Dsp {
fn set_params(&mut self, samplerate: Sample, freq: Sample, q: Sample) {
fn set_params(&mut self, freq: Sample, q: Sample) {
match self {
Self::Ideal(f) => {
f.set_cutoff(samplerate, freq);
f.set_cutoff(freq);
f.set_resonance(q);
}
Self::Ota(f) => {
f.set_cutoff(samplerate, freq);
f.set_cutoff(freq);
f.set_resonance(q);
}
Self::Transistor(f) => {
f.set_cutoff(samplerate, freq);
f.set_cutoff(freq);
f.set_resonance(q);
}
}
Expand All @@ -120,14 +120,14 @@ impl DSP<1, 1> for Dsp {
}

#[derive(Debug)]
struct SvfMixerPlugin {
struct LadderFilterPlugin {
topology_changed: Arc<AtomicBool>,
params: Arc<PluginParams>,
oversample: Oversample<Sample>,
dsp: Dsp,
}
impl SvfMixerPlugin {
fn setup_filter(&mut self, samplerate: Sample) {
impl LadderFilterPlugin {
fn setup_filter(&mut self, samplerate: impl Copy + Into<f64>) {
if self
.topology_changed
.load(std::sync::atomic::Ordering::SeqCst)
Expand All @@ -153,13 +153,13 @@ impl SvfMixerPlugin {
}
}

impl Default for SvfMixerPlugin {
impl Default for LadderFilterPlugin {
fn default() -> Self {
let topology_changed = Arc::new(AtomicBool::new(false));
let params = Arc::new(PluginParams::new(topology_changed.clone()));
let fc = Sample::splat(params.fc.default_plain_value());
let q = Sample::splat(params.q.default_plain_value());
let dsp = DspIdeal::new(Sample::splat(44100.0), fc, q);
let dsp = DspIdeal::new(44100.0, fc, q);
Self {
topology_changed,
params,
Expand All @@ -169,7 +169,7 @@ impl Default for SvfMixerPlugin {
}
}

impl nih_plug::prelude::Plugin for SvfMixerPlugin {
impl Plugin for LadderFilterPlugin {
const NAME: &'static str = "Ladder filter";
const VENDOR: &'static str = "SolarLiner";
const URL: &'static str = "https://github.com/SolarLiner/valib";
Expand All @@ -188,8 +188,8 @@ impl nih_plug::prelude::Plugin for SvfMixerPlugin {
aux_outputs: &[],
},
}];
type BackgroundTask = ();
type SysExMessage = ();
type BackgroundTask = ();

fn params(&self) -> Arc<dyn Params> {
self.params.clone()
Expand All @@ -201,7 +201,7 @@ impl nih_plug::prelude::Plugin for SvfMixerPlugin {
buffer_config: &BufferConfig,
_context: &mut impl InitContext<Self>,
) -> bool {
self.setup_filter(Sample::splat(buffer_config.sample_rate * OVERSAMPLE as f32));
self.setup_filter(buffer_config.sample_rate * OVERSAMPLE as f32);
true
}

Expand All @@ -213,10 +213,9 @@ impl nih_plug::prelude::Plugin for SvfMixerPlugin {
&mut self,
buffer: &mut Buffer,
_aux: &mut AuxiliaryBuffers,
_context: &mut impl ProcessContext<Self>,
context: &mut impl ProcessContext<Self>,
) -> ProcessStatus {
let samplerate = Sample::splat(_context.transport().sample_rate * OVERSAMPLE as f32);
self.setup_filter(samplerate);
self.setup_filter(context.transport().sample_rate * OVERSAMPLE as f32);

let mut drive = [0.; MAX_BUFFER_SIZE];
let mut fc = [0.; MAX_BUFFER_SIZE];
Expand Down Expand Up @@ -253,7 +252,7 @@ impl nih_plug::prelude::Plugin for SvfMixerPlugin {
for (i, s) in os_buffer.iter_mut().enumerate() {
let fc = Sample::splat(os_fc[i]);
let q = Sample::splat(4.0 * os_q[i]);
self.dsp.set_params(samplerate, fc, q);
self.dsp.set_params(fc, q);
let drive = Sample::splat(os_drive[i]);
*s = self.dsp.process([*s * drive])[0] / drive;
}
Expand All @@ -269,7 +268,7 @@ impl nih_plug::prelude::Plugin for SvfMixerPlugin {
}
}

impl ClapPlugin for SvfMixerPlugin {
impl ClapPlugin for LadderFilterPlugin {
const CLAP_ID: &'static str = "com.github.SolarLiner.valib.LadderFilter";
const CLAP_DESCRIPTION: Option<&'static str> = None;
const CLAP_MANUAL_URL: Option<&'static str> = None;
Expand All @@ -281,7 +280,7 @@ impl ClapPlugin for SvfMixerPlugin {
];
}

impl Vst3Plugin for SvfMixerPlugin {
impl Vst3Plugin for LadderFilterPlugin {
const VST3_CLASS_ID: [u8; 16] = *b"VaLibLaddrFltSLN";
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Fx,
Expand All @@ -290,5 +289,5 @@ impl Vst3Plugin for SvfMixerPlugin {
];
}

nih_export_clap!(SvfMixerPlugin);
nih_export_vst3!(SvfMixerPlugin);
nih_export_clap!(LadderFilterPlugin);
nih_export_vst3!(LadderFilterPlugin);
2 changes: 1 addition & 1 deletion examples/svfmixer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl nih_plug::prelude::Plugin for SvfMixerPlugin {
) -> bool {
self.dsp
.left_mut()
.set_samplerate(Sample::splat(buffer_config.sample_rate * OVERSAMPLE as f32));
.set_samplerate(buffer_config.sample_rate * OVERSAMPLE as f32);
true
}

Expand Down
68 changes: 54 additions & 14 deletions src/dsp/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ impl<T: Scalar> P1<T> {
}
}

pub fn set_samplerate(&mut self, samplerate: T) {
self.w_step = T::simd_pi() / samplerate
}

pub fn set_fc(&mut self, fc: T) {
self.fc = fc;
}
Expand All @@ -130,6 +126,10 @@ impl<T: Scalar> DSP<1, 3> for P1<T> {
[lp, hp, ap]
}

fn set_samplerate(&mut self, samplerate: f32) {
self.w_step = T::simd_pi() / T::from_f64(samplerate as _)
}

fn latency(&self) -> usize {
1
}
Expand Down Expand Up @@ -172,6 +172,13 @@ macro_rules! series_tuple {
)*
x
}

fn set_samplerate(&mut self, samplerate: f32) {
let Self(($($p),*)) = self;
$(
$p.set_samplerate(samplerate);
)*
}
}
};
}
Expand Down Expand Up @@ -226,6 +233,17 @@ where
{
type Sample = A::Sample;

fn process(&mut self, x: [Self::Sample; I]) -> [Self::Sample; O] {
let Self(a, _, b) = self;
let j = a.process(x);
b.process(j)
}

fn set_samplerate(&mut self, samplerate: f32) {
self.0.set_samplerate(samplerate);
self.2.set_samplerate(samplerate);
}

fn latency(&self) -> usize {
let Self(a, _, b) = self;
a.latency() + b.latency()
Expand All @@ -236,12 +254,6 @@ where
a.reset();
b.reset();
}

fn process(&mut self, x: [Self::Sample; I]) -> [Self::Sample; O] {
let Self(a, _, b) = self;
let j = a.process(x);
b.process(j)
}
}

impl<P: DSP<N, N>, const N: usize, const C: usize> DSP<N, N> for Series<[P; C]> {
Expand All @@ -251,6 +263,12 @@ impl<P: DSP<N, N>, const N: usize, const C: usize> DSP<N, N> for Series<[P; C]>
self.0.iter_mut().fold(x, |x, dsp| dsp.process(x))
}

fn set_samplerate(&mut self, samplerate: f32) {
for s in &mut self.0 {
s.set_samplerate(samplerate);
}
}

fn latency(&self) -> usize {
self.0.iter().map(|dsp| dsp.latency()).sum()
}
Expand Down Expand Up @@ -313,6 +331,13 @@ macro_rules! parallel_tuple {
)*
ret
}

fn set_samplerate(&mut self, samplerate: f32) {
let Self(($($p),*)) = self;
$(
$p.set_samplerate(samplerate);
)*
}
}
};
}
Expand All @@ -328,10 +353,6 @@ parallel_tuple!(A, B, C, D, E, F, G, H);
impl<P: DSP<I, O>, const I: usize, const O: usize, const N: usize> DSP<I, O> for Parallel<[P; N]> {
type Sample = P::Sample;

fn latency(&self) -> usize {
self.0.iter().fold(0, |max, dsp| max.max(dsp.latency()))
}

fn process(&mut self, x: [Self::Sample; I]) -> [Self::Sample; O] {
self.0
.iter_mut()
Expand All @@ -341,6 +362,16 @@ impl<P: DSP<I, O>, const I: usize, const O: usize, const N: usize> DSP<I, O> for
})
}

fn set_samplerate(&mut self, samplerate: f32) {
for s in &mut self.0 {
s.set_samplerate(samplerate);
}
}

fn latency(&self) -> usize {
self.0.iter().fold(0, |max, dsp| max.max(dsp.latency()))
}

fn reset(&mut self) {
for dsp in self.0.iter_mut() {
dsp.reset();
Expand Down Expand Up @@ -414,6 +445,10 @@ impl<FF: DSP<N, N>, const N: usize> DSP<N, N> for Feedback<FF, (), N> {
y
}

fn set_samplerate(&mut self, samplerate: f32) {
self.feedforward.set_samplerate(samplerate);
}

fn latency(&self) -> usize {
self.feedforward.latency()
}
Expand All @@ -439,6 +474,11 @@ where
y
}

fn set_samplerate(&mut self, samplerate: f32) {
self.feedforward.set_samplerate(samplerate);
self.feedback.set_samplerate(samplerate);
}

fn latency(&self) -> usize {
self.feedforward.latency()
}
Expand Down
12 changes: 12 additions & 0 deletions src/dsp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod utils;
/// It's up to each implementor to document what the inputs and outputs mean.
/// There are no restrictions on the number of input or output channels in and of itself.
/// Implementors can support multiple configurations of I/O for different setups.
#[allow(unused_variables)]
pub trait DSP<const I: usize, const O: usize> {
/// Type of the audio sample used by this DSP instance.
type Sample: Scalar;
Expand All @@ -25,6 +26,9 @@ pub trait DSP<const I: usize, const O: usize> {
/// for oscillators, or gate signals that are actually either 0 or 1.
fn process(&mut self, x: [Self::Sample; I]) -> [Self::Sample; O];

/// Sets the processing samplerate for this [`DSP`] instance.
fn set_samplerate(&mut self, samplerate: f32) {}

/// Report the latency of this DSP instance, that is the time, in samples, it takes for an input sample to be
/// output back.
fn latency(&self) -> usize {
Expand All @@ -38,6 +42,7 @@ pub trait DSP<const I: usize, const O: usize> {

/// Trait for DSP processes that take in buffers of audio instead of single-samples.
/// Documentation of [`DSP`] still applies in here; only the process method changes.
#[allow(unused_variables)]
pub trait DSPBlock<const I: usize, const O: usize> {
type Sample: Scalar;

Expand All @@ -49,6 +54,9 @@ pub trait DSPBlock<const I: usize, const O: usize> {
/// Implementors should assume inputs and outputs are of the same length, as it is the caller's responsibility to make sure of that.
fn process_block(&mut self, inputs: &[[Self::Sample; I]], outputs: &mut [[Self::Sample; O]]);

/// Sets the processing samplerate for this [`DSP`] instance.
fn set_samplerate(&mut self, samplerate: f32) {}

/// Define an optional maximum buffer size alloed by this [`DSPBlock`] instance. Callers into this instance must
/// then only provide buffers that are up to this size in samples.
#[inline(always)]
Expand Down Expand Up @@ -83,6 +91,10 @@ where
}
}

fn set_samplerate(&mut self, samplerate: f32) {
DSP::set_samplerate(self, samplerate)
}

#[inline(always)]
fn latency(&self) -> usize {
DSP::latency(self)
Expand Down
Loading
Loading