@maruaudio/dsp/physical/mallet models what the beater itself contributes to a struck plate's excitation, separately from how hard it was swung. It gives a fixed per-mode spectral tilt set by the head's softness, a bounded contact force pulse (a normalised half-sine raised to a hardness-dependent exponent), and the gain of a small roughness residual. The gong voice combines them with @maru/physical-struck's contact-time laws and @maru/physical-strike's position and velocity weights.
| Function | Law |
|---|---|
malletModeRolloff(softness, mode, count) | (1 − 0.75 · softness) ^ (mode / (count − 1)); 1 for mode 0 or a one-mode bank |
malletContactForce(frame, frames, hardness) | sin(π (frame + 0.5) / frames) ^ (1.15 + 2.35 h) / (frames · (0.59 − 0.19 h)), f32 |
malletRoughnessGain(amount, hardness, frames) | amount · (0.04 + 0.18 h) / √frames, f32 |
Parameters
| Argument | Range as coded |
|---|---|
softness | Not clamped; 0 (rigid) gives weight 1 on every mode, 1 gives a base of 0.25 |
hardness | Clamped 0 to 1 in the pulse and the roughness gain |
amount | Clamped 0 to 1 |
frame, frames | The pulse is 0 outside 0 ≤ frame < frames or when frames ≤ 0 |
Lifecycle
None: stateless functions with no imports or allocation. The tilt is computed once per strike and mode; the pulse once per contact frame. Each call runs one pow or sin.
When to use it
Letting the choice of beater, from a metal hammer to a soft yarn head, change a struck plate's excitation at the same velocity, in a modal gong or bell voice.
Limits
- The fundamental always gets tilt 1, so a mallet changes the mode balance, not the fundamental's level.
- The pulse's area is held near one by a fitted divisor rather than a per-strike normalisation, so it is approximate across the contact range.
- Roughness gain falls as
1 / √frames, keeping its energy constant across contact lengths.