standardized-audio-context

repository·master·Indexed 21 days ago

https://github.com/chrisguttandin/standardized-audio-context

A cross-browser ponyfill for the Web Audio API (version 25.3.77) that provides a consistent, standard-compliant interface for AudioContext and OfflineAudioContext without modifying the global scope. It includes utility functions like isSupported(), decodeAudioData(), and type-checking helpers (isAnyAudioNode, isAnyAudioParam) to ensure consistent behavior across Chrome v105+, Firefox v113+, and Safari v17.3+.

Tokens
4.6K
Snippets
11
Records
13
Agent score
23%

What's inside standardized-audio-context

  1. Check browser support with isSupported()

    master

    The package provides a way to check if the current environment supports the required Web Audio API features. The library uses 'expectation tests' to verify browser behavior; if a browser fix is released, the workaround is removed and the test is recycled into the isSupported() check.

    Currently supported browsers include:

    • Chrome v105+
    • Firefox v113+
    • Safari v17.3+

    Note: Supporting a browser means supporting it at the feature level. You may still need a transpiler like Babel to avoid syntax errors in older versions of supported browsers.

  2. Use standardized-audio-context in TypeScript

    master
    The package is written in TypeScript and provides types that match the concrete implementation of the Web Audio API. Unlike the standard Web Audio API types provided by TypeScript (which are generated from Web IDL and may not match actual browser implementations), the types exported by standardized-audio-context are designed to reflect the actual available implementations.
  3. Create an OscillatorNode using constructors

    master

    Alternatively, you can instantiate nodes directly using their constructors by passing the AudioContext instance as an argument.

    import { AudioContext, OscillatorNode } from 'standardized-audio-context';
    
    const audioContext = new AudioContext();
    const oscillatorNode = new OscillatorNode(audioContext);
    
    oscillatorNode.connect(audioContext.destination);
    
    oscillatorNode.start();
  4. Create a sine wave using AudioContext factory methods

    master

    You can use the standard factory methods (like createOscillator()) on an AudioContext instance to build an audio graph.

    import { AudioContext } from 'standardized-audio-context';
    
    const audioContext = new AudioContext();
    const oscillatorNode = audioContext.createOscillator();
    
    oscillatorNode.connect(audioContext.destination);
    
    oscillatorNode.start();
  5. Decode audio data with standalone decodeAudioData()

    master

    The standalone decodeAudioData() function is a wrapper that can be used similarly to the instance method.

    Differences from the instance method:

    • It requires an (Offline)AudioContext created with standardized-audio-context as the first parameter (though it can also handle native contexts).
    • It only returns a Promise and does not use callbacks.

    Use this when you want a consistent Promise-based API for decoding audio buffers.

    import { decodeAudioData } from 'standardized-audio-context';
    
    const nativeAudioContext = new AudioContext();
    
    const response = await fetch('/a-super-cool-audio-file');
    const arrayBuffer = await response.arrayBuffer();
    
    const audioBuffer = await decodeAudioData(nativeAudioContext, arrayBuffer);
  6. Identify AudioContexts, Nodes, and Params with isAny* utilities

    master

    The library provides several utility functions to identify Web Audio API objects without needing custom instanceof checks. These functions work regardless of whether the object was created by standardized-audio-context or is a native browser object.

    • isAnyAudioContext(context): Returns true if the value is an AudioContext. Returns false for OfflineAudioContext.
    • isAnyOfflineAudioContext(context): Returns true if the value is an OfflineAudioContext.
    • isAnyAudioNode(node): Returns true if the value is an AudioNode.
    • isAnyAudioParam(param): Returns true if the value is an AudioParam.
    import { OfflineAudioContext, isAnyAudioNode } from 'standardized-audio-context';
    
    // This will create a native AudioContext.
    const nativeAudioContext = new AudioContext();
    
    isAnyAudioNode(nativeAudioContext.createGain()); // true
    
    // This will create an OfflineAudioContext from standardized-audio-context.
    const offlineAudioContext = new OfflineAudioContext({ length: 10, sampleRate: 44100 });
    
    isAnyAudioNode(offlineAudioContext.createGain()); // true
  7. Use the OfflineAudioContext interface

    master

    The OfflineAudioContext class is an almost complete implementation of the Web Audio API OfflineAudioContext interface. It is used for rendering audio to a buffer rather than playing it through speakers. It also excludes the deprecated createScriptProcessor() method.

    Key capabilities include:

    • Rendering audio to a buffer via startRendering().
    • Creating audio nodes similar to AudioContext.
    • Managing audio state and properties like sampleRate and length.

    Note on Listener: Firefox and Safari (up to version 14.0.1) do not support modifying the listener via AudioParams. Calling scheduling functions on the AudioParams of an OfflineAudioContext listener in these browsers will throw a NotSupportedError.

    interface IOfflineAudioContext extends EventTarget {
        readonly audioWorklet?: IAudioWorklet;
        readonly currentTime: number;
        readonly destination: IAudioDestinationNode<IOfflineAudioContext>;
        readonly length: number;
        readonly listener: IAudioListener;
        onstatechange: null | TEventHandler<IOfflineAudioContext>;
        readonly sampleRate: number;
        readonly state: TAudioContextState;
        createAnalyser(): IAnalyserNode<IOfflineAudioContext>;
        createBiquadFilter(): IBiquadFilterNode<IOfflineAudioContext>;
        createBuffer(numberOfChannels: number, length: number, sampleRate: number): IAudioBuffer;
        createBufferSource(): IAudioBufferSourceNode<IOfflineAudioContext>;
        createChannelMerger(numberOfInputs?: number): IAudioNode<IOfflineAudioContext>;
        createChannelSplitter(numberOfOutputs?: number): IAudioNode<IOfflineAudioContext>;
        createConstantSource(): IConstantSourceNode<IOfflineAudioContext>;
        createConvolver(): IConvolverNode<IOfflineAudioContext>;
        createDelay(maxDelayTime?: number): IDelayNode<IOfflineAudioContext>;
        createDynamicsCompressor(): IDynamicsCompressorNode<IOfflineAudioContext>;
        createGain(): IGainNode<IOfflineAudioContext>;
        createIIRFilter(feedforward: number[], feedback: number[]): IIIRFilterNode<IOfflineAudioContext>;
        createOscillator(): IOscillatorNode<IOfflineAudioContext>;
        createPanner(): IPannerNode<IOfflineAudioContext>;
        createPeriodicWave(real: number[], imag: number[], constraints?: Partial<IPeriodicWaveConstraints>): IPeriodicWave;
        createStereoPanner(): IStereoPannerNode<IOfflineAudioContext>;
        createWaveShaper(): IWaveShaperNode<IOfflineAudioContext>;
        decodeAudioData(
            audioData: ArrayBuffer,
            successCallback?: TDecodeSuccessCallback,
            errorCallback?: TDecodeErrorCallback
        ): Promise<IAudioBuffer>;
        startRendering(): Promise<IAudioBuffer>;
    }
  8. Use the AudioContext interface

    master

    The AudioContext class is an almost complete implementation of the Web Audio API AudioContext interface. It provides a standardized way to manage audio graphs, including creating various audio nodes and managing the audio state. It excludes the deprecated createScriptProcessor() method.

    Key capabilities include:

    • Managing audio state (resume(), suspend(), close()).
    • Creating a wide range of audio nodes (Oscillators, Gain, Filters, Delays, etc.).
    • Decoding audio data via decodeAudioData().
    • Accessing the audioWorklet property (available only in a SecureContext).
    // The AudioContext implements the following TypeScript interface:
    interface IAudioContext extends EventTarget {
        readonly audioWorklet?: IAudioWorklet;
        readonly baseLatency: number;
        readonly currentTime: number;
        readonly destination: IAudioDestinationNode<IAudioContext>;
        readonly listener: IAudioListener;
        onstatechange: null | TEventHandler<IAudioContext>;
        readonly sampleRate: number;
        readonly state: TAudioContextState;
        close(): Promise<void>;
        createAnalyser(): IAnalyserNode<IAudioContext>;
        createBiquadFilter(): IBiquadFilterNode<IAudioContext>;
        createBuffer(numberOfChannels: number, length: number, sampleRate: number): IAudioBuffer;
        createBufferSource(): IAudioBufferSourceNode<IAudioContext>;
        createChannelMerger(numberOfInputs?: number): IAudioNode<IAudioContext>;
        createChannelSplitter(numberOfOutputs?: number): IAudioNode<IAudioContext>;
        createConstantSource(): IConstantSourceNode<IAudioContext>;
        createConvolver(): IConvolverNode<IAudioContext>;
        createDelay(maxDelayTime?: number): IDelayNode<IAudioContext>;
        createDynamicsCompressor(): IDynamicsCompressorNode<IAudioContext>;
        createGain(): IGainNode<IAudioContext>;
        createIIRFilter(feedforward: number[], feedback: number[]): IIIRFilterNode<IAudioContext>;
        createMediaElementSource(mediaElement: HTMLMediaElement): IMediaElementAudioSourceNode<IAudioContext>;
        createMediaStreamDestination(): IMediaElementAudioDestinationNode<IAudioContext>;
        createMediaStreamSource(mediaStream: MediaStream): IMediaStreamAudioSourceNode<IAudioContext>;
        createMediaStreamTrackSource(mediaStreamTrack: MediaStreamTrack): IMediaStreamTrackAudioSourceNode<IAudioContext>;
        createOscillator(): IOscillatorNode<IAudioContext>;
        createPanner(): IPannerNode<IAudioContext>;
        createPeriodicWave(real: number[], imag: number[], constraints?: Partial<IPeriodicWaveConstraints>): IPeriodicWave;
        createStereoPanner(): IStereoPannerNode<IAudioContext>;
        createWaveShaper(): IWaveShaperNode<IAudioContext>;
        decodeAudioData(
            audioData: ArrayBuffer,
            successCallback?: TDecodeSuccessCallback,
            errorCallback?: TDecodeErrorCallback
        ): Promise<IAudioBuffer>;
        resume(): Promise<void>;
        suspend(): Promise<void>;
    }
  9. Check for audio support with isSupported()

    master

    The isSupported() function returns a Promise that resolves to a boolean. This indicates whether the standardized-audio-context functionality is supported in the current browser environment. This is a non-specification utility provided for compatibility checks.

    import { isSupported } from 'standardized-audio-context';
    
    isSupported().then((isSupported) => {
        if (isSupported) {
            // yeah everything should work
        } else {
            // oh no this browser seems to be outdated
        }
    });
  10. Reference: Audio Node Factory Methods

    master

    The AudioContext and OfflineAudioContext provide factory methods to create various audio nodes. Most of these can also be instantiated using their respective constructors as an alternative.

    // Factory methods available on AudioContext/OfflineAudioContext:
    createAnalyser()
    createBiquadFilter()
    createBuffer(numberOfChannels, length, sampleRate)
    createBufferSource()
    createChannelMerger(numberOfInputs?)
    createChannelSplitter(numberOfOutputs?)
    createConstantSource()
    createConvolver()
    createDelay(maxDelayTime?)
    createDynamicsCompressor()
    createGain()
    createIIRFilter(feedforward, feedback)
    createMediaElementSource(mediaElement) // AudioContext only
    createMediaStreamDestination() // AudioContext only
    createMediaStreamSource(mediaStream) // AudioContext only
    createMediaStreamTrackSource(mediaStreamTrack) // AudioContext only
    createOscillator()
    createPanner()
    createPeriodicWave(real, imag, constraints?)
    createStereoPanner()
    createWaveShaper()