// In-place radix-2 complex FFT. export class FFT { private cos: Float32Array; private sin: Float32Array; private rev: Uint32Array; constructor(readonly n: number) { if (n & (n - 1)) throw new Error("FFT size must be a power of two"); this.cos = new Float32Array(n / 2); this.sin = new Float32Array(n / 2); for (let k = 0; k < n / 2; k++) { this.cos[k] = Math.cos((2 * Math.PI * k) / n); this.sin[k] = -Math.sin((2 * Math.PI * k) / n); } this.rev = new Uint32Array(n); const bits = Math.log2(n); for (let i = 0; i < n; i++) { let r = 0; for (let b = 0; b < bits; b++) r |= ((i >> b) & 1) << (bits - 1 - b); this.rev[i] = r; } } transform(re: Float32Array, im: Float32Array): void { const n = this.n; for (let i = 0; i < n; i++) { const r = this.rev[i]; if (r > i) { let t = re[i]; re[i] = re[r]; re[r] = t; t = im[i]; im[i] = im[r]; im[r] = t; } } for (let size = 2; size <= n; size <<= 1) { const half = size >> 1, step = n / size; for (let start = 0; start < n; start += size) { for (let k = 0; k < half; k++) { const c = this.cos[k * step], s = this.sin[k * step]; const a = start + k, b = a + half; const tr = re[b] * c - im[b] * s; const ti = re[b] * s + im[b] * c; re[b] = re[a] - tr; im[b] = im[a] - ti; re[a] += tr; im[a] += ti; } } } } }