/ simulated_instruments / recorder
Sign in
simulated_instruments / recorder
recorder / webapp / README.md
42 lines · 4.9 KBCodeBlameHistory
5623b11Recorder simulator: MATLAB jet-drive model and interactive web appJeremy Magland 1# Recorder Simulator — web app
3Interactive browser implementation of the physical model described in `../README.md`. The algorithm itself is written in MATLAB syntax, in `../matlab/*.m`, and executed client-side by [numbl](https://numbl.org) 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.
5The signal chain: a transmission-line solve of the tapered bore with its tone hole lattice under the chosen fingering, a modal fit of the resonances, a sample-by-sample integration of the jet / bore feedback loop (the note is a self-sustained oscillation, not a prescribed one), a coherent sum of aperture monopoles to the listener point, and Kaiser-windowed anti-aliased decimation to 48 kHz.
7## Usage
9```
10npm install
11npm run dev # development server
12npm run build # production build in dist/
13npm run selftest # run ../matlab/recorder_validate.m through numbl in Node
14```
16The self-test runs the closed-form and reproducibility checks, the emergent register and overblow checks, and the pinned diagnostics. The MATLAB code can also be run directly: `cd ../matlab && numbl run recorder_demo.m` (or `recorder_validate.m`).
18## Why rendering is tiered the way it is
3a84d42Explicit preview and full renders, as in the cymbal2 appJeremy Magland 20Unlike the sibling instruments, nothing here is closed-form between events: a recorder is a self-oscillator, so the jet loop is integrated sample by sample and a two-second note costs a few seconds. The worker therefore runs each stage as a separate numbl execution and keys its caches by tier: bore, hole, and window parameters invalidate the per-note basis (the transmission-line solve and modal fit); the breath, the jet, and the gesture re-run only the jet integration; the listener position and the direct gain re-run only the radiation, which is a matrix multiply; output conditioning is always re-run. Intermediate tensors stay inside the worker as numbl RuntimeValues. Nothing renders on its own: the Render preview button runs a fast pass (oversample 1), Render full runs the full-quality pass, 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.
3a84d42Explicit preview and full renders, as in the cymbal2 appJeremy Magland 22The New seed button redraws the breath turbulence without touching any other parameter. 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/recorder_defaults.m` mirrors).
24## Reading and editing the code in the app
3a84d42Explicit preview and full renders, as in the cymbal2 appJeremy Magland 26The 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. Doubling `jet_conv`'s effect by halving the transit delay in `recorder_jet.m`, for instance, audibly sharpens every note and then flips the register.
3a84d42Explicit preview and full renders, as in the cymbal2 appJeremy Magland 28Edits 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.
30## Layout
32- `../matlab/` — the algorithm: `recorder_geometry.m`, `recorder_bore.m`, `recorder_basis.m`, `recorder_notes.m`, `recorder_jet.m`, `recorder_radiate.m`, `recorder_output.m`, `recorder_rng.m`, plus `recorder_render.m` / `recorder_demo.m` / `recorder_validate.m` for CLI use
33- `src/params.ts` — parameter schema, defaults, tier assignment, persistence
34- `src/mfiles.ts` — the `.m` sources, bundled at build time (`src/mfilesCore.ts` holds the hash used for cache keying)
80e74e9Add instrument/: the recorder behind the track-render interfaceJeremy Magland 35- `../instrument/` — off-thread numbl execution with tiered caching, behind the shared track-render instrument interface (also used by midiboot)
5623b11Recorder simulator: MATLAB jet-drive model and interactive web appJeremy Magland 36- `src/lib/instrument.ts` — the hole lattice and fingering chart, mirrored from `recorder_geometry.m` for the 3D scene
37- `src/components/` — 3D scene (three.js), parameter panel, code panel and editor, plots (jet flow, waveform, spectrum, spectrogram, bore admittance, standing waves)
38- `src/selftest.ts` — Node harness for the MATLAB validation script
40## A note on the seeded generator
42The turbulence noise draws from a 32-bit LCG in `recorder_rng.m` rather than MATLAB's `rand`, so a given seed produces the identical breath in the numbl CLI, in Node, and in the browser. That is what lets the self-test require two renders to be bit-identical.
↑↓ move↵openescclose