Skip to content

EZ Web Audio / PolySynth

Class: PolySynth ​

Defined in: packages/core/src/poly-synth.ts:226

Polyphonic synthesizer with automatic voice pool management.

PolySynth manages a pool of Oscillator voices, handling allocation, recycling, and voice stealing automatically. All voices route through a shared output bus with master gain/pan controls and effect chain support.

PolySynth has no musical identity — it works with frequencies, not note names. Use frequencyMap at the application layer to convert note names to frequencies.

Example ​

typescript
import { createPolySynth, frequencyMap } from 'ez-web-audio'

const synth = await createPolySynth({
  maxVoices: 8,
  type: 'sawtooth',
  envelope: { attack: 0.01, decay: 0.2, sustain: 0.5, release: 0.3 },
  lowpass: { frequency: 2000, q: 1 }
})

// Play a chord
synth.play({ frequency: 261.63 }) // C4
synth.play({ frequency: 329.63 }) // E4
synth.play({ frequency: 392.00 }) // G4

// Add effects to all voices
const delay = createDelay({ time: 0.3, feedback: 0.4, wet: 0.3 })
synth.addEffect(delay)

// Master volume
synth.update('gain').to(0.5).as('ratio')

Extends ​

Constructors ​

Constructor ​

new PolySynth(audioContext, options?): PolySynth

Defined in: packages/core/src/poly-synth.ts:242

Parameters ​

audioContext ​

AudioContext

options? ​

PolySynthOptions

Returns ​

PolySynth

Overrides ​

TypedEventEmitter.constructor

Properties ​

audioContext ​

readonly audioContext: AudioContext

Defined in: packages/core/src/poly-synth.ts:243

Accessors ​

activeVoices ​

Get Signature ​

get activeVoices(): number

Defined in: packages/core/src/poly-synth.ts:343

Number of currently active voices.

Returns ​

number


availableVoices ​

Get Signature ​

get availableVoices(): number

Defined in: packages/core/src/poly-synth.ts:348

Number of available voice slots.

Returns ​

number


disposed ​

Get Signature ​

get disposed(): boolean

Defined in: packages/core/src/poly-synth.ts:353

Whether this PolySynth has been disposed.

Returns ​

boolean


maxVoices ​

Get Signature ​

get maxVoices(): number

Defined in: packages/core/src/poly-synth.ts:340

Maximum number of simultaneous voices.

Returns ​

number

Methods ​

_clearListeners() ​

protected _clearListeners(): void

Defined in: packages/core/src/events/typed-event-emitter.ts:192

Remove every listener registered through this emitter (via addEventListener(), on(), or once()), regardless of how many or what event type they're bound to.

