// Interactive tutorial: how the cymbal2 solver and renderer work, from the
// physics of Samejima (2021) down to the step loop the app executes. The
// prose cites the paper's equation numbers so it can be read side by side
// with the paper itself.
import { M, Eq } from './math';
import GeometryFig from './figures/GeometryFig';
import PitchGlideFig from './figures/PitchGlideFig';
import CascadeFig from './figures/CascadeFig';
import GridFig from './figures/GridFig';
import WavenumberFig from './figures/WavenumberFig';
import StabilityFig from './figures/StabilityFig';
import HertzFig from './figures/HertzFig';
import WasherFig from './figures/WasherFig';
const PAPER_DOI = 'https://doi.org/10.1250/ast.42.314';
const SECTIONS = [
{ id: 'tut-overview', n: 1, title: 'What a render computes' },
{ id: 'tut-nonlinear', n: 2, title: 'Why the model must be nonlinear' },
{ id: 'tut-shell', n: 3, title: 'The shell and the von Kármán equations' },
{ id: 'tut-boundaries', n: 4, title: 'The washer and the free edge' },
{ id: 'tut-mallet', n: 5, title: 'The mallet: head, stick, grip, hand' },
{ id: 'tut-grid', n: 6, title: 'Discretizing space: the grid' },
{ id: 'tut-wavenumber', n: 7, title: 'One wavenumber at a time' },
{ id: 'tut-time', n: 8, title: 'Marching in time' },
{ id: 'tut-sound', n: 9, title: 'From motion to sound' },
{ id: 'tut-departures', n: 10, title: 'Where the implementation departs from the paper' },
{ id: 'tut-refs', n: 11, title: 'Credits and references' },
];
function PipelineDiagram() {
const box = (
x: number, y: number, w: number, h: number, name: string, sub: string[],
) => (
An interactive walk through the theory and the implementation behind this simulator. The physical model is due to Toshiya Samejima (Faculty of Design, Kyushu University):{' '} “Nonlinear physical modeling sound synthesis of cymbals involving dynamics of washers and sticks/mallets,” Acoustical Science and Technology{' '} 42(6), 314–325 (2021) , which itself builds on Bilbao's nonlinear shell synthesis (2010). Equation numbers below, written (1), (20), and so on, are the paper's, so this page can be read beside it. Where the implementation departs from the paper in order to run stably or quickly, Section 10 says exactly how.
Nothing in this app is a recording, an oscillator bank, or a filter tuned to sound like a cymbal. Pressing Render integrates the equations of motion of three coupled mechanical systems, sample by sample, several hundred thousand times: a thin bronze shell (the cymbal itself), the felt washer it is mounted on, and the mallet striking it, the mallet being a flexible stick held by a moving hand with an elastic head on its tip. The sound you hear is the vertical acceleration of one point on the shell's surface, read off the simulation like a contact pickup.
The whole computation is written in MATLAB syntax, in the .m files
you can open (and edit) with the app's Code button, and runs in your
browser. Each stage lives in its own file:
The first three boxes are precomputation: they build the grid and assemble, then
invert, the small matrices the time loop applies at every step. The loop itself,
in cymbal2_sim.m, is where the minutes go (or the seconds, when the
browser exposes WebGPU and the loop runs on the GPU). The sections below follow
this pipeline: first the physics being solved (Sections 2 to 5), then how it is
discretized and integrated (Sections 6 to 8), then how the motion becomes audio
(Section 9).
A linear model of a struck plate is a fixed set of modes: the strike decides how much energy each mode receives, and from then on each rings at its own constant frequency and decays. Whatever spectrum exists at the moment of impact is the spectrum forever after, only quieter. A real cymbal does something a linear model cannot: struck hard, its sound changes shape after the strike. Pitches glide, and the bright, noise-like wash of a crash builds up over several hundred milliseconds, well after the stick has left. Chaigne, Touzé and Thomas called cymbals “nonlinear percussion instruments” for this reason, and Samejima's paper opens with the same observation.
The mechanism is geometric. A flat plate can bend without stretching, but a plate deflected into a curve, or a shell deflected at all, must stretch its own mid-surface, and the membrane tension this creates acts back on the bending motion. The effect grows as the square of the deflection measured in plate thicknesses: negligible for a whisper-quiet tap, dominant for a crash, where the shell moves by tens of thicknesses. Two small experiments show what this coupling does, and both are audible: each play button integrates the system's equations right here in the page and renders the result. The first is the simplest system that has it, a single oscillator whose spring stiffens with displacement:
The second experiment shows the other, more consequential effect: nonlinearity couples modes to each other, so energy placed low in the spectrum migrates upward. Here is a chain of masses with a quadratic geometric term in its springs (the Fermi–Pasta–Ulam system), started with all of its energy in its lowest mode:
Both effects, the amplitude-dependent detuning and the upward cascade, emerge in the shell model of the next section from a single nonlinear term. Neither is put in by hand. This is the sense in which the crash is computed rather than modeled: hit the simulated shell gently and it rings like a bell; hit it hard and the cascade fills the spectrum, because the equations say so.
A real cymbal has a raised cup and a gently tapered bow. Following Bilbao (2010),
the paper replaces both by one shallow spherical cap of radius{' '}
The price of this simplification is real and audible: the linear spectrum is that
of an idealized cap, not of a hammered, lathed instrument, and no irregularity
appears anywhere in the model. What it buys is a formulation in which the strong
nonlinearity is actually computable. The transverse deflection{' '}
Reading Eq. (1) term by term:
The remaining two terms are the shell physics. The function
This closed loop, deflection creates stress (2), stress deflects (1), is the
engine of everything in Section 2. Because
Fourth-order equations need two boundary conditions at each edge. At the outer rim{' '}
The inner boundary is the paper's first main contribution. Earlier work (Bilbao
2010) clamped the shell rigidly at its center, but a mounted cymbal is nothing
like clamped: it sits on a felt washer, and visibly bounces and rocks on it when
struck. Samejima models the washer as a mass–damper–spring per unit
length of the mounting circle
The paper measures the stiffness of an actual washer,{' '}
And the audible modes see a compliant inner edge instead of a rigid one, which
shifts the low-order resonances; the paper's Fig. 8 shows exactly this between its
clamped and impedance-supported calculations, and its Fig. 9 shows the mode shapes
that appear only when the support may move, such as the (0,0) mode in which the
cymbal moves as one piece. The app defaults to the washer support;{' '}
support_clamped restores the rigid clamp of the earlier literature
(Eqs. (12), (13)) for comparison.
The paper's second main contribution is taking the striking mechanism seriously. Most synthesis work injects a prescribed force pulse (a raised cosine, say) at the strike point. Here the force is not prescribed at all: it is whatever comes out of a mallet, itself a dynamical system, colliding with the moving shell.
The head (mass
where
The stick is an Euler–Bernoulli beam (Eq. (35)), discretized by the
finite element method into cubic beam elements (Eq. (38)), with the head attached
at its tip. The grip is the boundary condition at the other end, and it is
the paper's third experiment: a tight grip is a clamp (displacement and rotation
both follow the hand), a loose grip lets the stick pivot against a rotational
spring
The hand closes the system: the grip end's displacement{' '}
To compute with the equations of Section 3, the shell's annulus (washer circle to
rim) is sampled on a polar grid: cymbal2_grid.m here). Spatial derivatives become central differences:
for example
The biharmonic
The grid also sets what the model can resolve. The paper estimates that with its production grid (24 by 60) the computation is reliable up to roughly the (6,5) mode near 2 kHz; the crash extends far above that, but its top octaves ride on grid modes that are dispersion-warped (Section 7 shows why), which is the main respect in which the simulated crash is duller than a real one. Raising both counts sharpens it, at a cost that grows with their product.
The implicit time step of the next section needs two elliptic solves per sample:
one to find the stress function
One subtlety is worth naming. On the discrete ring, differentiating twice in{' '}
The nonlinear terms do mix wavenumbers, deliberately: they are the cascade. They are therefore evaluated in physical space, on the grid, and transformed to the wavenumber basis only for the solves. Every time step crosses between the two representations twice.
Time advances in steps of
where
The nonlinear terms and the contact force are evaluated explicitly, at the
current step, because n_theta cuts the ladder short, energy
piles up at the cutoff and blows up where a full grid rides it out.
With the operators prebuilt, one pass through the loop in{' '}
cymbal2_sim.m is:
A full render at the defaults is about 580,000 such steps. In the browser the same loop runs either through the numbl interpreter or, when WebGPU is available, as a sequence of GPU compute passes per step, which is roughly twenty times faster; the diagnostics panel reports which path a render took.
The rendered signal is the shell's normal acceleration at the pickup point,
just as in the paper's numerical experiments (its output point is{' '}
cymbal2_output.m conditions it: a gentle DC blocker
removes the quasi-static offset the washer relaxation leaves; a windowed-sinc
filter anti-aliases and decimates from the simulation rate down to the output
rate; a short fade closes the tail; and the result is normalized to the requested
peak level.
It is worth being precise about what this signal is and is not. It is the motion of one point of the metal: a contact pickup, not a microphone. Radiating the sound into air, with the interference and directivity of a real plate source, would require the full surface velocity history and an acoustic model on top, and is not part of the paper's method. The audible consequence is that low-order modes which radiate poorly from a real cymbal are present here at full strength, so renders carry somewhat more low end than a room recording of the same instrument would. With that caveat, the paper's trial calculations, and this implementation against the demonstration recording published by the paper's authors, reproduce the features that define the instrument: the clear low-order peaks, the slow buildup of high-frequency energy after a hard stroke, the difference between a washer-mounted and a clamped cymbal, and the effect of the grip on the attack. The spectrogram panel of the simulator is the place to watch the first of these; render the Paper demo preset and look for the energy arriving above 5 kHz over the first half second.
The physics above is Samejima's throughout. Turning a published scheme into code that must run stably for arbitrary knob settings forced a small number of departures, and honesty requires naming them; the repository README states each with its full justification.
The physical model implemented by this app, the washer boundary condition, the stick/mallet system, and the numerical scheme, are the work of{' '} Toshiya Samejima (Faculty of Design, Kyushu University), published as the paper below. The defaults are the paper's measured instrument: an 18-inch medium crash on its measured washer, struck by its measured mallet. This tutorial and the implementation are the app's own; errors in either should be laid at the app's door, not the paper's.