ez-web-audio
Version:
Making the Web Audio API super EZ since 2024.
361 lines • 13.5 kB
TypeScript
import { OscillatorOptsFilterValues, Oscillator, OscillatorOpts } from './oscillator';
import { Envelope, EnvelopeOptions } from './envelope';
import { stopAll, pauseAll, playAll } from './utils/collections';
import { SampledNote } from './sampled-note';
import { Connectable } from './interfaces/connectable';
import { Playable } from './interfaces/playable';
import { Font } from './font';
import { AudioContextError, AudioError, AudioLoadError, InvalidNoteError } from './errors';
import { default as frequencyMap } from './utils/frequency-map';
import { BeatTrackOptions, BeatTrack } from './beat-track';
import { Beat } from './beat';
import { MusicallyAware } from './musical-identity';
import { SamplerOptions, Sampler } from './sampler';
import { Sound } from './sound';
import { Track } from './track';
import { Note } from './note';
import { clearPreloadCache, isPreloaded, preload } from './preload';
import { AudioSprite, SpriteDefinition, SpriteManifest, SpritePlayOptions } from './sprite';
import { crossfade } from './utils/crossfade';
import { setDebugMode, setDebugHandler, DebugMessage } from './debug';
import { Analyzer, createAnalyzer, AnalyzerOptions } from './analyzer';
import { createGainEffect, createFilterEffect, wrapEffect, GainEffect, FilterEffect, EffectWrapper, Effect, FilterType, FilterEffectOptions, ExternalEffect } from './effects';
/**
* Initialize the audio system. Must be called in response to a user interaction
* (click, tap, keypress) due to browser autoplay policies.
*
* This function creates the AudioContext if it doesn't exist and handles
* iOS-specific workarounds for audio playback while the mute switch is on.
*
* @param useIosMuteWorkaround - Whether to apply iOS mute switch workaround (default: true)
* @throws {AudioContextError} If AudioContext cannot be created or is interrupted
*
* @example
* ```typescript
* import { initAudio, createSound } from 'ez-web-audio'
*
* // Call initAudio on user interaction
* button.addEventListener('click', async () => {
* await initAudio()
* const sound = await createSound('click.mp3')
* sound.play()
* })
* ```
*/
export declare function initAudio(useIosMuteWorkaround?: boolean): Promise<void>;
/**
* Get the shared AudioContext instance, initializing it if needed.
*
* The library uses a single AudioContext instance for all audio operations.
* This function ensures the context is initialized before returning it.
*
* @returns The shared AudioContext instance
*
* @example
* ```typescript
* import { getAudioContext } from 'ez-web-audio'
*
* // Get the AudioContext for custom Web Audio operations
* const ctx = await getAudioContext()
* const oscillator = ctx.createOscillator()
* ```
*/
export declare function getAudioContext(): Promise<AudioContext>;
/**
* Create an array of Note objects from a frequency map.
*
* Notes represent musical pitches with letter, accidental, octave, and frequency.
* If no frequency map is provided, uses the default 12-TET frequency map.
*
* @param json - Optional frequency map object (default: built-in frequencyMap)
* @returns Array of Note objects
*
* @example
* ```typescript
* import { createNotes } from 'ez-web-audio'
*
* // Create notes from default frequency map
* const notes = createNotes()
* const a4 = notes.find(n => n.frequency === 440)
* ```
*/
export declare function createNotes(json?: any): Note[];
/**
* Create a Sound from an audio file URL.
*
* Sound is for one-shot audio playback (sound effects, UI sounds). Each call to
* `.play()` creates a new audio source, allowing overlapping playback.
* Use {@link createTrack} instead for music with pause/resume/seek.
*
* @param url - URL to the audio file (local path, relative URL, or absolute URL)
* @returns Promise resolving to a Sound instance
* @throws {AudioLoadError} If the audio file cannot be loaded or decoded
*
* @example
* ```typescript
* import { createSound } from 'ez-web-audio'
*
* const click = await createSound('click.mp3')
* click.play()
*
* // Sounds can overlap
* click.play()
* click.play()
*
* // Control volume
* click.changeGainTo(0.5)
* click.play()
* ```
*/
export declare function createSound(url: string): Promise<Sound>;
/**
* Create a Track from an audio file URL.
*
* Track extends Sound with position tracking, pause/resume, and seeking.
* Use Track for music or longer audio where users need playback control.
* Unlike Sound, only one playback can be active at a time.
*
* @param url - URL to the audio file (local path, relative URL, or absolute URL)
* @returns Promise resolving to a Track instance
* @throws {AudioLoadError} If the audio file cannot be loaded or decoded
*
* @example
* ```typescript
* import { createTrack } from 'ez-web-audio'
*
* const song = await createTrack('song.mp3')
* song.play()
*
* // Pause and resume
* song.pause()
* song.resume()
*
* // Seek to 30 seconds
* song.seek(30).from('seconds')
*
* // Get current position
* console.log(song.position.string) // '0:30'
* ```
*/
export declare function createTrack(url: string): Promise<Track>;
/**
* Create a BeatTrack for drum machine-style rhythmic patterns.
*
* A BeatTrack manages a sequence of Beats, where each Beat can be active (plays sound)
* or inactive (rest). Sounds are played in round-robin fashion to prevent overlapping.
*
* @param urls - Array of audio file URLs to load as sound sources
* @param opts - Optional BeatTrack configuration
* @returns Promise resolving to a BeatTrack instance
* @throws {AudioLoadError} If any audio file cannot be loaded or decoded
*
* @example
* ```typescript
* import { createBeatTrack } from 'ez-web-audio'
*
* // Create a kick drum track with 3 sounds for round-robin
* const kick = await createBeatTrack(['kick1.mp3', 'kick2.mp3', 'kick3.mp3'])
*
* // Set up a 4/4 beat pattern (kick on 1 and 3)
* kick.beats[0].active = true // Beat 1
* kick.beats[2].active = true // Beat 3
*
* // Play the pattern
* kick.play()
* ```
*/
export declare function createBeatTrack(urls: string[], opts?: BeatTrackOptions): Promise<BeatTrack>;
/**
* Create a Sampler for round-robin playback of multiple sounds.
*
* Sampler holds multiple Sound instances and cycles through them on each play,
* providing natural variation and preventing the "machine gun" effect of
* identical sounds played rapidly.
*
* @param urls - Array of audio file URLs to load as sound sources
* @param opts - Optional Sampler configuration
* @returns Promise resolving to a Sampler instance
* @throws {AudioLoadError} If any audio file cannot be loaded or decoded
*
* @example
* ```typescript
* import { createSampler } from 'ez-web-audio'
*
* // Create a sampler with multiple gunshot variations
* const gunshot = await createSampler([
* 'shot1.mp3', 'shot2.mp3', 'shot3.mp3'
* ])
*
* // Each play uses the next sound in rotation
* gunshot.play() // shot1
* gunshot.play() // shot2
* gunshot.play() // shot3
* gunshot.play() // shot1 (wraps around)
* ```
*/
export declare function createSampler(urls: string[], opts?: SamplerOptions): Promise<Sampler>;
/**
* Create an Oscillator for synthesizing audio from waveforms.
*
* Oscillators generate sound from sine, square, sawtooth, or triangle waves.
* They support filters for tone shaping and ADSR envelopes for
* professional-quality synthesis.
*
* @param options - Optional oscillator configuration (frequency, type, filters, envelope)
* @returns Promise resolving to an Oscillator instance
*
* @example
* ```typescript
* import { createOscillator } from 'ez-web-audio'
*
* // Simple sine wave at 440Hz (A4)
* const synth = await createOscillator({ frequency: 440, type: 'sine' })
* synth.play()
* setTimeout(() => synth.stop(), 500)
*
* // With ADSR envelope for piano-like decay
* const piano = await createOscillator({
* frequency: 440,
* type: 'triangle',
* envelope: { attack: 0.01, decay: 0.3, sustain: 0.4, release: 0.5 }
* })
* piano.play()
* ```
*/
export declare function createOscillator(options?: OscillatorOpts): Promise<Oscillator>;
/**
* Create a LayeredSound that plays multiple Sound/Oscillator instances simultaneously.
* All layers start at exactly the same audioContext.currentTime for perfect sync.
*
* @param layers - Array of Sound or Oscillator instances to layer
* @param opts - Optional configuration (name, warnLayerCount)
* @returns LayeredSound instance
*
* @example
* const bass = await createSound('bass.mp3')
* const melody = await createSound('melody.mp3')
* const synth = await createOscillator({ frequency: 440 })
*
* const layered = await createLayeredSound([bass, melody, synth])
* layered.play() // All layers start at exact same time
* layered.setGain(0.5) // Affects all layers
* layered.getLayer(2)?.changeGainTo(0.8) // Control individual layer
*/
export declare function createLayeredSound(layers: (Sound | Oscillator)[], opts?: import('./layered-sound').LayeredSoundOptions): Promise<import('./layered-sound').LayeredSound>;
/**
* Create a Font from a soundfont file.
*
* A Font is a collection of sampled notes (like a piano or organ) that can be
* played by note name. Soundfont files contain base64-encoded audio samples
* for each note.
*
* @param url - URL to the soundfont JavaScript file
* @returns Promise resolving to a Font instance
* @throws {AudioLoadError} If the soundfont cannot be loaded or decoded
*
* @example
* ```typescript
* import { createFont } from 'ez-web-audio'
*
* // Load a piano soundfont
* const piano = await createFont('acoustic_grand_piano-mp3.js')
*
* // Play notes by name
* piano.play('C4') // Middle C
* piano.play('E4') // E above middle C
* piano.play('G4') // G above middle C
* ```
*/
export declare function createFont(url: string): Promise<Font>;
/**
* Create an audio sprite from an audio file and manifest.
* Sprites allow playing segments of a single audio file by name.
*
* @param audioUrl - URL of the audio file
* @param manifest - Sprite manifest with timing definitions
* @returns AudioSprite instance
*
* @example
* const sprite = await createSprite('sounds.mp3', {
* spritemap: {
* laser: { start: 0, end: 0.3 },
* explosion: { start: 1.0, end: 2.5 }
* }
* })
* sprite.play('laser', { gain: 0.5 })
*/
export declare function createSprite(audioUrl: string, manifest: SpriteManifest): Promise<AudioSprite>;
/**
* Create a Sound containing white noise.
*
* White noise is useful for sound effects (rain, static, wind) and as a
* synthesis building block when combined with filters.
*
* @returns Promise resolving to a Sound containing 1 second of white noise
*
* @example
* ```typescript
* import { createWhiteNoise, createFilterEffect } from 'ez-web-audio'
*
* // Create white noise
* const noise = await createWhiteNoise()
* noise.play()
*
* // Filter white noise to create wind-like sound
* const wind = await createWhiteNoise()
* const lowpass = createFilterEffect(await getAudioContext(), 'lowpass', {
* frequency: 400
* })
* wind.addEffect(lowpass)
* wind.play()
* ```
*/
export declare function createWhiteNoise(): Promise<Sound>;
interface Player {
play: () => void;
stop: () => void;
}
/**
* Prevent default behavior for common interaction events on an element.
*
* Useful for piano keys or other interactive audio controls where you want
* to prevent text selection, context menus, and drag-and-drop behaviors.
*
* @param key - HTML element to attach event prevention to
*
* @example
* ```typescript
* import { preventEventDefaults } from 'ez-web-audio'
*
* const pianoKey = document.getElementById('key-c4')
* preventEventDefaults(pianoKey)
* ```
*/
export declare function preventEventDefaults(key: HTMLElement): void;
/**
* Attach play/stop handlers to an element for touch and mouse interactions.
*
* Binds touchstart/mousedown to play() and touchend/mouseup/mouseleave to stop().
* Automatically initializes audio on first interaction.
*
* @param key - HTML element to attach handlers to
* @param player - Object with play() and stop() methods
*
* @example
* ```typescript
* import { useInteractionMethods, createOscillator } from 'ez-web-audio'
*
* const synth = await createOscillator({ frequency: 440 })
* const pianoKey = document.getElementById('key-a4')
*
* await useInteractionMethods(pianoKey, synth)
* // Now touching/clicking the element plays the synth
* ```
*/
export declare function useInteractionMethods(key: HTMLElement, player: Player): Promise<void>;
export { Font, Note, Sound, Sampler, SampledNote, Oscillator, Track, MusicallyAware, frequencyMap, Beat, BeatTrack, Envelope, AudioSprite, preload, isPreloaded, clearPreloadCache, stopAll, pauseAll, playAll, crossfade, setDebugMode, setDebugHandler, createGainEffect, createFilterEffect, wrapEffect, GainEffect, FilterEffect, EffectWrapper, Analyzer, createAnalyzer, AudioError, AudioContextError, AudioLoadError, InvalidNoteError, };
export { LayeredSound } from './layered-sound';
export type { LayeredSoundOptions } from './layered-sound';
export type { LayeredSoundEventMap, WarningEventDetail } from './events/event-types';
export type { Connectable, Playable, OscillatorOpts, OscillatorOptsFilterValues, EnvelopeOptions, SpriteDefinition, SpriteManifest, SpritePlayOptions, DebugMessage, Effect, FilterType, FilterEffectOptions, ExternalEffect, AnalyzerOptions, };
//# sourceMappingURL=index.d.ts.map