@emnudge/wat-fft 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # wat-fft
2
+
3
+ A high-performance FFT implementation in WebAssembly Text format that **significantly outperforms popular JavaScript FFT libraries**.
4
+
5
+ ## Performance
6
+
7
+ ### Complex FFT
8
+
9
+ Benchmarked against [fft.js](https://github.com/indutny/fft.js) (fastest pure-JS FFT):
10
+
11
+ | Size | wat-fft (f64) | fft.js | Speedup |
12
+ | ------ | ------------------- | --------------- | -------- |
13
+ | N=64 | **3,830,000 ops/s** | 2,794,000 ops/s | **1.4x** |
14
+ | N=128 | **1,586,000 ops/s** | 1,105,000 ops/s | **1.4x** |
15
+ | N=256 | **973,000 ops/s** | 559,000 ops/s | **1.7x** |
16
+ | N=512 | **344,000 ops/s** | 223,000 ops/s | **1.5x** |
17
+ | N=1024 | **191,000 ops/s** | 113,000 ops/s | **1.7x** |
18
+ | N=2048 | **74,500 ops/s** | 47,200 ops/s | **1.6x** |
19
+ | N=4096 | **44,400 ops/s** | 23,400 ops/s | **1.9x** |
20
+
21
+ ```mermaid
22
+ ---
23
+ config:
24
+ xyChart:
25
+ width: 700
26
+ height: 400
27
+ themeVariables:
28
+ xyChart:
29
+ plotColorPalette: "#4ade80, #60a5fa, #a855f7, #f87171"
30
+ ---
31
+ xychart-beta
32
+ title "Complex FFT Performance (Million ops/s)"
33
+ x-axis [N=64, N=128, N=256, N=512, N=1024, N=2048, N=4096]
34
+ y-axis "Million ops/s" 0 --> 5
35
+ line [3.83, 1.59, 0.97, 0.34, 0.19, 0.074, 0.044]
36
+ line [4.60, 2.40, 1.17, 0.54, 0.27, 0.124, 0.062]
37
+ line [2.79, 1.11, 0.56, 0.22, 0.11, 0.047, 0.023]
38
+ line [1.90, 0.80, 0.45, 0.18, 0.10, 0.041, 0.022]
39
+ ```
40
+
41
+ > 馃煝 **wat-fft f64** 路 馃數 **wat-fft f32** 路 馃煟 **fft.js** 路 馃敶 **kissfft-js**
42
+
43
+ **Choose f64** (`fft_combined.wasm`) for double precision - **1.4-1.9x faster** than fft.js at all sizes. **Choose f32** (`fft_stockham_f32_dual.wasm`) for maximum speed with single precision - up to **2.6x faster** than fft.js.
44
+
45
+ ### Real FFT
46
+
47
+ Benchmarked against [fftw-js](https://www.npmjs.com/package/fftw-js) (Emscripten port of FFTW):
48
+
49
+ | Size | wat-fft (f32) | fftw-js (f32) | Comparison |
50
+ | ------ | ------------------- | --------------- | ---------- |
51
+ | N=64 | **6,700,000 ops/s** | 6,620,000 ops/s | **+1%** |
52
+ | N=128 | **4,290,000 ops/s** | 4,100,000 ops/s | **+5%** |
53
+ | N=256 | **2,170,000 ops/s** | 1,430,000 ops/s | **+51%** |
54
+ | N=512 | **1,130,000 ops/s** | 870,000 ops/s | **+31%** |
55
+ | N=1024 | **525,000 ops/s** | 444,000 ops/s | **+18%** |
56
+ | N=2048 | **264,000 ops/s** | 225,000 ops/s | **+18%** |
57
+ | N=4096 | **116,000 ops/s** | 105,000 ops/s | **+11%** |
58
+
59
+ ```mermaid
60
+ ---
61
+ config:
62
+ xyChart:
63
+ width: 700
64
+ height: 400
65
+ themeVariables:
66
+ xyChart:
67
+ plotColorPalette: "#4ade80, #60a5fa, #f87171, #a855f7"
68
+ ---
69
+ xychart-beta
70
+ title "Real FFT Performance (Million ops/s)"
71
+ x-axis [N=64, N=128, N=256, N=512, N=1024, N=2048, N=4096]
72
+ y-axis "Million ops/s" 0 --> 8
73
+ line [4.80, 2.99, 1.28, 0.76, 0.27, 0.16, 0.062]
74
+ line [6.70, 4.29, 2.17, 1.13, 0.525, 0.264, 0.116]
75
+ line [6.62, 4.10, 1.43, 0.87, 0.444, 0.225, 0.105]
76
+ line [2.93, 1.74, 0.75, 0.42, 0.17, 0.094, 0.039]
77
+ ```
78
+
79
+ > 馃煝 **wat-fft f64** 路 馃數 **wat-fft f32** 路 馃敶 **fftw-js** 路 馃煟 **kissfft-js**
80
+
81
+ **wat-fft f32 beats fftw-js at all sizes** (+1% to +51%). **Choose f64** (`fft_real_combined.wasm`) for double precision. **Choose f32** (`fft_real_f32_dual.wasm`) for maximum single-precision speed.
82
+
83
+ ## Quick Start
84
+
85
+ ```bash
86
+ # Install dependencies
87
+ npm install
88
+
89
+ # Build WASM modules
90
+ npm run build
91
+
92
+ # Run tests
93
+ npm test
94
+
95
+ # Run benchmarks
96
+ npm run bench
97
+ ```
98
+
99
+ ### Prerequisites
100
+
101
+ - Node.js v18+
102
+ - [wasm-tools](https://github.com/bytecodealliance/wasm-tools)
103
+
104
+ ```bash
105
+ cargo install wasm-tools
106
+ ```
107
+
108
+ ## Usage
109
+
110
+ ```javascript
111
+ import fs from "fs";
112
+
113
+ // Load the WASM module (Stockham is recommended for best performance)
114
+ // No JavaScript imports needed - trig functions are computed inline
115
+ const wasmBuffer = fs.readFileSync("dist/combined_stockham.wasm");
116
+ const wasmModule = await WebAssembly.compile(wasmBuffer);
117
+ const instance = await WebAssembly.instantiate(wasmModule);
118
+ const fft = instance.exports;
119
+
120
+ // Prepare input (interleaved complex: [re0, im0, re1, im1, ...])
121
+ const N = 1024;
122
+ const data = new Float64Array(fft.memory.buffer, 0, N * 2);
123
+ for (let i = 0; i < N; i++) {
124
+ data[i * 2] = Math.sin((2 * Math.PI * i) / N); // real
125
+ data[i * 2 + 1] = 0; // imaginary
126
+ }
127
+
128
+ // Compute FFT
129
+ fft.precompute_twiddles(N);
130
+ fft.fft_stockham(N);
131
+
132
+ // Results are in-place in data[]
133
+ console.log("DC component:", data[0], data[1]);
134
+ ```
135
+
136
+ ## Implementations
137
+
138
+ **Recommended modules:**
139
+
140
+ | Module | Use Case | Precision |
141
+ | ---------------------------- | ---------------------- | --------- |
142
+ | `fft_combined.wasm` | Complex FFT (any size) | f64 |
143
+ | `fft_real_combined.wasm` | Real FFT (any size) | f64 |
144
+ | `fft_stockham_f32_dual.wasm` | Complex FFT (fastest) | f32 |
145
+ | `fft_real_f32_dual.wasm` | Real FFT (fastest) | f32 |
146
+
147
+ See [docs/IMPLEMENTATIONS.md](docs/IMPLEMENTATIONS.md) for detailed documentation of all modules, usage examples, and numerical accuracy information.
148
+
149
+ ## How It Works
150
+
151
+ See [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md) for algorithm details including:
152
+
153
+ - Real FFT algorithm (N-point real using N/2-point complex)
154
+ - Memory layout and buffer organization
155
+ - SIMD complex multiply implementation
156
+ - Stockham and Radix-4 FFT algorithms
157
+ - Taylor series trigonometry
158
+
159
+ ## Scripts
160
+
161
+ ```bash
162
+ npm run build # Build all WASM modules
163
+ npm test # Run all tests
164
+ npm run bench # Run complex FFT benchmarks
165
+ npm run bench:rfft # Run real FFT benchmarks
166
+ npm run bench:rfft32 # Run f32 real FFT benchmarks
167
+ npm run test:fft # Run comprehensive FFT tests
168
+ npm run test:rfft # Run real FFT tests
169
+ npm run test:permutation # Test permutation algorithms
170
+ ```
171
+
172
+ ## Development Tools
173
+
174
+ | Documentation | Description |
175
+ | ------------------------------------------------------ | ---------------------------------------- |
176
+ | [benchmarks/README.md](benchmarks/README.md) | Performance benchmarks and profiling |
177
+ | [tools/README.md](tools/README.md) | Debug tools for FFT development |
178
+ | [docs/OPTIMIZATION_PLAN.md](docs/OPTIMIZATION_PLAN.md) | Optimization strategy and experiment log |
179
+
180
+ ## Playground
181
+
182
+ An interactive browser-based playground is available for testing FFT performance with real-world tasks like spectrogram generation.
183
+
184
+ ```bash
185
+ cd playground
186
+ npm install
187
+ npm run dev
188
+ ```
189
+
190
+ Features:
191
+
192
+ - **Multiple FFT implementations**: Compare performance of different wat-fft modules
193
+ - **Audio sources**: Generate synthetic sine wave combinations using Web Audio API's OfflineAudioContext, or load your own audio files
194
+ - **Spectrogram visualization**: Real-time spectrogram rendering with configurable FFT size, hop size, and color scales
195
+ - **Spectrum analyzer**: Live microphone input with bar, curve, and mirrored visualization modes
196
+ - **Performance metrics**: Track FFT execution time and throughput
197
+
198
+ Add your own sample audio files to `playground/public/samples/`.
199
+
200
+ ## Testing FFT Implementations
201
+
202
+ The comprehensive FFT test suite (`tests/fft.test.js`) tests all implementations against a reference DFT with various input sizes and patterns.
203
+
204
+ ### Run all FFT tests
205
+
206
+ ```bash
207
+ npm run test:fft
208
+ ```
209
+
210
+ ### Test a single implementation (useful for debugging)
211
+
212
+ ```bash
213
+ node tests/fft.test.js --impl stockham 64 random
214
+ node tests/fft.test.js --impl fast 256 impulse
215
+ ```
216
+
217
+ ### Input patterns
218
+
219
+ - `impulse` - Single 1.0 at index 0
220
+ - `constant` - All 1.0 values
221
+ - `singleFreq` - Single cosine wave
222
+ - `random` - Seeded pseudorandom values
223
+
224
+ ### Test sizes
225
+
226
+ Powers of 2: 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096
227
+
228
+ ## License
229
+
230
+ ISC
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/dist/swap.wasm ADDED
Binary file
package/index.js ADDED
@@ -0,0 +1,80 @@
1
+ import { readFile } from "fs/promises";
2
+ import { fileURLToPath } from "url";
3
+ import { dirname, join } from "path";
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const distDir = join(__dirname, "dist");
7
+
8
+ /**
9
+ * Load and instantiate a WASM module
10
+ * @param {string} filename - Name of the wasm file in dist/
11
+ * @returns {Promise<WebAssembly.Instance>}
12
+ */
13
+ async function loadWasm(filename) {
14
+ const wasmPath = join(distDir, filename);
15
+ const wasmBuffer = await readFile(wasmPath);
16
+ const wasmModule = await WebAssembly.compile(wasmBuffer);
17
+ return WebAssembly.instantiate(wasmModule);
18
+ }
19
+
20
+ /**
21
+ * Complex FFT with f64 precision (1.4-1.9x faster than fft.js)
22
+ *
23
+ * Exports:
24
+ * - memory: WebAssembly.Memory
25
+ * - precompute_twiddles(n: i32): void
26
+ * - fft_stockham(n: i32): void
27
+ * - ifft_stockham(n: i32): void
28
+ *
29
+ * Input: interleaved complex [re0, im0, re1, im1, ...] as Float64Array
30
+ */
31
+ export async function createFFT() {
32
+ return loadWasm("fft_combined.wasm");
33
+ }
34
+
35
+ /**
36
+ * Complex FFT with f32 precision (up to 2.6x faster than fft.js)
37
+ *
38
+ * Exports:
39
+ * - memory: WebAssembly.Memory
40
+ * - precompute_twiddles(n: i32): void
41
+ * - fft(n: i32): void
42
+ * - ifft(n: i32): void
43
+ *
44
+ * Input: interleaved complex [re0, im0, re1, im1, ...] as Float32Array
45
+ */
46
+ export async function createFFTf32() {
47
+ return loadWasm("fft_stockham_f32_dual.wasm");
48
+ }
49
+
50
+ /**
51
+ * Real FFT with f64 precision
52
+ *
53
+ * Exports:
54
+ * - memory: WebAssembly.Memory
55
+ * - precompute_twiddles(n: i32): void
56
+ * - rfft(n: i32): void
57
+ * - irfft(n: i32): void
58
+ *
59
+ * Input: real values as Float64Array of length N
60
+ * Output: N/2+1 complex bins (interleaved) for positive frequencies
61
+ */
62
+ export async function createRFFT() {
63
+ return loadWasm("fft_real_combined.wasm");
64
+ }
65
+
66
+ /**
67
+ * Real FFT with f32 precision (beats fftw-js at all sizes)
68
+ *
69
+ * Exports:
70
+ * - memory: WebAssembly.Memory
71
+ * - precompute_twiddles(n: i32): void
72
+ * - rfft(n: i32): void
73
+ * - irfft(n: i32): void
74
+ *
75
+ * Input: real values as Float32Array of length N
76
+ * Output: N/2+1 complex bins (interleaved) for positive frequencies
77
+ */
78
+ export async function createRFFTf32() {
79
+ return loadWasm("fft_real_f32_dual.wasm");
80
+ }
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@emnudge/wat-fft",
3
+ "version": "0.1.0",
4
+ "description": "High-performance FFT in WebAssembly",
5
+ "license": "ISC",
6
+ "author": "EmNudge",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/emnudge/wat-fft"
10
+ },
11
+ "keywords": [
12
+ "fft",
13
+ "rfft",
14
+ "fourier",
15
+ "transform",
16
+ "wasm",
17
+ "webassembly",
18
+ "dsp",
19
+ "signal-processing",
20
+ "audio"
21
+ ],
22
+ "type": "module",
23
+ "exports": {
24
+ ".": {
25
+ "import": "./index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "index.js",
30
+ "dist/*.wasm"
31
+ ],
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "scripts": {
36
+ "test": "npm run test:swap && npm run test:reverse_bits && npm run test:fft",
37
+ "test:all": "npm run test && npm run test:rfft && npm run test:property && npm run test:boundary && npm run test:correctness && npm run test:output-order",
38
+ "test:output-order": "node --test tests/output-order.test.js",
39
+ "test:swap": "node tests/swap.test.js",
40
+ "test:reverse_bits": "node tests/reverse_bits.test.js",
41
+ "test:permutation": "node tests/permutation.test.js",
42
+ "test:fft": "node tests/fft.test.js",
43
+ "test:rfft": "node --test tests/rfft.test.js",
44
+ "test:f32": "node tests/fft_f32_dual.test.js",
45
+ "test:property": "node tests/fft.property.test.js",
46
+ "test:boundary": "node --test tests/boundary.test.js",
47
+ "test:butterfly": "node tools/butterfly_tester.js",
48
+ "test:correctness": "node --test tests/correctness/*.test.js",
49
+ "test:correctness:roundtrip": "node --test tests/correctness/fft.roundtrip.test.js",
50
+ "test:correctness:parseval": "node --test tests/correctness/fft.parseval.test.js",
51
+ "test:correctness:linearity": "node --test tests/correctness/fft.linearity.test.js",
52
+ "test:correctness:shift": "node --test tests/correctness/fft.shift.test.js",
53
+ "test:correctness:reference": "node --test tests/correctness/fft.reference.test.js",
54
+ "test:correctness:known": "node --test tests/correctness/fft.known-values.test.js",
55
+ "debug:stockham": "node tools/wasm_compare.js",
56
+ "debug:index": "node tools/index_visualizer.js",
57
+ "debug:perm": "node tools/permutation_validator.js",
58
+ "debug:ref": "node tools/stockham_reference.js",
59
+ "build": "node build.js",
60
+ "bench": "node benchmarks/fft.bench.js",
61
+ "bench:rfft": "node benchmarks/rfft.bench.js",
62
+ "bench:f32": "node benchmarks/fft_f32_dual.bench.js",
63
+ "bench:rfft32": "node benchmarks/rfft_f32_dual.bench.js",
64
+ "lint": "oxlint .",
65
+ "format": "oxfmt --write .",
66
+ "format:check": "oxfmt --check ."
67
+ },
68
+ "devDependencies": {
69
+ "fast-check": "^4.5.3",
70
+ "fft-js": "^0.0.12",
71
+ "fft.js": "^4.0.4",
72
+ "fftw-js": "^0.1.4",
73
+ "kissfft-js": "^0.1.8",
74
+ "kissfft-wasm": "^2.0.1",
75
+ "oxfmt": "^0.26.0",
76
+ "oxlint": "^1.41.0"
77
+ }
78
+ }