@maruaudio/dsp/voices/mouth is a monophonic vocal-tract physical model: an LF glottal-flow source with aspiration drives a Kelly-Lochbaum digital waveguide (44 sections at 48 kHz, stepped twice per frame) with a branching nasal cavity, fricative turbulence at constrictions, stop-release transients, portamento and an inlined Freeverb tail. The source header says it is ported from Neil Thapen's Pink Trombone (MIT) with f32 state. Noise samples are arguments, so it is deterministic.
Parameters
setMouthParam(state, index, value), clamped as coded (44-section grid):
| Index | Range | Default |
|---|---|---|
| 0 tongue index / 1 diameter | 12 to 29 (blade + 2 to tip − 3) / 2.05 to 3.5 | 12.9 / 2.43 |
| 2 constriction index / 3 diameter | −1 to the section count / −1 to 3.5 | −1 / 3 |
| 4 velum / 5 tenseness (loudness = t^0.25) / 6 glide | 0 to 1 / 0 to 1 / 0 to 1 s | 0 / 0.6 / 0.06 |
| 7 vibrato amount / 8 rate | 0 to 0.1 / 0 to 12 Hz | 0.005 / 6 |
| 9 fricative / 10 reverb mix | 0 to 1 | 0 / 0.2 |
| 11 reverb room | 0 to 1, mapped to feedback 0.7 + 0.28 × room | feedback 0.82 |
| 12 breath / 13 always voice / 14 pitch wobble | 0 to 1 | 0 / 1 / 0 |
| 15 movement speed / 16 throat | 1 to 60 / −1 to 1 | 15 / 0 |
Lifecycle
initMouthVoice(rate) keeps the historical 44-section, two-step geometry at every rate; prepareMouthVoiceSampleRate(state, rate) re-initializes in place with rate-native geometry (mouthTractSteps, mouthTractSections) and resets parameters to defaults → setMouthParam → mouthNoteOn (note clamped to 0..127; from silence the pitch jumps, else it glides) / mouthNoteOff (only the gate note) → mouthTick(state, aspirationNoise, turbulenceNoise) per frame → mouthFinishBlock every mouthBlockFrames(rate) frames (128 at 48 kHz) → resetMouthVoice clears the tract, nasal branch and reverb without reallocating.
When to use it
Keyboard-driven vowels and sung lines where tongue, constriction and velum are performance controls.
Limits
- Mono, one voice, sample tick; output at unity with no master parameter.
- The caller supplies and conditions the noise;
mouthNoiseGain(rate)keeps its power per hertz at the 48 kHz level. - Storage is sized at the maximum rate, so preparing never allocates.