@maruaudio/dsp/voices/portamento is an exact-duration glide in semitones: a retarget computes a linear per-sample step from the current pitch to the target note over a whole number of frames, and the last tick lands exactly on the target. The source header says it was extracted from Phase 7's voice. The default policy rounds pitch and step to f32; doublePrecision keeps f64, which @maru/voices-phase-7 selects (synth voices).
Parameters
| Call | Coded range and behavior |
|---|---|
initPortamento(capacity, doublePrecision = false) | One slot per voice; capacity is the caller's |
portamentoFrames(mode, seconds, rate, hadHeldNote) | Mode rounded into 0 off, 1 always, 2 only when a note was already held; seconds clamped to 0..2; returns round(seconds × rate) or 0 |
retargetPortamento(state, slot, note, frames) | Frames rounded, floored at 0; 0 frames jumps to the note at once |
tickPortamento(state, slot) | Advances one frame and returns the current pitch in semitones |
Lifecycle
initPortamento allocates four typed arrays at preparation → on a note event compute frames with portamentoFrames, then retargetPortamento → one tickPortamento per sample per slot → resetPortamento zeroes every slot and keeps the buffers and precision. Retarget and tick allocate nothing. A retarget mid-glide starts from the current value.
When to use it
A glide between notes that should take the same time at every sample rate, in mono or legato play or per polyphonic voice. The synth voices guide recommends it for new glides and keeping a product's legacy glide law where presets depend on it.
Limits
- Pitch is linear in semitones; converting to frequency is the caller's job.
- Glide time is capped at 2 seconds by
portamentoFrames. - The slot index is not range-checked.
- In the default policy a fractional value written into
currentbefore a retarget is rounded to f32, preserving the former Float32Array storage.