@maruaudio/dsp/envelopes/overshoot-adsr is DaisySP's Adsr with its exact f32 semantics, as the CHOMPI firmware's sample voices use it. Each stage is a one-pole step toward a target past its end point: attack aims at 9·shape¹⁰ + 0.3·shape + 1.01 and ends on crossing 1; decay chases the sustain level; release aims at −0.01 and goes idle on crossing 0. Decay and release coefficients are 1 − exp(ln(1/e) / (t·rate)), so a stage covers 1 − 1/e of its distance in t seconds; the attack coefficient uses its own target.
const env = initOvershootAdsrNode(48000)
setOvershootAdsrAttack(env, 0.005, 0)
const level = overshootAdsrNodeTick(env, gateHigh) // per sampleParameters
Inputs are rounded to f32. Times and shape are cached: a setter with unchanged values leaves the coefficient alone. A non-positive time gives an instant stage.
| Setter | Range as coded | Default | Unit |
|---|---|---|---|
setOvershootAdsrAttack(state, time, shape) | Not clamped; shape sets the overshoot target | 0.1, shape 0 | s, curve |
setOvershootAdsrDecay / …Release | Not clamped | 0.1 / 0.1 | s |
setOvershootAdsrSustain | Above 1 becomes 1; at or below 0 becomes −0.01, which sends decay to idle | 0.7 | level |
Lifecycle
initOvershootAdsrNode(sampleRate, blockSize = 1) stores the integer rate int(sampleRate / blockSize) and sets 0.1 s stages → setters → overshootAdsrNodeTick(state, gate) per sample: a rising gate starts the attack from the current level, a falling gate the release. retriggerOvershootAdsr(state, hard) enters attack, from zero when hard. resetOvershootAdsrNode idles at zero with the gate low, keeping the settings.
When to use it
Reproducing the firmware's sample-voice envelope exactly, or a gate envelope whose attack overshoot is set by one shape control.
Limits
- One branch and one f32 step per sample;
exp,logandpowrun only in setters. The rate is an integer, as upstream; the firmware'sexpfandlogfmay differ by one f32 ulp for rare arguments.