1// Shared declarations, prepended to every kernel.
3struct Params {
4 nx: u32,
5 ny: u32,
6 n: u32,
7 histLen: u32,
8 hx: f32,
9 hy: f32,
10 dt: f32,
11 nu: f32,
12 Db: f32, // E / (12 (1 - nu^2)): bending stiffness per h^3 [Pa]
13 Cm: f32, // E / (1 - nu^2): membrane stiffness per h [Pa]
14 Gm: f32, // E / (2 (1 + nu)): membrane shear stiffness per h [Pa]
15 rho: f32, // density [kg/m^3]
16 mass: f32, // total mass [kg]
17 Ix: f32, // sum m y^2
18 Iy: f32, // sum m x^2
19 Iz: f32, // sum m (x^2 + y^2)
20 fs: f32, // audio sample rate [Hz]
21 strikeX: f32, // drumstick contact point [m]
22 strikeY: f32,
23 strikeR2: f32, // squared contact radius [m^2]
24 patchMass: f32, // mass of the contact patch [kg]
25 strikeNode: u32, // plate node nearest the contact point
26 K: f32, // Hertz contact stiffness [N/m^alpha]
27 alpha: f32, // Hertz exponent
28 stickMass: f32, // [kg]
29 patchI0: u32, // index box enclosing the contact patch (inclusive)
30 patchI1: u32,
31 patchJ0: u32,
32 patchJ1: u32,
33 patchCX: f32, // mass-weighted center of the contact patch [m]
34 patchCY: f32,
35 inPlaneMass: f32, // factor by which the in-plane inertia is scaled (1: physical)
36 invInPlaneMass: f32, // its reciprocal
37 mountX: f32, // center of the mount patch [m]
38 mountY: f32,
39 mountR2: f32, // squared mount radius [m^2]
40 mountKw: f32, // mount stiffness per unit node weight [N/m]
41 mountCw: f32, // mount damping per unit node weight [N s/m]
42 mountNode: u32, // plate node nearest the mount center (always a member)
43 mountOn: u32, // 1 when the plate sits on a mount, 0 when it is free
44};
46// Per-step parameters, addressed with a dynamic uniform offset.
47struct StepParams {
48 step: u32,
49 flags: u32, // bit 0: drumstick active
50 audioSlot: i32, // ring-buffer slot to record the velocity into (-1: none)
51 audioOut: i32, // index of this sample within the batch's output
52 sigma0: f32,
53 sigma1: f32,
54 sigmaIn: f32, // additional frequency-independent loss of the in-plane motion
55 parity: u32, // which of the two stick-state slots holds the current state
56 pad0: u32,
57 pad1: u32,
58 pad2: u32,
59 pad3: u32,
60};
62fn nodeX(i: i32) -> f32 { return (f32(i) - 0.5 * f32(P.nx - 1u)) * P.hx; }
63fn nodeY(j: i32) -> f32 { return (f32(j) - 0.5 * f32(P.ny - 1u)) * P.hy; }
65// Static per-node data, written once by the host: x = stress-free shape w0 [m],
66// y = quadrature and lumped-mass weight (the fraction of the node's four cells
67// that belong to the plate; trapezoidal weights on a full rectangle, zero
68// outside), z = thickness [m].
69@group(0) @binding(8) var<storage, read> nd: array<vec4f>;
70fn nodeWeight(i: i32, j: i32) -> f32 {
71 if (i < 0 || i >= i32(P.nx) || j < 0 || j >= i32(P.ny)) { return 0.0; }
72 return nd[u32(j) * P.nx + u32(i)].y;
73}
74// Lumped mass of a node [kg].
75fn nodeMass(i: i32, j: i32) -> f32 {
76 if (i < 0 || i >= i32(P.nx) || j < 0 || j >= i32(P.ny)) { return 0.0; }
77 let k = u32(j) * P.nx + u32(i);
78 return P.rho * nd[k].z * P.hx * P.hy * nd[k].y;
79}