Fast Spectral Swirl — Multi‑Channel
An STFT‑based effect that circularly rotates and/or permutes spectral bins over time to create shimmering, time‑varying timbres. Designed for speed and for coherent multi‑channel processing.
What this does
Per frame, the spectrum is taken via STFT. Bins are circularly shifted and/or phase‑advanced with a rate that can be constant or modulated. The result is a swirling timbre that preserves overall energy while redistributing partials. Multi‑channel handling keeps imaging stable when desired—or purposely decorrelated for wide, spacious effects.
- Real‑time friendly: small‑hop STFT with in‑place bin rotation.
- Deterministic or stochastic: constant, LFO‑modulated, or random‑walk swirl.
- Coherent surround: link channels to preserve localization; offset to design motion.
Quick start
- In Praat, select a mono or multi‑channel Sound.
- Run script… →
fast_spectral_swirl_multi_channel.praat. - Pick a preset (e.g., “Subtle shimmer”).
- Adjust rate, depth, and banding as needed.
- Choose link_channels = yes for stable imaging, no for wide/decorrelated swirl.
- Set mix (dry/wet) and normalize if needed. Press OK.
Concepts
STFT & Bin Rotation
Swirl via circular shift S bins: X'(k,n) = X((k - S(n)) mod K, n)
Alternative phase advance: X'(k,n) = X(k,n) · e^{j φ(k,n)}
Rotation re‑orders magnitudes across frequency; phase advance simulates spectral shearing. Both reconstruct via overlap–add.
Swirl Modes
🎛️ Constant Shift
Fixed S bins per frame; gentle chorus‑like shimmer.
🌊 LFO‑Modulated
S(n) = S0 + Sd · sin(2π f_LFO nH/Fs + φ) for periodic swirl.
🎲 Random Walk
Per frame, S jitters within bounds; seedable for repeatability.
🧩 Banded
Apply different shifts per band (low/mid/high) or per Bark/ERB groups for tone‑aware results.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| fft_size | option | 2048 | Power of two; resolution vs latency |
| hop | integer (samples) | N/4 | Smaller hop → smoother, higher CPU |
| window | option | Hann | Hann/Blackman/Hamming |
| mode | option | LFO | Constant, LFO, Random, Banded |
| shift_bins | integer | 2 | Base circular shift per frame |
| rate_hz | real | 0.6 | LFO rate for modulated mode |
| depth_bins | integer | 6 | LFO/random amplitude (bins) |
| phase_shear | real | 0.0 | Additional linear phase advance per bin |
| bands | text | "" | CSV edges in Hz (e.g., 0,300,3000,Nyq) |
| band_shifts | text | "" | CSV shifts per band (bins) |
| link_channels | boolean | yes | Use same shifts for all channels |
| stereo_offset | integer | 0 | Extra shift for R (or even channels) to widen |
| random_seed | integer | 0 | 0=auto; otherwise reproducible |
| dry_wet | real | 0.5 | 0=dry, 1=wet |
| normalize | boolean | yes | Normalize peak to norm_target |
| norm_target | real | 0.99 | Peak amplitude target |
| formant_keep | boolean | no | Reduce shifts near vocal formants (experimental) |
| report | boolean | no | Print effective shifts per frame/band |
Presets
✨ Subtle shimmer
fft=2048, hop=N/4, mode=LFO, shift=1, depth=3, rate=0.4, link_channels=yes, dry_wet=0.3
🌪️ Fast swirl
fft=1024, hop=N/4, mode=LFO, shift=2, depth=8, rate=2.0, stereo_offset=+1
🧊 Frozen highs
bands=0,300,4000,Nyq; band_shifts=0,0,2; formant_keep=yes
🎲 Grainy random
mode=Random, depth=10, random_seed=42, link_channels=no, dry_wet=0.6
Multi‑Channel Strategies
- Linked (coherent): Same
S(n)across channels maintains localization; use small stereo_offset for gentle width. - Decorrelated (wide): Offset or randomize per channel; keep low‑frequency bands linked to protect bass image.
- Surround beds: Link L/R and Ls/Rs pairs; add ±1 bin offsets to rears for movement without smearing center.
Tips & Pitfalls
- Latency vs detail: Larger FFT improves selectivity but increases latency.
- Clicks: Use Hann window and overlap ≥ 4 for smooth OLA.
- Vocal integrity: Enable formant_keep or reduce high‑band shifting.
- Gain staging: Spectral re‑arrangement can cause peaks; normalize after processing.
- Mono check: Excessive inter‑channel offsets may comb‑filter in mono.
Math
Bin Rotation & Phase Shear
Phase shear: φ'(k,n) = φ(k,n) + α·k ⇒ X'(k,n) = |X| e^{j φ'(k,n)}
Inverse STFT via OLA reconstructs y(t).
LFO Mapping
For banded swirl, use S_b(n) per band b and apply within band edges.