Skip to content

Commit

Permalink
Merge pull request #9 from SolarLiner/feat/set-samplerate
Browse files Browse the repository at this point in the history
`set_samplerate` method on `DSP`/`DSPBlock`
  • Loading branch information
SolarLiner authored Feb 11, 2024
2 parents 09cf20c + 9811d49 commit 9c2edd3
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 69 deletions.
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

0 comments on commit 9c2edd3

Please sign in to comment.