/ simulated_instruments / cymbal
Sign in
simulated_instruments / cymbal
cymbal / webapp / README.md
60 lines · 7.7 KBCodeBlameHistory
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.
3a32a66Default the turbulent fluctuation offJeremy Magland 5The signal chain: a Hertz stick contact (or a seeded repeated figure, with `Strokes` above 1), the modes of a bronze shell of revolution from one finite element eigensolve per nodal-diameter order, hybridized to stand for the hammering that makes a real cymbal irregular, a nonlinear cascade of modal energy up the frequency ladder, an oscillator bank radiating through a coherent sum of surface dipoles 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/cymbal_validate.m through numbl in Node
14```
16The self-test runs the closed-form and reproducibility checks and the pinned diagnostics. The MATLAB code can also be run directly: `cd ../matlab && numbl run cymbal_demo.m` (or `cymbal_validate.m`).
18## Where the time goes
20The expensive stage is the mode basis: one generalized eigensolve per nodal-diameter order, about two seconds at the defaults, and that is exactly the piece the worker caches. Striking somewhere else, changing the stick, moving the microphone or retuning the cascade all reuse the cached modes. The synthesis that follows is an oscillator bank rather than the closed-form exponentials of the sibling `triangle` repository, because the cascade makes every amplitude time-varying; the per-frame phase advance is a unit-modulus multiply and the oscillator basis is hoisted out of the loop, so a three-second render costs about the same again.
22## Reading and editing the code in the app
5fefed3Explicit preview and full renders, as in the cymbal2 appJeremy Magland 24The 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. Zeroing the meridian curvature `cs` in `cymbal_shell.m`, for instance, decouples bending from stretching and collapses the partials back onto those of a flat disc.
5fefed3Explicit preview and full renders, as in the cymbal2 appJeremy Magland 26Edits 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.
28## How rendering is tiered
5fefed3Explicit preview and full renders, as in the cymbal2 appJeremy Magland 30Nothing 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. The worker runs each stage as a separate numbl execution and keys its caches by tier: plate geometry, material, damping, radiation scaling and discretization parameters invalidate the mode basis; the stick, the gesture, the cascade and the listener only re-run the strike process, the cascade and the radiation; pre-delay, normalization and bit depth only re-run the output stage. Intermediate tensors stay inside the worker as numbl RuntimeValues.
5fefed3Explicit preview and full renders, as in the cymbal2 appJeremy Magland 32The New seed button redraws the timing and velocities of a repeated figure without touching any other parameter (a single stroke is deterministic, so the button is disabled there). 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/cymbal_defaults.m` mirrors).
34## Layout
36- `../matlab/` — the algorithm: `cymbal_profile.m`, `cymbal_shell.m`, `cymbal_basis.m`, `cymbal_at.m`, `cymbal_point.m`, `cymbal_strikes.m`, `cymbal_rng.m`, `cymbal_cascade.m`, `cymbal_radiate.m`, `cymbal_output.m`, plus `cymbal_render.m` / `cymbal_demo.m` / `cymbal_validate.m` for CLI use
37- `src/params.ts` — parameter schema, defaults, tier assignment, persistence
38- `src/mfiles.ts` — the `.m` sources, bundled at build time and hashed for cache keying
39- `src/worker/renderWorker.ts` — off-thread numbl execution with tiered caching
a136eacMake the contact point a first-class controlJeremy Magland 40- `src/lib/profile.ts` — the cymbal meridian, mirrored from `cymbal_profile.m`, with the arclength table that converts `strike_r` to and from a radius for the scene and the picker
41- `src/components/` — strike picker, 3D scene (three.js), parameter panel, code panel and editor, plots (strokes, cascade, waveform, spectrum, spectrogram, mode map, mode shapes)
4ddcc1bCymbal simulator: shell-of-revolution modal model with a nonlinear energy cascade, numbl MATLAB reference, and interactive web appJeremy Magland 42- `src/selftest.ts` — Node harness for the MATLAB validation script
44## The cascade plot
46The plot the sibling repositories do not have. The cascade solve tracks the energy of every mode at the control rate, and the plot collapses that onto a log-frequency by time grid, so the upward flux is visible directly. Dropping `Cascade gain` to zero flattens it into horizontal streaks, every mode simply decaying where the stick left it, and the sound turns from a crash into a gong.
a136eacMake the contact point a first-class controlJeremy Magland 48## Placing the stick
50The model addresses the contact by arclength fraction along the meridian, `strike_r`, which is the right coordinate for the physics and a poor one to aim with. The cross-section at the top of the page draws the real profile to scale, with the bell, bow and edge marked and a ruler in centimetres, and both contacts are draggable: the amber marker is `strike_r` and the dim one is `roll_r2`, which even-numbered strokes land on. The strip underneath shows what the current contact actually excites, band by band, which is the quickest way to see why the bell and the edge are different instruments: a mode with `n` nodal diameters falls off as roughly `r^n` toward the axis, so at the bell an `n = 40` mode sits at 1e-22 of its rim amplitude and simply is not driven. Striking the bell puts 91 of the 378 modes into play, striking the outermost edge 178.
52There is deliberately no azimuth control. The plate is a surface of revolution and the hammering is applied as a statistical mixing with no azimuthal structure, so striking at a different azimuth is exactly equivalent to rotating the listener, which the listener coordinates already do.
3a32a66Default the turbulent fluctuation offJeremy Magland 56`Hybridization` at 0 is the ideal, perfectly round plate. Its high nodal-diameter modes cannot radiate at all, so a few low-order partials carry everything and the instrument becomes a small bell; sliding it back up is hammering the cymbal. `Fluctuation` is off at the defaults: it broadens each partial by letting its amplitude wander about the mean the cascade solves for, which on paper closes the comb into a wash and in practice adds grit, so a few tenths is as far as it is worth taking. `Stroke velocity` sweeps the whole dynamic behaviour through one physical quantity, because the cascade strength goes as the square of the amplitude: at 0.7 m/s the same cymbal pings, at 6 m/s it opens right up.
60The stroke pattern draws from a 32-bit LCG in `cymbal_rng.m` rather than MATLAB's `rand`, so a given seed produces the identical pattern in the numbl CLI, in Node, and in the browser. That is what lets the self-test pin exact impulse sums and stroke times.
↑↓ move↵openescclose