Struct nih_plug::util::StftHelper

source ·
pub struct StftHelper<const NUM_SIDECHAIN_INPUTS: usize = 0> { /* private fields */ }
Expand description

Process the input buffer in equal sized blocks, running a callback on each block to transform the block and then writing back the results from the previous block to the buffer. This introduces latency equal to the size of the block.

Additional inputs can be processed by setting the NUM_SIDECHAIN_INPUTS constant. These buffers will not be written to, so they are purely used for analysis. These sidechain inputs will have the same number of channels as the main input.

TODO: Better name? TODO: We may need something like this purely for analysis, e.g. for showing spectrums in a GUI. Figure out the cleanest way to adapt this for the non-processing use case.

Implementations§

source§

impl<const NUM_SIDECHAIN_INPUTS: usize> StftHelper<NUM_SIDECHAIN_INPUTS>

source

pub fn new( num_channels: usize, max_block_size: usize, max_padding: usize ) -> Self

Initialize the StftHelper for Buffers with the specified number of channels and the given maximum block size. When the option is set, then every yielded sample buffer will have this many zero samples appended at the end of the block. Call set_block_size() afterwards if you do not need the full capacity upfront. If the padding option is non zero, then all yielded blocks will have that many zeroes added to the end of it and the results stored in the padding area will be added to the outputs in the next iteration(s). You may also change how much padding is added with set_padding().

Panics

Panics if num_channels == 0 || max_block_size == 0.

source

pub fn set_block_size(&mut self, block_size: usize)

Change the current block size. This will clear the buffers, causing the next block to output silence.

Panics

Will panic if block_size > max_block_size.

source

pub fn set_padding(&mut self, padding: usize)

Change the current padding amount. This will clear the buffers, causing the next block to output silence.

Panics

Will panic if padding > max_padding.

source

pub fn num_channels(&self) -> usize

The number of channels this StftHelper was configured for

source

pub fn max_block_size(&self) -> usize

The maximum block size supported by this instance.

source

pub fn max_padding(&self) -> usize

The maximum amount of padding supported by this instance.

source

pub fn latency_samples(&self) -> u32

The amount of latency introduced when processing audio through this StftHelper.

source

pub fn process_overlap_add<M, F>( &mut self, main_buffer: &mut M, overlap_times: usize, process_cb: F )where M: StftInputMut, F: FnMut(usize, &mut [f32]),

Process the audio in main_buffer in small overlapping blocks, adding up the results for the main buffer so they can eventually be written back to the host one block later. This means that this function will introduce one block of latency. This can be compensated by calling InitContext::set_latency() in your plugin’s initialization function.

If a padding value was specified in new(), then the yielded blocks will have that many zeroes appended at the end of them. The padding values will be added to the next block before process_cb() is called.

Since there are a couple different ways to do it, any window functions needs to be applied in the callbacks. Check the nih_plug::util::window module for more information.

For efficiency’s sake this function will reuse the same vector for all calls to process_cb. This means you can only access a single channel’s worth of windowed data at a time. The arguments to that function are process_cb(channel_idx, real_fft_buffer). real_fft_buffer will be a slice of block_size real valued samples. This can be passed directly to an FFT algorithm.

Panics

Panics if main_buffer or the buffers in sidechain_buffers do not have the same number of channels as this StftHelper, or if the sidechain buffers do not contain the same number of samples as the main buffer.

TODO: Add more useful ways to do STFT and other buffered operations. I just went with this approach because it’s what I needed myself, but generic combinators like this could also be useful for other operations.

source

pub fn process_overlap_add_sidechain<M, S, F>( &mut self, main_buffer: &mut M, sidechain_buffers: [&S; NUM_SIDECHAIN_INPUTS], overlap_times: usize, process_cb: F )where M: StftInputMut, S: StftInput, F: FnMut(usize, Option<usize>, &mut [f32]),

The same as process_overlap_add(), but with sidechain inputs that can be analyzed before the main input gets processed.

The extra argument in the process function is sidechain_buffer_idx, which will be None for the main buffer.

source

pub fn process_analyze_only<B, F>( &mut self, buffer: &B, overlap_times: usize, analyze_cb: F )where B: StftInput, F: FnMut(usize, &mut [f32]),

Similar to process_overlap_add(), but without the inverse STFT part. buffer will only ever be read from. This can be useful for providing FFT data for a spectrum analyzer in a plugin GUI. These is still a delay to the analysis equal to the block size.

Auto Trait Implementations§

§

impl<const NUM_SIDECHAIN_INPUTS: usize> RefUnwindSafe for StftHelper<NUM_SIDECHAIN_INPUTS>

§

impl<const NUM_SIDECHAIN_INPUTS: usize> Send for StftHelper<NUM_SIDECHAIN_INPUTS>

§

impl<const NUM_SIDECHAIN_INPUTS: usize> Sync for StftHelper<NUM_SIDECHAIN_INPUTS>

§

impl<const NUM_SIDECHAIN_INPUTS: usize> Unpin for StftHelper<NUM_SIDECHAIN_INPUTS>

§

impl<const NUM_SIDECHAIN_INPUTS: usize> UnwindSafe for StftHelper<NUM_SIDECHAIN_INPUTS>

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pointable for T

§

const ALIGN: usize = mem::align_of::<T>()

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T, U> ToSample<U> for Twhere U: FromSample<T>,

§

fn to_sample_(self) -> U

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Any for Twhere T: Any,

§

impl<S, T> Duplex<S> for Twhere T: FromSample<S> + ToSample<S>,