UNPKG

ez-web-audio

Version:

Making the Web Audio API super EZ since 2024.

361 lines 13.5 kB
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