# Oscillators, envelopes and voices

> Build instruments from oscillators, envelopes, voice engines and physical resonators.

Canonical: https://maru.audio/docs/dsp-synthesis
Documentation index: https://maru.audio/llms.txt

An instrument turns note events into sound. You can compose an oscillator,
envelope and filter yourself, reuse a prepared voice engine, or excite a
physical resonator. The module still owns its identity, parameters, presets,
MIDI ports and face.

## Start with a sound source

```ts
import {
  initOscillatorNode, setOscillatorNodeFrequency,
  setOscillatorNodeWaveform, oscillatorNodeTick,
} from "maruaudio/dsp/oscillators/polyblep"

const oscillator = initOscillatorNode(48_000)
setOscillatorNodeWaveform(oscillator, 1) // 0 sine, 1 saw, 2 square, 3 triangle
setOscillatorNodeFrequency(oscillator, 220)
// Call once per audio frame, after preparation:
const sample = 0.2 * oscillatorNodeTick(oscillator)
```

This is a continuous source. For a played instrument, add an amplitude envelope,
voice allocation and note-on/off handling. `envelopes/adsr` exposes
`initAdsrNode`, attack/decay/sustain/release setters, `adsrNodeGateOn`,
`adsrNodeGateOff` and `adsrNodeTick`; multiply the oscillator by the envelope.
Gate-off begins release, so keep rendering until the voice finishes.

