Perlines v2: browser audio visualizer (WebAudio + WebGL2) #1
Loading…
Reference in a new issue
No description provided.
Delete branch "web-v2"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds
web/: a zero-install static visualizer. File + mic input, band-split dB-flux onset detector, chroma/Krumhansl key estimate that tints the scene, three scenes (aurora disk, burning water, vector trails). Fresh code, ideas only from the 2013 Aethervis work; no GPL Vamp code.Verified:
cd web && npm test(10/10 synthetic clicks at two hop sizes, no false positives; silence/noise/tone give none; key reads C, Am, Bm on synthesized progressions). All three scenes render under headless Chrome (SwiftShader) with no console errors.Not verified: no human has watched this run. No real-GPU frame-time number exists (
web/BENCH.mdhas a software-rasterizer run only; burning water is 46 ms there and is the scene to check on a GPU). Mic path, real music, real display untested.The existing Fensalir C# client is untouched; README front door now points at both.
Onset detector, update (commit
908e8dc). Rewritten against a deterministic synthetic bench,web/tools/onset-bench.mjs(npm run bench:onsets, about 30 s, no network). Corpus: 81 synthesized signals of 14 s (kick/snare/hat patterns at 90/120/150 bpm, three master levels 0/-20/-40 dB, three beds: none, bass drone + pink noise, louder). Scored at the page's 30 fps rate (hop 1600 at 48 kHz) and at full rate (hop 512). An onset counts as hit when a detection lands within -20..+90 ms of the frame-window end; coincident kick+snare count as one onset.The old detector's hit rate fell with level (-40 dB: 19.9% at 30 fps); the new one is flat across levels (87.2-87.5%). On the page's own
DemoFeedat 30 fps (20 s): old 24/37 kicks, new 37/37 (and 74/74 quarter-beat events vs 24/74). That feed is synthetic and written by the same author as the detector, so it flatters.Costs: the new detector's median timing at 30 fps is 8 ms worse than before it looked; it reads two previous frames, so a transient is picked a frame later. Remaining misses are mostly kicks under a loud bass bed and 16th hats at 150 bpm.
Still not verified (updated): all of the above is synthetic. The corpus was adjusted while it was built (recorded in the commit message), the tuning parameters were chosen on the same corpus they are scored on (no held-out set), and the test floors use a one-third subset of it. Nobody has heard this; no real music has been run through the detector; no real-GPU bench; no human has watched any scene. The numbers say nothing about whether onsets will feel right.
🤖 Generated with Claude Code
Maintainer pass (2026-11-10). Diff is additive under web/ plus a README edit; merges into main without conflict and touches nothing of the C# Fensalir client.
web/test/dsp.test.mjs+onset.test.mjs: 7 passed (note:npm testruns only dsp.test.mjs). Falsification by reading: needs WebGL2 only (guard present, message shown otherwise), RGBA8 feedback targets (no float-texture or colour-buffer-float extension to be missing), optional EXT_disjoint_timer_query. NEVER RUN ON A REAL GPU: BENCH.md numbers are SwiftShader software rasterisation only (water scene 46 ms p50 there, the one to watch at 4K/high-dpi) and no human has watched it. Failure risks on a real GPU: frame-time budget for the water scene (3x fbm per pixel), shader precision on mobile, trail ghosting from 8-bit persistence. None blocks main: it is a self-contained static folder behind README text that already says unwatched. Merging with that caveat.