@maruaudio/dsp/voices/subtractive is one fused mono subtractive voice: a PolyBLEP oscillator into an RBJ low-pass biquad whose cutoff follows the envelope, an exponential ADSR, and gain, all through @maru/voices-stages with Math.fround at every stateful accumulation. The source header calls it a port of the osc1-plugin voice in which the filter envelope reuses the amp envelope.
Parameters
setVoiceParam(state, index, value), clamped as coded:
| Index | Range | Default | Unit |
|---|---|---|---|
PARAM_OSC_TYPE 0 | Rounded, 0 sine, 1 saw, 2 square, 3 triangle | 1 | — |
PARAM_OSC_OCTAVE 1 | Rounded, −2 to 2 | 0 | octaves |
PARAM_OSC_DETUNE 2 | −100 to 100 | 0 | cents |
PARAM_FILTER_CUTOFF 3 | 20 to 20000 | 2000 | Hz |
PARAM_FILTER_RESONANCE 4 | 0.1 to 18 | 0.7 | Q |
PARAM_FILTER_ENV_AMOUNT 5 | −8 to 8 | 0 | octaves |
PARAM_AMP_ATTACK 6 / DECAY 7 | 0 to 2 | 0.01 / 0.2 | s |
PARAM_AMP_SUSTAIN 8 / PARAM_MASTER_GAIN 10 | 0 to 1 | 0.7 / 0.8 | — |
PARAM_AMP_RELEASE 9 | 0 to 5 | 0.3 | s |
Resonance and gain glide over a 0.01 s one-pole during a note, at once when idle.
Lifecycle
initSubtractiveVoice(sampleRate) → setVoiceParam → voiceNoteOn(note, velocity) (note clamped to 0..127, velocity to 0..1; a full retrigger of phase, filter state and envelope) or voiceNoteOff(note) (releases only if that note owns the gate) → updateVoiceQuantum at each 128-frame quantum start (pitch and filter coefficients, cutoff = cutoff × 2^(amount × envelope), clamped to 10 Hz..0.45 × rate) → voiceTick per sample. To reset, init a new state. renderSubtractiveVoice renders 13-byte events to PCM16 from fresh state.
When to use it
A single-oscillator mono synth line, a bass or lead, or a reference voice for checking compiled targets against the JavaScript output.
Limits
- Mono, one voice, one sample per tick; filter and pitch refresh per 128 frames.
- The render entry allocates its output and clamps to −1..1 before PCM16; the tick path allocates nothing.