From b416d1630b88cfdde26756e3731386c21fe73def Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 6 Mar 2022 02:07:53 +0100 Subject: [PATCH] Add the basis for a simple STFT example Right now it doesn't do any FFT operations yet, but all the pieces are in place using the new STFT helper. --- Cargo.lock | 7 +++ Cargo.toml | 1 + README.md | 4 ++ plugins/examples/stft/Cargo.toml | 12 ++++ plugins/examples/stft/src/lib.rs | 98 ++++++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 plugins/examples/stft/Cargo.toml create mode 100644 plugins/examples/stft/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index af9ba7fa..93d2bc56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -855,6 +855,13 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "stft" +version = "0.1.0" +dependencies = [ + "nih_plug", +] + [[package]] name = "syn" version = "1.0.86" diff --git a/Cargo.toml b/Cargo.toml index 8437d32f..28f230f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ members = [ "plugins/examples/gain", "plugins/examples/gain-gui", "plugins/examples/sine", + "plugins/examples/stft", "plugins/diopser", ] diff --git a/README.md b/README.md index 403bbcb7..fec9e606 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,10 @@ examples. - [**sine**](plugins/examples/sine) is a simple test tone generator plugin with frequency smoothing that can also make use of MIDI input instead of generating a static signal based on the plugin's parameters. +- [**stft**](plugins/examples/stft) shows off some of NIH-plug's other optional + helper features, like an adapter to process audio in buffered blocks meant for + short-term Fourier transform operations, all using the compositional `Buffer` + interface. ## Licensing diff --git a/plugins/examples/stft/Cargo.toml b/plugins/examples/stft/Cargo.toml new file mode 100644 index 00000000..71cf7856 --- /dev/null +++ b/plugins/examples/stft/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "stft" +version = "0.1.0" +edition = "2021" +authors = ["Robbert van der Helm "] +license = "ISC" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +nih_plug = { path = "../../../", features = ["assert_process_allocs"] } diff --git a/plugins/examples/stft/src/lib.rs b/plugins/examples/stft/src/lib.rs new file mode 100644 index 00000000..1dcf9ecd --- /dev/null +++ b/plugins/examples/stft/src/lib.rs @@ -0,0 +1,98 @@ +use nih_plug::prelude::*; +use std::pin::Pin; + +struct Stft { + params: Pin>, + + stft: util::StftHelper, +} + +#[derive(Params)] +struct StftParams {} + +impl Default for Stft { + fn default() -> Self { + Self { + params: Box::pin(StftParams::default()), + + stft: util::StftHelper::new(2, 512), + } + } +} + +impl Default for StftParams { + fn default() -> Self { + Self {} + } +} + +impl Plugin for Stft { + const NAME: &'static str = "STFT Example"; + const VENDOR: &'static str = "Moist Plugins GmbH"; + const URL: &'static str = "https://youtu.be/dQw4w9WgXcQ"; + const EMAIL: &'static str = "info@example.com"; + + const VERSION: &'static str = "0.0.1"; + + const DEFAULT_NUM_INPUTS: u32 = 2; + const DEFAULT_NUM_OUTPUTS: u32 = 2; + + const ACCEPTS_MIDI: bool = false; + + fn params(&self) -> Pin<&dyn Params> { + self.params.as_ref() + } + + fn accepts_bus_config(&self, config: &BusConfig) -> bool { + // We'll only do stereo for simplicity's sake + config.num_input_channels == config.num_output_channels && config.num_input_channels == 2 + } + + fn initialize( + &mut self, + _bus_config: &BusConfig, + _buffer_config: &BufferConfig, + context: &mut impl ProcessContext, + ) -> bool { + // Normally we'd also initialize the STFT helper for the correct channel count here, but we + // only do stereo so that's not necessary + self.stft.set_block_size(512); + context.set_latency_samples(self.stft.latency_samples()); + + true + } + + fn process( + &mut self, + buffer: &mut Buffer, + _context: &mut impl ProcessContext, + ) -> ProcessStatus { + self.stft.process(buffer, [], |block, _| { + for channel_samples in block.iter_mut() { + for sample in channel_samples { + // TODO: Use the FFTW bindings and do some STFT operation here instead of + // reducing the gain at a 512 sample latency... + *sample *= 0.5; + } + } + }); + + ProcessStatus::Normal + } +} + +impl ClapPlugin for Stft { + const CLAP_ID: &'static str = "com.moist-plugins-gmbh.stft"; + const CLAP_DESCRIPTION: &'static str = "An example plugin using the STFT helper"; + const CLAP_FEATURES: &'static [&'static str] = &["audio_effect", "stereo", "tool"]; + const CLAP_MANUAL_URL: &'static str = Self::URL; + const CLAP_SUPPORT_URL: &'static str = Self::URL; +} + +impl Vst3Plugin for Stft { + const VST3_CLASS_ID: [u8; 16] = *b"StftMoistestPlug"; + const VST3_CATEGORIES: &'static str = "Fx|Tools"; +} + +nih_export_clap!(Stft); +nih_export_vst3!(Stft);