Process the spectrum
Work in the frequency domain.To edit audio by frequency, construct a Spectral STFT in prepare and call
process(ctx) each block. The host re-enters processSpectrum once per hop with the
complex spectrum.
private stft: Spectral | null = null;
prepare(sampleRate: f64, maxBlock: i32): void {
this.stft = new Spectral(1024, 2, maxBlock); // fftSize, channels, maxBlock
}
process(ctx: Ctx): void {
const stft = this.stft;
if (stft == null) return;
stft.process(ctx);
}Edit bins in processSpectrum. A brickwall lowpass keeps the lowest bins and zeroes the
rest:
processSpectrum(frame: SpectralFrame, ctx: Ctx): void {
const keep = <i32>(<f32>frame.binCount * ctx.param(0));
for (let ch = 0; ch < frame.numChannels; ch++) {
for (let b = keep; b < frame.binCount; b++) {
frame.set(ch, b, 0.0, 0.0);
}
}
}Read with frame.real(ch, bin) / frame.imag(ch, bin), overwrite with frame.set(...),
or scale a bin's magnitude while keeping its phase with frame.scale(ch, bin, g).
Whatever you leave is resynthesized; for an analysis-only pass, never write back. The
export * line already exposes the per-frame entry point.
An STFT delays the signal by fftSize, so report it: m.latency(1024).
Note
For a vocoder, pass a sidechain channel count as the 6th Spectral argument
and declare a sidechainIn port, then read the modulator's spectrum per bin
with frame.sidechainMag(ch, bin). For full control over windowing and hop (a
phase vocoder, time-stretch), drop to the raw Fft primitive.
See DSP blocks.