Native EventTarget has no removeAllListeners(). This works around that by aborting a shared AbortSignal threaded through every addEventListener() call this class makes, then swapping in a fresh AbortController so the instance can keep accepting new listeners afterward (e.g. if it's reused before being garbage collected).

Subclasses call this from their dispose() alongside neutering dispatchEvent — the neuter stops future emits, this stops stale listener closures from being retained/invoked at all.

Returns ​

void

Inherited from ​

TypedEventEmitter._clearListeners


addEffect() ​

addEffect(effect, position?): this

Defined in: packages/core/src/poly-synth.ts:793

Add an effect to the shared output bus. All voices are affected.

Parameters ​

effect ​

Effect

The Effect instance to add

position? ​

number

Optional index to insert at

Returns ​

this

this for chaining


addEventListener() ​

Call Signature ​

addEventListener<K>(type, listener, options?): void

Defined in: packages/core/src/events/typed-event-emitter.ts:44

Add a typed event listener for known event types. Overloaded to provide type safety for known event types while remaining compatible with the native EventTarget API.

Type Parameters ​
K ​

K extends "dispose" | "voicestolen"

Parameters ​
type ​

K

The event type (key of TMap)

listener ​

(event) => void

Typed event handler

options? ​

Standard addEventListener options

boolean | AddEventListenerOptions

Returns ​

void

Inherited from ​

TypedEventEmitter.addEventListener

Call Signature ​

addEventListener(type, listener, options?): void

Defined in: packages/core/src/events/typed-event-emitter.ts:49

Add a typed event listener for known event types. Overloaded to provide type safety for known event types while remaining compatible with the native EventTarget API.

Parameters ​
type ​

string

The event type (key of TMap)

listener ​

Typed event handler

EventListenerOrEventListenerObject | null

options? ​

Standard addEventListener options

boolean | AddEventListenerOptions

Returns ​

void

Inherited from ​

TypedEventEmitter.addEventListener


changeGainTo() ​

changeGainTo(value): this

Defined in: packages/core/src/poly-synth.ts:768

Set the master gain for all voices.

Parameters ​

value ​

number

Gain from 0 (silent) to 1 (full volume)

Returns ​

this


changePanTo() ​

changePanTo(value): this

Defined in: packages/core/src/poly-synth.ts:778

Set the master pan for all voices.

Parameters ​

value ​

number

Pan from -1 (left) to 1 (right)

Returns ​

this


dispose() ​

dispose(): void

Defined in: packages/core/src/poly-synth.ts:865

Dispose this PolySynth, releasing all audio resources.

Stops all voices, disconnects the shared bus, and marks the instance as unusable. Dispose is idempotent.

Returns ​

void


emit() ​

protected emit<K>(type, detail): void

Defined in: packages/core/src/events/typed-event-emitter.ts:95

Emit a typed event with the given detail.

Creates a CustomEvent with the provided detail and dispatches it on this target. Subclasses call this internally to fire lifecycle events.

Type Parameters ​

K ​

K extends "dispose" | "voicestolen"

Parameters ​

type ​

K

The event type to emit (key of TMap)

detail ​

PolySynthEventMap[K]["detail"]

The event detail object (typed by TMap)

Returns ​

void

Inherited from ​

TypedEventEmitter.emit


getAnalyzer() ​

getAnalyzer(): Analyzer | null

Defined in: packages/core/src/poly-synth.ts:841

Get the currently attached analyzer.

Returns ​

Analyzer | null


getEffects() ​

getEffects(): readonly Effect[]

Defined in: packages/core/src/poly-synth.ts:822

Get a readonly copy of the current effects array.

Returns ​

readonly Effect[]


getGainNode() ​

getGainNode(): GainNode

Defined in: packages/core/src/poly-synth.ts:358

Returns the master GainNode (for LFO targeting and external routing).

Returns ​

GainNode


getPannerNode() ​

getPannerNode(): StereoPannerNode

Defined in: packages/core/src/poly-synth.ts:361

Returns the master StereoPannerNode (for LFO targeting and external routing).

Returns ​

StereoPannerNode


off() ​

off<K>(type, listener): this

Defined in: packages/core/src/events/typed-event-emitter.ts:167

Unsubscribe from an event.

Note: Due to native EventTarget limitations, you must provide the same listener function reference that was used when subscribing.

Type Parameters ​

K ​

K extends "dispose" | "voicestolen"

Parameters ​

type ​

K

The event type to unsubscribe from

listener ​

(event) => void

The event handler function to remove

Returns ​

this

this for chaining

Example ​

typescript
const handler = (e) => console.log(e.detail)
emitter.on('play', handler)
// later...
emitter.off('play', handler)

Inherited from ​

TypedEventEmitter.off


on() ​

on<K>(type, listener): this

Defined in: packages/core/src/events/typed-event-emitter.ts:116

Subscribe to one or more events. Supports chaining.

Type Parameters ​

K ​

K extends "dispose" | "voicestolen"

Parameters ​

type ​

The event type(s) to subscribe to (key or array of keys of TMap)

K | K[]

listener ​

(event) => void

The event handler function

Returns ​

this

this for chaining

Example ​

typescript
emitter.on('play', handlePlay).on('stop', handleStop)
emitter.on(['play', 'stop'], handleBoth)

Inherited from ​

TypedEventEmitter.on


once() ​

once<K>(type, listener): this

Defined in: packages/core/src/events/typed-event-emitter.ts:141

Subscribe to an event once. Handler is removed after first invocation.

Type Parameters ​

K ​

K extends "dispose" | "voicestolen"

Parameters ​

type ​

K

The event type to subscribe to

listener ​

(event) => void

The event handler function

Returns ​

this

this for chaining

Example ​

typescript
emitter.once('end', () => console.log('Finished'))

Inherited from ​

TypedEventEmitter.once


play() ​

play(options): VoiceHandle

Defined in: packages/core/src/poly-synth.ts:376

Play a note at the given frequency. Returns a VoiceHandle for per-voice control.

Parameters ​

options ​

PlayOptions

Frequency and optional per-voice gain

Returns ​

VoiceHandle

VoiceHandle for controlling the voice

Example ​

typescript
const handle = synth.play({ frequency: 440 })
handle.update('gain').to(0.5).as('ratio')
await handle.stop()

removeEffect() ​

removeEffect(effect): this

Defined in: packages/core/src/poly-synth.ts:810

Remove an effect from the shared output bus.

Parameters ​

effect ​

Effect

The Effect instance to remove

Returns ​

this

this for chaining


removeEventListener() ​

Call Signature ​

removeEventListener<K>(type, listener, options?): void

Defined in: packages/core/src/events/typed-event-emitter.ts:70

Remove a typed event listener for known event types. Overloaded to provide type safety for known event types while remaining compatible with the native EventTarget API.

Type Parameters ​
K ​

K extends "dispose" | "voicestolen"

Parameters ​
type ​

K

The event type (key of TMap)

listener ​

(event) => void

Typed event handler to remove

options? ​

Standard removeEventListener options

boolean | EventListenerOptions

Returns ​

void

Inherited from ​

TypedEventEmitter.removeEventListener

Call Signature ​

removeEventListener(type, listener, options?): void

Defined in: packages/core/src/events/typed-event-emitter.ts:75

Remove a typed event listener for known event types. Overloaded to provide type safety for known event types while remaining compatible with the native EventTarget API.

Parameters ​
type ​

string

The event type (key of TMap)

listener ​

Typed event handler to remove

EventListenerOrEventListenerObject | null

options? ​

Standard removeEventListener options

boolean | EventListenerOptions

Returns ​

void

Inherited from ​

TypedEventEmitter.removeEventListener


setAnalyzer() ​

setAnalyzer(analyzer): this

Defined in: packages/core/src/poly-synth.ts:832

Attach an analyzer to the shared bus output for visualization.

Parameters ​

analyzer ​

The Analyzer instance, or null to detach

Analyzer | null

Returns ​

this

this for chaining


setDestination() ​

setDestination(node): this

Defined in: packages/core/src/poly-synth.ts:851

Set a custom destination for audio output.

Parameters ​

node ​

AudioNode

The AudioNode to route output to

Returns ​

this

this for chaining


stopAll() ​

stopAll(): void

Defined in: packages/core/src/poly-synth.ts:682

Stop all active voices immediately, including voices already mid-release from an earlier stop() call. All handles become stale.

State is updated synchronously here rather than deferred to the oscillator's own 'stop'/'end' events (as setupVoiceListeners does for a normal single-voice stop) — those events depend on Oscillator's own async play/stop machinery (e.g. an AudioContext.resume() still in flight), which panic can't afford to wait on. Recycling the slot immediately is click-safe: G1's Oscillator.setup() already detects a still-audible outgoing node (via _isPlaying/_releaseTailEndsAt) on the NEXT play() and routes it through a release-gain handoff instead of a hard cut, regardless of whether this method's synchronous bookkeeping or the oscillator's own async event fires first.

Returns ​

void

Example ​

typescript
synth.stopAll() // Panic button

update() ​

update(type): object

Defined in: packages/core/src/poly-synth.ts:748

Update a master bus parameter immediately.

Note: unlike GrainPlayer, PolySynth's master bus intentionally does NOT have onPlaySet()/onPlayRamp() (R1#6 evaluated this and skipped it) — PolySynth has no singular "play()" for the whole instance to hook a consume-once schedule onto; play(options) triggers one voice at a time and each returned VoiceHandle already exposes its own onPlaySet()/onPlayRamp() (delegating to the voice's Oscillator) for per-note envelopes. Use those for per-note fades, or update('gain') / changeGainTo() here for master-bus-wide immediate changes.

Parameters ​

type ​

'gain' or 'pan'

"gain" | "pan"

Returns ​

object

Fluent builder

to() ​

to: (value) => object

Parameters ​
value ​

number

Returns ​

object

as() ​

as: (method) => void

Parameters ​
method ​

RatioType

Returns ​

void

Example ​

typescript
synth.update('gain').to(0.5).as('ratio')