Synchronized Multi-Sound Playback
EZ Web Audio provides two ways to play multiple sounds at exactly the same moment using the Web Audio API's precise timing:
playTogether()— A one-liner for fire-and-forget synchronized playbackLayeredSound— A class with master gain/pan and per-layer control
playTogether()
The simplest way to play multiple sounds at the same time:
import { createSound, playTogether } from 'ez-web-audio'
const kick = await createSound('kick.mp3')
const snare = await createSound('snare.mp3')
const hihat = await createSound('hihat.mp3')
// All three start at the exact same AudioContext time
await playTogether([kick, snare, hihat])playTogether() gets the current audioContext.currentTime, adds a tiny scheduling offset, and calls playAt() on every sound with the same timestamp. Works with any mix of Sounds, Tracks, and Oscillators.
Interactive Demo
Composition is trivial — fire multiple sounds at once.
Ready
LayeredSound
When you need ongoing control over a group of synchronized sounds — master volume, panning, per-layer mixing — use LayeredSound:
import { createLayeredSound, createSound } from 'ez-web-audio'
const bass = await createSound('bass.mp3')
const melody = await createSound('melody.mp3')
const synth = await createSound('synth.mp3')
const layered = await createLayeredSound([bass, melody, synth])
// All three sounds start at exactly the same time
await layered.play()Interactive Demo
Stacked sounds, one play call.
Ready
Master Controls
Control all layers together using master gain and pan:
// Set master volume for all layers (0–1 range)
layered.changeGainTo(0.75)
// Set stereo panning for all layers (-1 left, 0 center, 1 right)
layered.changePanTo(-0.2)
await layered.play()Individual Layer Access
Get a specific layer by index for individual control:
const layered = await createLayeredSound([bass, melody, synth])
// Access individual layers (0-based index)
const bassLayer = layered.getLayer(0)
const melodyLayer = layered.getLayer(1)
// Set individual layer gain
bassLayer?.changeGainTo(0.9)
melodyLayer?.changeGainTo(0.6)
// Count active layers
console.log(layered.layerCount) // 3Timed Playback
Play all layers for a fixed duration, then auto-stop:
// Play all layers for 2 seconds, then stop automatically
await layered.playFor(2)Event Handling
Listen for playback lifecycle events:
layered.on('play', (event) => {
console.log(`Started at audioContext time: ${event.detail.time}`)
})
layered.on('stop', () => {
console.log('All layers stopped')
})
layered.on('end', () => {
// Fires when the last layer finishes (layers may end at different times)
console.log('All layers finished naturally')
})
layered.on('warning', (event) => {
console.warn(`LayeredSound warning: ${event.detail.message}`)
})Stopping All Layers
Stop all layers at once:
await layered.stop()Layer Count Warning
LayeredSound will log a console warning if you create an instance with 8 or more layers. This is configurable via warnLayerCount option. High layer counts may impact performance on some devices.
// Customize the warning threshold
const layered = await createLayeredSound(sounds, { warnLayerCount: 16 })Which Should I Use?
playTogether() is a single function call — no class, no instance, no cleanup. It fires the sounds and you're done:
// That's it. One line.
await playTogether([kick, snare, hihat])LayeredSound is a persistent object that holds references to your sounds and gives you ongoing control — master volume, panning, per-layer mixing, events. It's more powerful but more to manage:
const layered = await createLayeredSound([bass, melody, synth])
layered.setGain(0.75)
layered.setPan(-0.2)
await layered.play()
// ... later
await layered.stop()playTogether() | LayeredSound | |
|---|---|---|
| Complexity | One function call | Class instance with lifecycle |
| Synchronized start | Yes | Yes |
| Master gain/pan | No | Yes |
| Per-layer control | Manual | Built-in |
| Best for | One-shot triggers (chords, percussion hits) | Ongoing mixing and control |
Next Steps
- Basic Playback — Playing individual sounds
- AudioSprite — Pack multiple sounds into one file
- Crossfade — Smooth transitions between tracks