Streaming multichannel STFT/WOLA engine. More...
#include <spectral_frame_engine.hpp>
Public Member Functions | |
| SpectralFrameEngineT ()=default | |
| void | prepare (const SpectralFrameEngineConfig &config) |
| RT contract: prepare() allocates FFT/window/ring/frame storage and is not audio-thread safe. | |
| int | latency_samples () const |
| Fixed delay of the equal-hop process() path. | |
| std::int64_t | first_frame_start () const |
| Stream position of the first analysis frame after prepare()/reset(): 0 without full-overlap stream start, otherwise in (-fft_size, 0] and a multiple of analysis_hop. | |
| int | fft_size () const |
| int | analysis_hop () const |
| int | num_bins () const |
| int | channels () const |
| std::uint64_t | retained_storage_bytes () const noexcept |
| Logical retained allocations, using actual container capacities and the selected FFT provider's backing-store charge (excluding allocator metadata). | |
| template<typename Fn> | |
| SpectralSplitResult | analyze_guarded (const SampleType *const *in, int count, Fn &&fn) |
| Checked split analysis refuses the whole block before ingest on a clock or block-limit error. | |
| SpectralSplitResult | synthesize_frame_guarded (const std::complex< SampleType > *const *frames) noexcept |
| Equal-hop split synthesis. | |
| void | stop_synthesis_guarded () noexcept |
| After a fatal frame at the current origin, prior samples are final: this frame cannot contribute before its origin. | |
| SpectralSplitResult | read_output_guarded (SampleType *const *out, int count, int &consumed) noexcept |
| Pop a finite prefix and return its length. | |
| template<typename Fn> | |
| void | process (const SampleType *const *in, SampleType *const *out, int num_samples, Fn &&on_frames) |
| Equal-hop streaming: push num_samples per channel, invoke on_frames(std::complex<SampleType>* const* frames, int num_bins) once per completed analysis frame (modify in place), resynthesize at the analysis hop, and write exactly num_samples per channel to out (the first latency_samples() of the stream are zeros). | |
| int | samples_until_next_frame () const |
| Samples that must still be fed before the next analysis frame completes (>= 1). | |
| template<typename Fn> | |
| void | analyze (const SampleType *const *in, int num_samples, Fn &&on_frames) |
| Split API — analysis only. | |
| void | synthesize_frame (std::complex< SampleType > *const *frames, int synthesis_hop) |
| Split API — overlap-add one spectral frame (all channels) at the current synthesis position, then advance it by synthesis_hop. | |
| int | available_output () const |
| Split API — number of final (fully overlapped) output samples that can be read right now. | |
| void | read_output (SampleType *const *out, int num_samples) |
| Split API — pop exactly num_samples per channel into out. | |
| void | reset () |
Streaming multichannel STFT/WOLA engine.
Not thread-safe; one instance per audio stream.
|
default |
|
inline |
|
inline |
Split API — analysis only.
Pushes num_samples per channel from in, invoking on_frames once per completed frame. Runs are split exactly at frame boundaries, so frames land at fft_size + first_frame_start() + k * hop for ANY feed chunking — the analysis hop the callback observes is constant regardless of host block size. With full-overlap stream start the first frames arrive after fewer than fft_size samples and carry the implicit pre-stream silence.
|
inline |
Checked split analysis refuses the whole block before ingest on a clock or block-limit error.
Frame borrows expire when the callback returns.
|
inline |
Split API — number of final (fully overlapped) output samples that can be read right now.
|
inline |
|
inline |
|
inline |
Stream position of the first analysis frame after prepare()/reset(): 0 without full-overlap stream start, otherwise in (-fft_size, 0] and a multiple of analysis_hop.
Frame k analyses input [first_frame_start() + k * hop, ... + fft_size), silence before 0.
|
inline |
Fixed delay of the equal-hop process() path.
A frame is only final once every overlapping frame has been added, which trails the input by up to fft_size + (analysis_hop - 1) samples depending on block phase; the constant fft_size + analysis_hop bound makes the reported latency exact and block-size independent.
|
inline |
|
inline |
RT contract: prepare() allocates FFT/window/ring/frame storage and is not audio-thread safe.
After prepare(), process(), analyze(), synthesize_frame(), available_output(), read_output(), reset(), and accessors are allocation-free for blocks no larger than max_block and synthesis hops no larger than max_synthesis_hop. The callback must also be RT-safe.
|
inline |
Equal-hop streaming: push num_samples per channel, invoke on_frames(std::complex<SampleType>* const* frames, int num_bins) once per completed analysis frame (modify in place), resynthesize at the analysis hop, and write exactly num_samples per channel to out (the first latency_samples() of the stream are zeros).
|
inline |
Split API — pop exactly num_samples per channel into out.
Callers should not request more than available_output(); any excess is filled with silence without advancing the read position (the engine never invents a variable delay on its own).
|
inlinenoexcept |
Pop a finite prefix and return its length.
On failure the caller keeps that prefix and supplies terminal silence from the first unread sample.
|
inline |
|
inlinenoexcept |
Logical retained allocations, using actual container capacities and the selected FFT provider's backing-store charge (excluding allocator metadata).
|
inline |
Samples that must still be fed before the next analysis frame completes (>= 1).
Lets a caller chunk its feed so each analyze call ends exactly when a frame emits — making the in-block offset of the completed frame known precisely (needed to evaluate per-frame control trajectories, e.g. a smoothed pitch ratio, at the correct position instead of the chunk end).
|
inlinenoexcept |
After a fatal frame at the current origin, prior samples are final: this frame cannot contribute before its origin.
Retain that prefix and prohibit further synthesis until reset; no failing frame is committed.
|
inline |
Split API — overlap-add one spectral frame (all channels) at the current synthesis position, then advance it by synthesis_hop.
frames must hold channels() pointers to num_bins() bins (DC..Nyquist); the conjugate half is reconstructed internally. The synthesis position starts at first_frame_start(); output that falls before stream position 0 is discarded.
|
inlinenoexcept |
Equal-hop split synthesis.
Validate and stage every channel and divisor before committing any ring cell, preserving earlier history on failure.