Build with this node

Start with a prompt in Studio, or copy it into your own coding agent.

Ask Studio

@maruaudio/dsp/voices/modal-struck is the struck-resonator pool shared by Bells, Handpan and Kalimba: a 128-entry note map with per-note recipe and mode weights over up to eight recipes, a twelve-slot stereo pool, a raised-cosine excitation through a velocity-coupled one-pole noise filter, and per-mode coupled resonators with stereo detune. A ringing voice keeps the coefficients captured at its strike; modules fill the tables through plain writer functions.

Parameters

setModalStruckV2Param quantizes to a 1e-5 grid (modalStruckQuantize), then clamps:

IndexRangeDefault
0 position (marks tables dirty)0 to 10.15
1 hardness / 2 noise / 6 stereo width0 to 10.6 / 0.1 / 0.5
3 decay scale / 4 damping / 5 size (marks dirty)0.001 to 60 / 0.001 to 60 / 0.001 to 321 / 1 / 1
7 release / 17 tail0 to 60 s / 0.01 to 60 s0.5 / 8
8 master0 to 1; 0.01 s glide while voices ring0.8
9 velocity gain exponent / 16 base gain / 10 velocity–hardness coupling0 to 4 / 0 to 4 / −1 to 12 / 0.03 / 0
11 / 12 noise cutoff min / max1 to 24000 Hz / min to 24000 Hz600 / 9600
14 / 15 excite min / max; 13 seed0.1 to 100 ms / min to 100 ms; raw u32, 0 becomes 13 / 14; 0x9e3779b9

setModalStruckVoiceCount clamps the active pool to 10..12 (default 10).

Lifecycle

initModalStruckState(rate) → voice count and parameters → when modalStruckConfigDirty is set, refill the recipe and note tables through modalStruckSetRecipe, …SetRecipeMode, …SetNoteRecipe, …SetNoteMode and clear the flag → modalStruckV2NoteOn(note, velocity) (lowest free slot, else the oldest; returns whether the note is mapped) / modalStruckV2NoteOff → modalStruckV2Tick(state, bus) per frame (or …VoiceTick per voice); the caller applies master live via modalStruckAdvanceMaster. resetModalStruckState retires every voice and restarts the strike counter, keeping tables.

When to use it

Tuned struck instruments whose notes map to a few mode recipes: bells, handpans, kalimbas.

Limits

  • Stereo, sample tick; 12 voices of up to 16 modes, 128 notes, 8 recipes.
  • The age counter advances for every note-on, mapped or not; a completed note-off ramp retires its voice.
  • Modes at or above 0.45 × fs get amplitude 0; a stolen slot fades over 192 frames.

Algorithm properties and proofs

No Lean 4 proof is mapped to this node.

Explore proofs alongside performance

Parameters

ParameterTypeSetter
Count count

Declare the product's active polyphony. `loadModalStruckV2Params` derived this from the blob header as `min(12, max(10, header))`; the same bound is applied here so a product cannot declare a pool the storage does not have or a count below the ABI's floor of 10.

floatsetModalStruckVoiceCount

Dependencies

Dependents

No other node imports this one.

Used by