|
1 | 1 | # resonato**rs** |
2 | 2 |
|
3 | | -A Rust implementation of Alexandre François's [Resonate algorithm][paper] for low-latency spectral analysis, with Python and WebAssembly bindings. |
| 3 | +A Rust implementation of Alexandre François's [Resonate algorithm][resonate] for low-latency spectral analysis, with Python and WebAssembly bindings. |
4 | 4 |
|
5 | 5 | [](https://crates.io/crates/resonators) |
6 | 6 | [](https://pypi.org/project/resonators/) |
@@ -33,16 +33,17 @@ It's based on Alexandre's reference implementation, [noFFT][nofft], which is wri |
33 | 33 | - General-purpose STFT or CQT analysis: use [librosa](https://librosa.org/) or similar |
34 | 34 | - Offline batch where FFT's O(N log N) per frame is fine |
35 | 35 |
|
36 | | -## Demo |
| 36 | +## Browser Demos |
37 | 37 |
|
38 | | - |
| 38 | +### [Live Spectrogram](https://jhartquist.github.io/resonators/spectrogram/) |
39 | 39 |
|
40 | | -*[Try it in your browser](https://jhartquist.github.io/resonators/spectrogram/).* |
| 40 | +[](https://jhartquist.github.io/resonators/spectrogram/) |
41 | 41 |
|
42 | | -Live in the browser: |
| 42 | +Loads the WASM build of the crate into an `AudioWorkletNode`, feeds it live microphone samples through a bank of 440 resonators (5 per semitone from A0 to C8), and writes the bank's magnitudes into a ring-buffer R32F texture. A WebGL2 fragment shader samples the texture, converts to dB, and applies a colormap. |
43 | 43 |
|
44 | | -- [**Spectrogram**](https://jhartquist.github.io/resonators/spectrogram/): feed your mic through a resonator bank in real time |
45 | | -- [**Benchmark**](https://jhartquist.github.io/resonators/bench/): run the WASM bank in your browser |
| 44 | +### [In-browser Benchmark](https://jhartquist.github.io/resonators/bench/) |
| 45 | + |
| 46 | +Loads the WASM build into a `Worker`, runs the bank over one second of pseudo-random noise at 48 kHz, and times the result. Reports nanoseconds per sample, microseconds per 128-sample quantum, and the percentage of `AudioWorklet` callback budget consumed at 88, 264, 440, and 880 bins. |
46 | 47 |
|
47 | 48 | ## Install |
48 | 49 |
|
@@ -114,6 +115,14 @@ for (let i = 0; i < signal.length; i++) { |
114 | 115 | const spectrogram = bank.resonate(signal, 256); // Float32Array, interleaved [re, im, ...] |
115 | 116 | ``` |
116 | 117 |
|
| 118 | +## Examples |
| 119 | + |
| 120 | + |
| 121 | + |
| 122 | +*Same trumpet sample from [librosa](https://librosa.org), rendered through two banks with different bin layouts: linear-spaced on the left, log-spaced on the right. The resonator algorithm is layout-agnostic, so you can match the bin structure to whatever analysis you're doing.* |
| 123 | + |
| 124 | +Reproduce with `uv run scripts/example.py`. |
| 125 | + |
117 | 126 | ## Benchmarks |
118 | 127 |
|
119 | 128 | Throughput of `bank.resonate(signal, hop)` measured against [noFFT][nofft] (installed from PyPI). noFFT uses Apple's Accelerate framework under the hood. |
|
0 commit comments