2022-03-06 12:07:53 +11:00
|
|
|
use nih_plug::prelude::*;
|
|
|
|
use std::pin::Pin;
|
|
|
|
|
2022-03-07 00:33:30 +11:00
|
|
|
const WINDOW_SIZE: usize = 2048;
|
2022-03-07 01:28:44 +11:00
|
|
|
const OVERLAP_TIMES: usize = 4;
|
2022-03-07 00:33:30 +11:00
|
|
|
|
2022-03-06 12:07:53 +11:00
|
|
|
struct Stft {
|
|
|
|
params: Pin<Box<StftParams>>,
|
|
|
|
|
|
|
|
stft: util::StftHelper,
|
2022-03-07 00:48:41 +11:00
|
|
|
window_function: Vec<f32>,
|
2022-03-06 12:07:53 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Params)]
|
|
|
|
struct StftParams {}
|
|
|
|
|
|
|
|
impl Default for Stft {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
params: Box::pin(StftParams::default()),
|
|
|
|
|
2022-03-07 00:33:30 +11:00
|
|
|
stft: util::StftHelper::new(2, WINDOW_SIZE),
|
2022-03-07 00:48:41 +11:00
|
|
|
window_function: util::window::hann(WINDOW_SIZE),
|
2022-03-06 12:07:53 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2022-03-07 00:33:30 +11:00
|
|
|
self.stft.set_block_size(WINDOW_SIZE);
|
2022-03-06 12:07:53 +11:00
|
|
|
context.set_latency_samples(self.stft.latency_samples());
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process(
|
|
|
|
&mut self,
|
|
|
|
buffer: &mut Buffer,
|
|
|
|
_context: &mut impl ProcessContext,
|
|
|
|
) -> ProcessStatus {
|
2022-03-07 01:28:44 +11:00
|
|
|
self.stft.process_overlap_add(
|
|
|
|
buffer,
|
|
|
|
[],
|
|
|
|
&self.window_function,
|
|
|
|
OVERLAP_TIMES,
|
|
|
|
2.0 / OVERLAP_TIMES as f32, // Gain compensation for the overlap
|
|
|
|
|_channel_idx, _, _block| {
|
|
|
|
// for sample in block {
|
|
|
|
// // TODO: Use the FFTW bindings and do some STFT operation here instead of
|
|
|
|
// // reducing the gain at a 2048 sample latency...
|
|
|
|
// *sample *= 0.5;
|
|
|
|
// }
|
|
|
|
},
|
|
|
|
);
|
2022-03-06 12:07:53 +11:00
|
|
|
|
|
|
|
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);
|