/ proof-of-concept / steelsim41
Sign in
proof-of-concept / steelsim41
steelsim41 / src / audio / fft.ts
46 lines · 1.4 KBCodeBlameHistory
1ee087eCymbal designer: scripted design, thickness field, mount, single strikeJeremy Magland 1// In-place radix-2 complex FFT.
3export class FFT {
4 private cos: Float32Array;
5 private sin: Float32Array;
6 private rev: Uint32Array;
7 constructor(readonly n: number) {
8 if (n & (n - 1)) throw new Error("FFT size must be a power of two");
9 this.cos = new Float32Array(n / 2);
10 this.sin = new Float32Array(n / 2);
11 for (let k = 0; k < n / 2; k++) {
12 this.cos[k] = Math.cos((2 * Math.PI * k) / n);
13 this.sin[k] = -Math.sin((2 * Math.PI * k) / n);
14 }
15 this.rev = new Uint32Array(n);
16 const bits = Math.log2(n);
17 for (let i = 0; i < n; i++) {
18 let r = 0;
19 for (let b = 0; b < bits; b++) r |= ((i >> b) & 1) << (bits - 1 - b);
20 this.rev[i] = r;
21 }
22 }
23 transform(re: Float32Array, im: Float32Array): void {
24 const n = this.n;
25 for (let i = 0; i < n; i++) {
26 const r = this.rev[i];
27 if (r > i) {
28 let t = re[i]; re[i] = re[r]; re[r] = t;
29 t = im[i]; im[i] = im[r]; im[r] = t;
30 }
31 }
32 for (let size = 2; size <= n; size <<= 1) {
33 const half = size >> 1, step = n / size;
34 for (let start = 0; start < n; start += size) {
35 for (let k = 0; k < half; k++) {
36 const c = this.cos[k * step], s = this.sin[k * step];
37 const a = start + k, b = a + half;
38 const tr = re[b] * c - im[b] * s;
39 const ti = re[b] * s + im[b] * c;
40 re[b] = re[a] - tr; im[b] = im[a] - ti;
41 re[a] += tr; im[a] += ti;
42 }
43 }
44 }
45 }
↑↓ move↵openescclose