@maruaudio/dsp/envelopes/grain-windows holds the five amplitude windows a granular voice gates each grain with, as a pure function of phase and as a 512-point curve read the way Web Audio setValueCurveAtTime interpolates. The arithmetic is extracted unchanged from the Granular module's granular-bank.ts.
| Slot | Shape | Formula |
|---|---|---|
0 HANN | Raised cosine | 0.5 − 0.5·cos(2πx) |
1 TUKEY | Cosine tapers of α/2 at each end, α = 0.4, unity between | — |
2 EXPODEC | 2 % linear attack, then exp(ln(0.001)·d) down to −60 dB | — |
3 REXPODEC | Expodec read backwards | — |
4 TRIANGLE | Linear rise and fall | 2x, then 2 − 2x |
const curves = new Float32Array(GRAIN_WINDOW_COUNT * GRAIN_WINDOW_CURVE_POINTS)
fillGrainWindowCurve(curves, 0, GRAIN_WINDOW_HANN) // at init
const g = grainWindowCurveAt(curves, 0, phase) // per sampleParameters
This DSP node has no setters or state; shape, phase and the caller-owned curve are passed to each function.
| Function | Inputs as coded |
|---|---|
grainWindowValue(shape, phase) | Phase clamped to 0 to 1; an unknown shape reads as Hann |
fillGrainWindowCurve(curve, offset, shape) | Writes 512 points at phase i/511, forces both endpoints to 0 and scales so the peak is exactly 1 |
grainWindowCurveAt(curve, offset, phase) | Linear between neighbours; phase ≤ 0 or NaN returns the first point, ≥ 1 the last |
Lifecycle
Pure functions. Fill each curve once at init into caller-owned storage, then read it per sample; or evaluate grainWindowValue directly.
When to use it
Gating grains in a granular voice so the Processor and the browser engine apply identical shapes: Hann or Tukey for smooth clouds, expodec for percussive grains, rexpodec for swells.
Limits
- The slot order is a persisted parameter contract: append, never reorder.
- Expodec's formula ends at 0.001, not silence; only the rendered curve forces its endpoints to 0.
- Fixed 512-point curves; loops count to that compile-time bound.