EZ Web Audio / GrainPlayer
Class: GrainPlayer
Defined in: packages/core/src/grain-player.ts:74
Granular synthesis player that generates continuous texture/pad sounds from an audio buffer.
GrainPlayer works by scheduling many overlapping short "grains" of audio from a source buffer. Each grain gets a triangular window envelope (linear ramp up -> linear ramp down) to prevent clicks. Grains are scheduled slightly ahead of real time using a WorkerTimer for glitch-free playback even in background tabs.
Provides independent control over:
- Position (0-1): Which region of the buffer to sample grains from
- Pitch (semitones): Pitch shift via playbackRate on each grain's BufferSourceNode
- Grain parameters: grainSize, overlap, jitter — adjustable in real-time
Note: Pitch shifting is implemented via playbackRate, which changes both pitch AND speed of each grain. The overlap system compensates for the changed grain duration, but extreme values (beyond +/-24 semitones) may affect texture quality.
Example
import { createGrainPlayer, createSound } from 'ez-web-audio'
const sound = await createSound('pad.mp3')
const grains = await createGrainPlayer(sound.audioBuffer, {
grainSize: 0.1,
overlap: 0.05,
jitter: 0.1
})
grains.play()
grains.position = 0.5 // scrub to middle of buffer
grains.pitch = 7 // pitch up a fifthExtends
Constructors
Constructor
new GrainPlayer(
audioContext,buffer,options?):GrainPlayer
Defined in: packages/core/src/grain-player.ts:110
Parameters
audioContext
AudioContext
buffer
AudioBuffer
options?
Returns
GrainPlayer
Overrides
Properties
audioContext
readonlyaudioContext:AudioContext
Defined in: packages/core/src/grain-player.ts:111
Accessors
activeGrainCount
Get Signature
get activeGrainCount():
number
Defined in: packages/core/src/grain-player.ts:404
Number of currently active (playing) grains.
Returns
number
disposed
Get Signature
get disposed():
boolean
Defined in: packages/core/src/grain-player.ts:401
Whether this GrainPlayer has been disposed.
Returns
boolean
grainSize
Get Signature
get grainSize():
number
Defined in: packages/core/src/grain-player.ts:453
Duration of each grain in seconds. Minimum 0.01s. Changes take effect on the next grain. Note: Shrinking grainSize will re-clamp overlap to maintain valid hop size.
Returns
number
Set Signature
set grainSize(
value):void
Defined in: packages/core/src/grain-player.ts:454
Parameters
value
number
Returns
void
jitter
Get Signature
get jitter():
number
Defined in: packages/core/src/grain-player.ts:474
Random scatter around the position for organic texture, 0-1. 0 = no scatter, 1 = scatter across entire buffer.
Returns
number
Set Signature
set jitter(
value):void
Defined in: packages/core/src/grain-player.ts:475
Parameters
value
number
Returns
void
loop
Get Signature
get loop():
boolean
Defined in: packages/core/src/grain-player.ts:480
Whether to loop when reaching the buffer end.
Returns
boolean
Set Signature
set loop(
value):void
Defined in: packages/core/src/grain-player.ts:481
Parameters
value
boolean
Returns
void
overlap
Get Signature
get overlap():
number
Defined in: packages/core/src/grain-player.ts:465
Overlap between consecutive grains in seconds. Clamped to [0, grainSize - 0.001] to ensure hop size never drops below 0.001s. Changes take effect on the next grain.
Returns
number
Set Signature
set overlap(
value):void
Defined in: packages/core/src/grain-player.ts:466
Parameters
value
number
Returns
void
paused
Get Signature
get paused():
boolean
Defined in: packages/core/src/grain-player.ts:398
Whether the grain player is paused.
Returns
boolean
pitch
Get Signature
get pitch():
number
Defined in: packages/core/src/grain-player.ts:431
Pitch shift in semitones. 0 = original pitch. Internally converts to playbackRate via 2^(semitones/12).
Note: This is playbackRate-based pitch shift. It changes grain duration, which the overlap system compensates for, but extreme values will affect texture quality.
Example
grainPlayer.pitch = 7 // up a fifth
grainPlayer.pitch = 12 // up an octave
grainPlayer.pitch = -12 // down an octaveReturns
number
Set Signature
set pitch(
semitones):void
Defined in: packages/core/src/grain-player.ts:432
Parameters
semitones
number
Returns
void
playbackRate
Get Signature
get playbackRate():
number
Defined in: packages/core/src/grain-player.ts:441
Direct playback rate ratio. 1 = original speed, 2 = double speed (octave up). Setting this also updates the pitch property accordingly.
Returns
number
Set Signature
set playbackRate(
value):void
Defined in: packages/core/src/grain-player.ts:442
Parameters
value
number
Returns
void
playing
Get Signature
get playing():
boolean
Defined in: packages/core/src/grain-player.ts:395
Whether the grain player is currently playing.
Returns
boolean
position
Get Signature
get position():
number
Defined in: packages/core/src/grain-player.ts:411
Playback position in the buffer, normalized 0-1. 0 = beginning of buffer, 1 = end of buffer. Changes take effect on the next grain.
Returns
number
Set Signature
set position(
value):void
Defined in: packages/core/src/grain-player.ts:412
Parameters
value
number
Returns
void
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/grain-player.ts:669
Add an effect to the shared output bus. All grains are affected.
Parameters
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 "pause" | "play" | "dispose" | "stop" | "resume"
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/grain-player.ts:644
Set the master gain for all grains.
Parameters
value
number
Gain from 0 (silent) to 1 (full volume)
Returns
this
changePanTo()
changePanTo(
value):this
Defined in: packages/core/src/grain-player.ts:654
Set the master pan for all grains.
Parameters
value
number
Pan from -1 (left) to 1 (right)
Returns
this
dispose()
dispose():
void
Defined in: packages/core/src/grain-player.ts:741
Dispose this GrainPlayer, releasing all audio resources.
Stops playback, disconnects the shared bus, and marks the instance as unusable. Dispose is idempotent.
Returns
void
emit()
protectedemit<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 "pause" | "play" | "dispose" | "stop" | "resume"
Parameters
type
K
The event type to emit (key of TMap)
detail
GrainPlayerEventMap[K]["detail"]
The event detail object (typed by TMap)
Returns
void
Inherited from
getAnalyzer()
getAnalyzer():
Analyzer|null
Defined in: packages/core/src/grain-player.ts:717
Get the currently attached analyzer.
Returns
Analyzer | null
getEffects()
getEffects(): readonly
Effect[]
Defined in: packages/core/src/grain-player.ts:698
Get a readonly copy of the current effects array.
Returns
readonly Effect[]
getGainNode()
getGainNode():
GainNode
Defined in: packages/core/src/grain-player.ts:488
Returns the master GainNode (for LFO targeting and external routing).
Returns
GainNode
getPannerNode()
getPannerNode():
StereoPannerNode
Defined in: packages/core/src/grain-player.ts:491
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 "pause" | "play" | "dispose" | "stop" | "resume"
Parameters
type
K
The event type to unsubscribe from
listener
(event) => void
The event handler function to remove
Returns
this
this for chaining
Example
const handler = (e) => console.log(e.detail)
emitter.on('play', handler)
// later...
emitter.off('play', handler)Inherited from
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 "pause" | "play" | "dispose" | "stop" | "resume"
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
emitter.on('play', handlePlay).on('stop', handleStop)
emitter.on(['play', 'stop'], handleBoth)Inherited from
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 "pause" | "play" | "dispose" | "stop" | "resume"
Parameters
type
K
The event type to subscribe to
listener
(event) => void
The event handler function
Returns
this
this for chaining
Example
emitter.once('end', () => console.log('Finished'))Inherited from
onPlayRamp()
onPlayRamp(
type,rampType?):object
Defined in: packages/core/src/grain-player.ts:581
Schedule a master gain/pan ramp when play() is called.
Same fluent shape as BaseSound.onPlayRamp() (R1#6). Consume-once: the ramp is applied and cleared by the next play() call.
Parameters
type
'gain' or 'pan'
"gain" | "pan"
rampType?
RampType
'linear' or 'exponential' (default: 'exponential')
Returns
object
Fluent builder for setting start value, end value, and duration
from()
from: (
startValue) =>object
Parameters
startValue
number
Returns
object
to()
to: (
endValue) =>object
Parameters
endValue
number
Returns
object
in()
in: (
endTime) =>void
Parameters
endTime
number
Returns
void
Example
grainPlayer.onPlayRamp('gain', 'linear').from(0).to(0.8).in(2)
grainPlayer.play()onPlaySet()
onPlaySet(
type):object
Defined in: packages/core/src/grain-player.ts:540
Schedule a master gain/pan value to be set when play() is called.
Same fluent shape as BaseSound.onPlaySet() (R1#6) — use .at(time) for an immediate setValueAtTime, or .endingAt(time, rampType) to ramp to the value. Consume-once: the schedule is applied and cleared by the next play() call.
Parameters
type
'gain' or 'pan'
"gain" | "pan"
Returns
object
Fluent builder for setting value and timing
to()
to: (
value) =>object
Parameters
value
number
Returns
object
at()
at: (
time) =>void
Parameters
time
number
Returns
void
endingAt()
endingAt: (
time,rampType?) =>void
Parameters
time
number
rampType?
RampType
Returns
void
Example
// Fade the texture in over 2 seconds
grainPlayer.onPlaySet('gain').to(0).at(0)
grainPlayer.onPlaySet('gain').to(0.8).endingAt(2, 'linear')
grainPlayer.play()pause()
pause():
void
Defined in: packages/core/src/grain-player.ts:355
Pause grain playback. Active grains will finish naturally. Resume with resume.
Returns
void
Example
grainPlayer.pause()
// later...
grainPlayer.resume()play()
play():
void
Defined in: packages/core/src/grain-player.ts:288
Start grain playback. If already playing, this is a no-op.
Returns
void
Example
grainPlayer.play()removeEffect()
removeEffect(
effect):this
Defined in: packages/core/src/grain-player.ts:686
Remove an effect from the shared output bus.
Parameters
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 "pause" | "play" | "dispose" | "stop" | "resume"
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
resume()
resume():
void
Defined in: packages/core/src/grain-player.ts:377
Resume grain playback from where it was paused.
Returns
void
Example
grainPlayer.resume()setAnalyzer()
setAnalyzer(
analyzer):this
Defined in: packages/core/src/grain-player.ts:708
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/grain-player.ts:727
Set a custom destination for audio output.
Parameters
node
AudioNode
The AudioNode to route output to
Returns
this
this for chaining
stop()
stop():
void
Defined in: packages/core/src/grain-player.ts:329
Stop grain playback. Active grains will decay naturally (they're very short).
Returns
void
Example
grainPlayer.stop()update()
update(
type):object
Defined in: packages/core/src/grain-player.ts:506
Update a master bus parameter immediately.
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
Returns
void
Example
grainPlayer.update('gain').to(0.5).as('ratio')