Skip to content

Getting Started

Get up and running with EZ Web Audio in under 5 minutes.

Installation

bash
pnpm add ez-web-audio
bash
npm install ez-web-audio
bash
yarn add ez-web-audio

Your First Sound

Play a sound file with just a few lines of code:

typescript
import { createSound } from 'ez-web-audio'

document.querySelector('button')?.addEventListener('click', async () => {
  const sound = await createSound('/sounds/click.mp3')
  sound.play()
})

AudioContext & User Interaction

Browsers require a user interaction (click, tap, keypress) before playing audio. This is a security feature to prevent auto-playing sounds. EZ Web Audio handles this automatically — the AudioContext is created lazily when you first call a factory function like createSound() or createOscillator().

TIP

You don't need to call initAudio(). The library creates and manages the AudioContext automatically. Just make sure your first audio call happens inside a user interaction handler (click, tap, keypress).

Advanced: Explicit initialization

If you need explicit control over initialization timing (e.g., iOS mute switch workaround, pre-warming the context), you can still call initAudio():

typescript
import { createSound, initAudio } from 'ez-web-audio'

button.addEventListener('click', async () => {
  await initAudio() // Optional — for explicit control
  const sound = await createSound('/sounds/click.mp3')
  sound.play()
})

Playing Music Tracks

For longer audio files with pause/resume:

typescript
import { createTrack } from 'ez-web-audio'

button.addEventListener('click', async () => {
  const track = await createTrack('/music/song.mp3')
  track.play()

  // Control playback
  pauseBtn.onclick = () => track.pause()
  resumeBtn.onclick = () => track.resume()
  seekBtn.onclick = () => track.seek(30).as('seconds') // Jump to 30 seconds
})

Sound vs Track

FeatureSoundTrack
Use caseShort sounds (clicks, effects)Music, long audio
OverlapMultiple plays overlapOne play at a time
Pause/ResumeNoYes
SeekNoYes
Position trackingNoYes

Generating Sounds

Create sounds from scratch with oscillators:

typescript
import { createOscillator } from 'ez-web-audio'

button.addEventListener('click', async () => {
  const synth = await createOscillator({
    frequency: 440, // A4 note
    type: 'sine' // sine, square, sawtooth, or triangle
  })

  synth.play()

  // Stop after 1 second
  setTimeout(() => synth.stop(), 1000)
})

With ADSR Envelope

For more natural-sounding synthesis, add an envelope:

typescript
const piano = await createOscillator({
  frequency: 440,
  type: 'triangle',
  envelope: {
    attack: 0.01, // Quick attack
    decay: 0.3, // Decay over 0.3 seconds
    sustain: 0.4, // Sustain at 40% volume
    release: 0.5 // Fade out over 0.5 seconds
  }
})

piano.play()
// Call stop() to trigger the release phase
piano.stop()

Controlling Volume and Pan

All sounds support gain (volume) and pan (stereo position):

typescript
const sound = await createSound('/sounds/effect.mp3')

// Set volume to 50%
sound.changeGainTo(0.5)

// Pan to the left
sound.changePanTo(-1) // -1 = left, 0 = center, 1 = right

sound.play()

Scheduled Parameter Changes

You can also schedule parameter changes relative to play time:

typescript
const sound = await createSound('/sounds/whoosh.mp3')

// Fade in over 1 second
sound.onPlaySet('gain').to(0).endingAt(1, 'exponential')

sound.play() // Starts silent, fades in

Adding Effects

Apply effects like filters to shape your sound:

typescript
import { createFilterEffect, createSound } from 'ez-web-audio'

const sound = await createSound('/sounds/vocal.mp3')

// Create a lowpass filter (no AudioContext needed)
const filter = createFilterEffect('lowpass', {
  frequency: 800, // Cut frequencies above 800Hz
  q: 1.0 // Resonance
})

sound.addEffect(filter)
sound.play() // Sound plays through the filter

Preloading Audio

For responsive applications, preload audio files before they're needed:

typescript
import { createSound, isPreloaded, preload } from 'ez-web-audio'

// Preload during app initialization
await preload(['/sounds/click.mp3', '/sounds/whoosh.mp3'])

// Later, sounds load instantly from cache
if (isPreloaded('/sounds/click.mp3')) {
  const sound = await createSound('/sounds/click.mp3') // Uses cached data
  sound.play()
}

Batch Loading

Load multiple sounds at once with progress tracking:

typescript
import { createSounds } from 'ez-web-audio'

const sounds = await createSounds(
  ['/sounds/click.mp3', '/sounds/whoosh.mp3', '/sounds/ding.mp3'],
  (loaded, total) => console.log(`Loaded ${loaded}/${total}`)
)

Complete Example

Here's a complete example combining multiple features:

typescript
import { createOscillator, createSound, createTrack } from 'ez-web-audio'

// Wait for user interaction
document.getElementById('start')?.addEventListener('click', async () => {
  // Sound effect for UI feedback
  const click = await createSound('/sounds/click.mp3')
  click.changeGainTo(0.5)

  // Background music
  const music = await createTrack('/music/background.mp3')
  music.changeGainTo(0.3)
  music.play()

  // Synthesized notification sound
  const notification = await createOscillator({
    frequency: 880,
    type: 'sine',
    envelope: { attack: 0.01, decay: 0.1, sustain: 0, release: 0.1 }
  })

  // Wire up UI
  document.querySelectorAll('button').forEach((btn) => {
    btn.addEventListener('click', () => click.play())
  })

  document.getElementById('notify')?.addEventListener('click', () => {
    notification.play()
    notification.stop()
  })

  document.getElementById('pause')?.addEventListener('click', () => music.pause())
  document.getElementById('resume')?.addEventListener('click', () => music.resume())
})

Next Steps