Woodblock Simulator — web app#
Interactive browser implementation of the physical model specified in ../woodblock.md (reference implementation: ../woodblock.py). The algorithm itself is written in MATLAB syntax, in ../matlab/*.m, and executed client-side by numbl inside a Web Worker; the TypeScript here is only the UI, the plots, the WAV encoder, and the marshalling of parameters and tensors in and out of the numbl runtime.
The signal chain: Hunt-Crossley mallet contact, free-free bar modes two-way coupled to a Helmholtz cavity, retarded-monopole radiation to the listener point, and Kaiser-windowed anti-aliased decimation to 48 kHz.
Usage#
npm install
npm run dev # development server
npm run build # production build in dist/
npm run selftest # run ../matlab/woodblock_validate.m through numbl in Node
The self-test reproduces the woodblock.py reference diagnostics (contact 0.301 ms at 794 N, 6.132 Pa / 109.7 dB SPL at the default listener) and the four validation listener positions from woodblock.md §7. The MATLAB code can also be run directly: cd ../matlab && numbl run woodblock_demo.m (or woodblock_validate.m).
The solver#
The reference implementation integrates the whole strike with RK4. The MATLAB implementation instead exploits that the system is nonlinear only while the mallet is in contact (a fraction of a millisecond): it runs RK4 until the mallet has provably separated (receding, and further from the surface than a bound derived from the current modal energy), then evolves the remaining coupled linear body+cavity system in closed form from one eigendecomposition of the (2N+2) system matrix, evaluated vectorized over the time axis. The free-phase solution is exact in time, and the results match the reference to display precision on every published diagnostic.
Reading and editing the code in the app#
The Code button opens the MATLAB source in a CodeMirror editor with MATLAB syntax highlighting. Every .m file in ../matlab is listed, tagged by whether the app executes it or it is a CLI entry point. The sources are editable: an edit takes effect on the next render, so changing the physics in the editor is heard and plotted the same way moving a slider is. Editing sqrt(12) to sqrt(48) in the pitch prefactor, for instance, halves every partial.
Edits live in memory only. They are deliberately not persisted, so a reload restores the code the app shipped with; "Revert file" and "Revert all" undo them sooner, and a dot marks the files that differ from the shipped source. A fault in edited code is reported with its file and line (numbl skips a file it cannot parse and then fails at the call site, so the worker captures the parse warning and reports that instead), the failed render leaves nothing playable, so Play and Download go dead until a render succeeds, and reverting recovers.
How rendering is tiered#
Nothing renders on its own: the Render preview button runs a fast pass (oversample 8, 24 radiating elements), Render full runs the full-quality pass (oversample 16, 48 elements), and either can be cancelled while it runs. The status shows the stage, a progress bar and the elapsed time. While the current result is a preview, the Play and Download buttons and the status badge say so. The worker runs each stage as a separate numbl execution and keys its caches by tier: geometry, material, damping, mallet, and cavity parameters invalidate the solve; listener and slit positions and block height only re-run radiation; pre-delay, normalization, and bit depth only re-run the output stage. Intermediate tensors stay inside the worker as numbl RuntimeValues. Moving the microphone after a full render reuses the cached solve and returns a full-quality result.
The Loop button repeats the last render continuously, swapping in each new render as it completes. Parameters persist in localStorage; "Reset to defaults" restores the values in src/params.ts (which ../matlab/woodblock_defaults.m mirrors).
Layout#
../matlab/— the algorithm:woodblock_basis.m,woodblock_solve.m,woodblock_radiate.m,woodblock_output.m, pluswoodblock_render.m/woodblock_demo.m/woodblock_validate.mfor CLI usesrc/params.ts— parameter schema, defaults, tier assignment, persistencesrc/mfiles.ts— the.msources, bundled at build time and hashed for cache keying../instrument/— off-thread numbl execution with tiered caching, behind the shared track-render instrument interface (also used by midiboot)src/components/— 3D scene (three.js), parameter panel, code panel and editor, plots (waveform, spectrum, spectrogram, contact force, animated mode shapes)src/selftest.ts— Node harness for the MATLAB validation script