Before installing external buffers, use isRealFftComplexMemoryValid for the complex transform, or isRealFftIoMemoryValid for real forward/inverse calls. These preparation checks admit fixed, disjoint views outside private scratch and tables. For inverse calls, pass the output and the two input arrays to the same symmetric three-view check. Recheck after replacing a view. Calls borrow storage only until they return; serialize work on one FFT state.
The transforms reject short spectrum/complex arrays before mutation. Forward also rejects identical real/imaginary outputs. Integer offsets retain their existing zero-padding and bounds-limited write behavior. Keep partial backing overlap out of the processing calls through the preparation check.
@maruaudio/dsp/spectral/real-fft is the one FFT a Processor closure may import. It transforms real signals of any power-of-two size from 4 to the maxSize the state was built for (at most 2^19) by the two-for-one method: an N-point input is packed as N/2 complex points x[2n] + i·x[2n+1], transformed by an iterative radix-2 decimation-in-time FFT and split into X[k] = Fe[k] + W^k·Fo[k]. Spectra are split re/im arrays of N/2 + 1 bins with numpy rfft/irfft conventions: the forward transform is unnormalised and the inverse carries 1/N. Everything is f64.
Functions
| Name | Inputs | Output | Domain as coded |
|---|---|---|---|
initRealFft | maxSize | state with f64 twiddles, bit reversal and work arrays | Rounded up to a power of two, clamped to 4..2^19 |
realFftForward | state, size, input, inputOffset, outRe, outIm | true and bins 0..size/2 | false for an unsupported size; input past the end reads as 0 |
realFftInverse | state, size, inRe, inIm, output, outputOffset | true and size samples | Normalised by 1/size; imaginary parts of DC and Nyquist ignored; writes bounds-checked |
realFftComplexInPlace | state, size, re, im, inverse | true, in place | Size 2..maxSize/2; unnormalised both ways; false leaves the arrays untouched |
realFftSizeSupported | state, size | boolean | Power of two from 4 to maxSize |
realFftLog2 | size | log2, or −1 | Powers of two 1..2^19 |
Lifecycle
initRealFft(maxSize) allocates everything once, outside realtime. The same state then serves every smaller power-of-two size by striding the same tables; there is no reset, because the transforms keep no state between calls.
When to use it
Spectral analysis, FFT convolution and room-acoustics preparation inside a Processor. @maru/filters-partitioned-convolution and @maru/acoustics-octave-bands build on it (spectral and rooms).
Limits
- Inside a realtime callback keep one transform at or below
REAL_FFT_REALTIME_MAX_SIZE(8192 points); larger sizes belong in budgeted preparation steps. - Output arrays are caller-owned; spectra need at least size/2 + 1 entries.
- The transforms allocate nothing, and every loop has a literal bound with the runtime size as an inner guard.
@maru/oscillators-band-limited-tablekeeps its own private f32 transform.