@maruaudio/dsp/oscillators/formant ports DaisySP's FormantOscillator: a sine at the formant frequency whose phase restarts at every carrier cycle, so the carrier sets the pitch and the formant the resonance. The restart is a discontinuity, band-limited with BLEP residuals at its sub-sample time. A phase shift, in turns, is applied as an explicit increment on the next tick. State and arithmetic are f32, and the output is one sample late.
Parameters
| Path | Setter | Range as coded | Default | Unit |
|---|---|---|---|---|
carrierFrequency | setFormantOscillatorCarrierFrequency | frequency / sampleRate clamped to −0.25..0.25 | 0 | Hz |
formantFrequency | setFormantOscillatorFormantFrequency | Same signed clamp | 100 | Hz |
phaseShift | setFormantOscillatorPhaseShift | Unclamped; stores new − current as a one-tick increment | 0 | turns |
gain | setFormantOscillatorGain | 0 to 1 | 1 | linear |
Lifecycle
initFormantOscillatorNode(sampleRate) starts with a zero phase-shift history, so the first tick is deterministic. Then setters → formantOscillatorNodeTick per sample → resetFormantOscillatorNode, which clears phases, residuals and the phase shift. prepareFormantOscillatorNodeSampleRate re-derives both increments from the stored Hz values.
When to use it
A voice whose formant frequency stays fixed while the carrier, and so the pitch, moves, with phase-shift modulation of the formant sine.
Limits
- Mono sample tick, one sample of latency. The tick does not apply
gain; the Graph node multiplies by it. - The phase-shift increment is consumed by the next tick and cleared; two setter calls before a tick keep only the last.
- Phases wrap only upward (at 1). With the default carrier of 0 Hz the carrier never resets.