The [Processor instrument starter](https://maru.audio/docs/processor-module.md#start-with-a-complete-example)
connects these responsibilities in a runnable project. Start there when your
goal is an instrument you can play and publish.

## Pick the level of reuse

| Approach | Useful starting points | Your responsibility |
| --- | --- | --- |
| Oscillator-based synth | PolyBLEP, wavetable, variable-shape or formant oscillators | Pitch, envelopes, filters, notes, allocation and mix. |
| Reusable voice engine | Subtractive, FM, pluck, modal-struck or sampler voices | Map product controls/events/resources into that engine’s lifecycle. |
| Physical model | Modal resonators, struck exciters, felt contact and string recipes | Excitation, model data, decay, radiation/readout and musical calibration. |

Unison is a stack of oscillator lanes for one note; polyphony is the number of
simultaneous notes. Use `voices/unison` for lane detune/spread and the prepared
voice pools for note allocation. `voices/mono-performance` and
`voices/portamento` supply note priority, articulation and glide decisions.
The [sampling reference](https://maru.audio/docs/dsp-sampling.md) covers sample-based voices separately.

## Prepare for musical transitions

Allocate every voice’s state before rendering. Decide how repeated notes,
sustain, release, stealing and a changing voice limit behave. Retire a stolen
voice through a short transition rather than cutting a nonzero sample.
Use phase-aware oscillator reset when a note restart needs matching triangle
history. Resetting all voices on every note loses overlapping notes and tails.

Firmware-derived engines have specific model selections, rates and block
formats. In particular, the Warps core is fixed to 96 kHz/60-frame PCM16; its
stream adapter adds cadence buffering, not host-rate conversion. Clouds still
has pending target qualification, and Plaits exposes only its listed engines.
Choose these deliberately rather than assuming a generic oscillator interface.

## Toolkit reference

Import paths below are suffixes of `maruaudio/dsp/`. Use the exported types
and setters in your installed version for complete signatures and defaults.

### Oscillators

| Import suffix | Purpose | Selected API |
| --- | --- | --- |
| `oscillators/polyblep` | Sine, saw, square and triangle source with pitch offsets and band-limited discontinuity treatment. | `initOscillatorNode`, `oscillatorNodeTick` |
| `oscillators/lissajous-duo` | Stereo dual oscillator with an integer frequency ratio driven by one master phase. | `initLissajousDuoNode`, `setLissajousDuoNodeWaveform` |
| `oscillators/daisysp-blep` | DaisySP polynomial step/integrated-step corrections, turn-based sine and clamp helpers. | `daisyClamp`, `daisyThisBlepSample` |
| `oscillators/band-limited-table` | Band-limited wavetable playback: per-frame FFT into a sixteen-level half-octave pyramid (256 down to 1 harmonic, like PeriodicWave), Nyquist-safe level crossfading, cubic cycle interpolation, and linear frame morphing. | `initBandLimitedTable`, `bandLimitedLevelOffset` |
| `oscillators/variable-shape` | DaisySP VariableShapeOscillator port: a hard-syncable saw/triangle/square morph with band-limited pulse-edge and wrap transitions bounded to two per sample. | `initVariableShapeOscillatorNode`, `variableShapeOscillatorNodeTick` |
| `oscillators/z` | DaisySP ZOscillator port: a phase-distortion carrier contour multiplied by a formant discontinuity, with the discontinuity reset band-limited and shape/mode double-buffered. | `initZOscillatorNode`, `zOscillatorNodeTick` |
| `oscillators/formant` | DaisySP FormantOscillator port: a windowed-sine formant generator whose carrier reset is band-limited, with the phase shift applied as an explicit per-sample increment. | `initFormantOscillatorNode`, `formantOscillatorNodeTick` |

### Envelopes

| Import suffix | Purpose | Selected API |
| --- | --- | --- |
| `envelopes/adsr` | Exponential ADSR envelope state machine in VCA form over the shared one-pole coefficient/step and stage thresholds: gate-on is a full retrigger, gate-off releases from the current level. | `initAdsrNode`, `adsrNodeTick` |
| `envelopes/linear-ar` | Linear attack/release and optional AHDSR amplitude envelope; release starts from the current level. | `createLinearArState`, `linearArTick` |
| `envelopes/grain-windows` | Hann, Tukey, exponential, reversed exponential and triangle grain windows, plus curve rendering and reading. | `grainWindowValue`, `fillGrainWindowCurve` |
| `envelopes/overshoot-adsr` | DaisySP exponential-style ADSR with overshooting stage targets and soft/hard retrigger. | `initOvershootAdsrNode`, `overshootAdsrNodeTick` |

### Noise

| Import suffix | Purpose | Selected API |
| --- | --- | --- |
| `noise/coloured` | Deterministic coloured-noise source: seed policy, [-1,1) white mapping, pink/brown colour filters, fixed-crossover signed tone tilt and output level. | `initNoiseNode`, `noiseNodeTickWhite` |
| `noise/xorshift32` | Unsigned xorshift32 transition and conversion to white noise; caller retains the seed/state. | `xorshift32NextU32`, `rawU32ToBipolar` |
| `noise/newlib-rand` | Seeded newlib-compatible integer random sequence for firmware-derived engines. | `initNewlibRand`, `seedNewlibRand` |
| `noise/record-texture` | Deterministic crackle, dust and mains-hum generators with prepared scalar/filter state. | `initRecordTexture`, `recordTextureTick` |

### Physical models

| Import suffix | Purpose | Selected API |
| --- | --- | --- |
| `physical/modal` | Two-pole modal recurrence with displacement/velocity taps, mode roll-off and excitation shaping. | `exciterLowpassTick`, `modalPoleRadius` |
| `physical/modal-radiation` | Bounded radiation weighting and displacement/velocity readout with stereo gain. | `modalRadiationFrequencyWeight`, `modalRadiationReadout` |
| `physical/modal-table` | Prepare modal recipe tables with bounded mode counts, pitch-scaled frequencies and decay. | `modalTableSlot`, `modalTableBoundedModeCount` |
| `physical/modal-resonator` | Single two-pole resonator with T60 decay, excitation and gain/readout. | `initModalResonatorNode`, `modalResonatorNodeTick` |
| `physical/modal-resonator-bank` | Prepared 16-mode resonator banks and packed multi-bank pools; common excitation and displacement/velocity/radiation outputs. | `initModalResonatorBank`, `modalResonatorBankTick` |
| `physical/piano-scale` | Provisional per-key string/hammer geometry, mass, tension and tuning equations for piano models. | `createPianoKeyScale`, `pianoHammerContactDuration` |
| `physical/felt-hammer` | Nonlinear felt contact and hammer momentum against a passive load; no returning-wave feedback or hysteresis. | `createFeltHammer`, `feltHammerTickRealtime` |
| `physical/struck` | Reusable struck-instrument excitation: velocity, hardness, contact time, noise, seeding and size-to-decay laws. | `struckVelocityGain`, `struckEffectiveHardness` |
| `physical/strike` | Per-mode excitation gains at the moment of contact: free-free bar and gong/kettle mode-shape weights with a mallet-width floor, plus the contact-time velocity tilt across the bank. | `strikeBarShape`, `strikeGongShape` |
| `physical/mallet` | Beater contribution to a struck plate's spectrum: softness-driven per-mode spectral tilt, a bounded normalized half-sine contact-force pulse, and the constant-energy roughness residual gain. | `malletModeRolloff`, `malletContactForce` |
| `physical/bloom` | Tam-tam nonlinear upward energy cascade as a per-mode arrival-time split: deferred excitation fraction, one-pole rise coefficient, envelope step and the audible per-mode gain recombination. | `bloomModeFraction`, `bloomRiseCoefficient` |

### Voice engines and performance

| Import suffix | Purpose | Selected API |
| --- | --- | --- |
| `voices/stages` | Oscillator, envelope and filter stages used to compose a subtractive voice. | `polyBlep`, `oscSineSample` |
| `voices/note-stack` | Held-note stack for mono and legato play modes: held flags, per-note velocity, press order and last-note priority lookup. | `initNoteStack`, `noteStackPush` |
| `voices/grain-pool` | Bounded granular voice storage and scheduling over prepared sample data. | `initGrainPool`, `grainPoolRenderFrame` |
| `voices/polyphonic-pool` | Bounded note-slot allocation with same-note retrigger and voice-stealing policy. | `initPolyphonicVoicePool`, `boundedPolyphonicCapacity` |
| `voices/subtractive` | Subtractive synth voice composition over shared oscillators, envelopes and filters. | `initSubtractiveVoice`, `voiceTick` |
| `voices/oscillo` | Prepared Oscillo synthesis voice; use its own parameter and note lifecycle. | `initOscilloVoice`, `oscilloLfoTick` |
| `voices/gamelan` | Prepared gamelan-style struck voice with modal synthesis and a caller-owned stereo output bus. | `initGamelanVoice`, `gamelanExciterTick` |
| `voices/gong` | Prepared gong voice with modal synthesis and a caller-owned stereo output bus. | `initGongVoice`, `gongExciterTick` |
| `voices/fm-keys` | Four-operator phase-modulation keyboard: six routings, per-operator envelopes, eight voices and feedback shaping. | `initFmKeysVoice`, `fmKeysRenderFrame` |
| `voices/fm-algorithms` | Shared FM operator-routing algorithms and stable algorithm lookup. | `fmWiringFromMatrix`, `dx7Algorithm` |
| `voices/drum-kit-model` | Shared drum-kit model data and contracts for percussion consumers. | `drumVoiceForNote`, `drumVoiceById` |
| `voices/fm-core` | Prepared operator-count-flexible phase-modulation graph with weighted source-to-target routes, deterministic one-sample feedback for cyclic connections, and independent carrier output gains. | `createFmCoreState`, `resetFmCoreState` |
| `voices/mouth` | Monophonic glottal source and vocal-tract waveguide with nasal branch, constrictions, turbulence and a reverb tail. Caller supplies noise. | `initMouthVoice`, `mouthTick` |
| `voices/modal-struck` | Twelve-slot stereo struck-resonator pool with recipe/note tables, velocity-sensitive excitation, release and bounded tail retirement. | `initModalStruckState`, `modalStruckV2VoiceTick` |
| `voices/phase-7` | Six-operator FM instrument: 32 routings, operator/pitch envelopes, LFO, unison, mono/poly modes, portamento and pitch bend. | `phase7Tick`, `phase7Ratio` |
| `voices/rings` | Rings modal-model resonator core with original parameter laws, bounded polyphony, separate odd/even taps and independent signal inputs; qualification remains module-owned. | `initRingsState`, `tickRings` |
| `voices/pluck` | Twelve-voice extended Karplus–Strong strings with pick/noise excitation, stiffness, loss, body resonances and stereo detune. | `createPluckVoiceState`, `pluckTick` |
| `voices/stiff-string-piano` | Register-scaled modal/shared-load/waveguide piano recipe with felt contact and reduced secondary resonances. | `createStiffStringPiano`, `stiffStringPianoTick` |
| `voices/chord-voicing` | Root-position, voice-led, drop-2 and spread MIDI voicings with an optional bass note. | `sortAscending`, `voiceChord` |
| `voices/chord-colour` | Scale-aware added chord tones, avoid-note rules and a decaying pitch-class histogram. | `createChordColour`, `colourIntervalClassConsonance` |
| `voices/portamento` | Exact-duration semitone glide with an explicit preparation and note-transition lifecycle. | `initPortamento`, `tickPortamento` |
| `voices/mono-performance` | Held-note selection, note priority and mono/legato retrigger decisions. | `initMonoPerformance`, `resetMonoPerformanceConfiguration` |
| `voices/unison` | Symmetric detune/stereo lanes, bounded peak gain, smooth lane-count transitions and optional deterministic phase seeds. | `initUnison`, `tickUnison` |
| `voices/clouds` | Original Clouds engine translation; only the initial model is supported and target qualification is pending. | `initCloudsState`, `processCloudsBlock` |
| `voices/peaks` | Firmware-derived Twin ADSR/Split AD envelope function with independent gates; other modes are explicitly unsupported. | `initPeaksState`, `tickPeaksRaw` |
| `voices/warps` | Firmware-derived crossmodulation/vocoder and frequency/phase-shifter core; requires 96 kHz, 60-frame interleaved PCM16 processing. | `createWarpsState`, `processWarpsBlock` |
| `voices/warps/controls` | Warps ADC-domain control scaling and smoothing, with explicit connection presence; no physical voltage/jack interface. | `createWarpsControlState`, `resetWarpsControlState` |
| `voices/warps/stream` | Cadence adapter for the 96 kHz PCM16 Warps core, retaining MAIN/AUX outputs and adding 60 frames; does not resample. | `createWarpsStreamState`, `processWarpsStream` |
| `voices/plaits` | Firmware-derived Voice supporting the virtual-analog and additive engines; other engine selections are silent. | `initPlaitsState`, `tickPlaits` |

Return to [DSP fundamentals](https://maru.audio/docs/dsp-fundamentals.md) for I/O, lifecycle,
units and the category map.
