@maruaudio/dsp/envelopes/linear-ar is the sample player's linear amplitude envelope over a bounded pool of voices, as functions over preallocated typed arrays. Ramps move one f32 step per frame, step = fround(1 / (seconds·rate)), or 1 for a non-positive time. Two shapes share the state. The AR shape attacks from 0 to 1, sustains at 1 and releases at its full-scale step, so a release from a partial level is proportionally shorter. The AHDSR shape adds a hold of round(hold·rate) frames at 1, a linear decay to a sustain level and a release rescaled on entry so it takes its declared time from any stage.
const env = createLinearArState(32)
linearAhdsrStart(env, v, 0.005, 0.02, 0.3, 0.6, 0.4, 48000) // note-on
if (linearArTick(env, v) === 0) retire(v) // per frame, before the read
const gain = env.level[v]Parameters
There are no setters; times and levels are passed to the start calls, in seconds, with the rate.
| Call | Arguments as coded |
|---|---|
linearArStart(state, v, attack, release, rate) | A zero attack starts at level 1 in sustain |
linearAhdsrStart(state, v, attack, hold, decay, sustain, release, rate) | Sustain clamped to 0 to 1 and rounded to f32; 1 skips the decay; a non-positive decay reaches sustain on its first frame |
linearArCutRelease(state, v, minStep) | Release at least minStep per frame: the choke gesture |
Lifecycle
createLinearArState(voices) allocates the per-voice arrays once, never resized → a start call at note-on → linearArTick(state, v) once per frame before the voice's sample is read, returning 0 when the voice ended → linearArRelease or linearArCutRelease at note-off or choke → linearArClear returns the slot to idle. Stages: 0 idle, 1 attack, 2 sustain, 3 release, 4 hold, 5 decay.
When to use it
Onsets and releases for sample playback, where the sample carries its own decay, and AHDSR shapes for percussive or held sampler zones. @maru/envelopes-adsr is the exponential alternative.
Limits
- A zero sustain ends the voice when the decay reaches it, so a percussive AHD shape retires its slot instead of rendering silence.
- Ticking before reading means a voice that reaches zero contributes nothing on that frame. A voice already releasing keeps its step on a second release.