WASM Audio Decoders

repository·main·Indexed 20 days ago

https://github.com/eshaz/wasm-audio-decoders

A collection of WebAssembly-based audio decoder libraries for high-performance audio processing in the browser and NodeJS. It includes specialized decoders for MPEG (mpg123-decoder), FLAC (@wasm-audio-decoders/flac), Opus (ogg-opus-decoder, opus-decoder, @wasm-audio-decoders/opus-ml), and Vorbis (@wasm-audio-decoders/ogg-vorbis). The libraries support synchronous decoding on the main thread and asynchronous decoding via built-in Web Worker implementations, providing near-native execution speeds.

Tokens
22.9K
Snippets
74
Records
94
Agent score
69%

What's inside wasm-audio-decoders

  1. Overview of WASM Audio Decoders

    main
    WASM Audio Decoders is a collection of WebAssembly-based audio decoder libraries optimized for browser use. They provide near-native execution speeds and support both synchronous decoding on the main thread and asynchronous (threaded) decoding via built-in Web Worker implementations. All decoders are designed to be easy to bundle, using inlined, yEnc-encoded, and gzip-compressed WASM to minimize complexity with bundlers like Webpack.
  2. Understand multichannel output and speaker mapping

    main

    The decoder supports up to 8 channels. Channels are assigned to speaker locations following a conventional surround arrangement (consistent with the Vorbis codec):

    • 1 channel: monophonic (mono)
    • 2 channels: stereo (left, right)
    • 3 channels: linear surround (left, center, right)
    • 4 channels: quadraphonic (front left, front right, rear left, rear right)
    • 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right)
    • 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE)
    • 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE)
    • 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE)
  3. Understand multichannel output mapping

    main

    The decoder supports up to 255 channels. For standard channel counts, speaker locations follow a conventional surround arrangement (similar to Vorbis):

    • 1 channel: monophonic (mono)
    • 2 channels: stereo (left, right)
    • 3 channels: linear surround (left, center, right)
    • 4 channels: quadraphonic (front left, front right, rear left, rear right)
    • 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right)
    • 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE)
    • 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE)
    • 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE)
    • 9-255 channels: No mapping is defined.
  4. How to properly use OggOpusDecoderWebWorker to avoid blocking

    main

    To maximize concurrency and avoid blocking the main thread, do not await every decode() call sequentially. Instead, use .then() to handle results as they arrive, allowing multiple decode operations to be queued in the worker simultaneously.

    Recommended Pattern (Non-blocking):

    const playAudio = ({ channelData, samplesDecoded, sampleRate }) => {
      // Play the audio data
    };
    
    // Operations are queued and run in the worker without halting the main thread
    decoder.decode(data1).then(playAudio);
    decoder.decode(data2).then(playAudio);
    decoder.decode(data3).then(playAudio);

    Avoid this Pattern (Blocking):

    // This halts the main thread for every decode, negating worker benefits
    const decoded1 = await decoder.decode(data1);
    playAudio(decoded1);
    
    const decoded2 = await decoder.decode(data2);
    playAudio(decoded2);
  5. Multichannel Output Speaker Mapping

    main

    The decoder supports up to 255 channels. Each channel index is assigned to a specific speaker location following standard Vorbis/RFC 7845 conventions:

    • 1 channel: monophonic (mono)
    • 2 channels: stereo (left, right)
    • 3 channels: linear surround (left, center, right)
    • 4 channels: quadraphonic (front left, front right, rear left, rear right)
    • 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right)
    • 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE)
    • 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE)
    • 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE)
  6. Configure multichannel speaker mapping

    main

    The decoder supports up to 255 channels. For standard channel counts, speaker locations are assigned following the Vorbis codec convention:

    • 1 channel: monophonic (mono)
    • 2 channels: stereo (left, right)
    • 3 channels: linear surround (left, center, right)
    • 4 channels: quadraphonic (front left, front right, rear left, rear right)
    • 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right)
    • 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE)
    • 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE)
    • 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE)
    • 9-255 channels: No mapping defined.
  7. Understand the decoded audio data format

    main

    The decode methods return a promise that resolves to an object containing the PCM audio data and metadata. The channelData array contains Float32Array objects that can be used directly with the WebAudio API.

    Decoded Object Structure:

    {
        channelData: [
          leftAudio, // Float32Array of PCM samples for the left channel
          rightAudio, // Float32Array of PCM samples for the right channel
          ... // additional channels
        ],
        samplesDecoded: 1234, // number of PCM samples that were decoded per channel
        sampleRate: 48000, // sample rate of the decoded PCM
        bitDepth: 16, // bit depth of the original Ogg Vorbis file
        errors: [ // array containing descriptions for any decode errors
          {
            message: "OV_ENOTVORBIS the packet is not a Vorbis header packet.",
            frameLength: 400,
            frameNumber: 5,
            inputBytes: 11606,
            outputSamples: 20480,
          }
        ]
    }

    Note: Decoding continues even if errors are encountered, though errors may result in audio gaps.

  8. How MPEGDecoder and MPEGDecoderWebWorker work together

    main

    The library provides two main classes for decoding MPEG Layer (I/II/III) audio:

    1. MPEGDecoder: Decodes data synchronously on the main thread. Use this for simple tasks where blocking the main thread is acceptable.
    2. MPEGDecoderWebWorker: Decodes data asynchronously within a Web Worker. This is non-blocking and allows for concurrent decoding of multiple streams by spawning multiple workers. Each instance runs in its own thread.

    Both classes require you to wait for the WASM module to compile by awaiting the .ready promise before attempting to decode data.

    // Main thread synchronous
    const decoder = new MPEGDecoder();
    await decoder.ready;
    
    // Web Worker asynchronous
    const workerDecoder = new MPEGDecoderWebWorker();
    await workerDecoder.ready;
  9. Quickstart: Decode Ogg Opus data

    main

    To decode audio, create an instance of OggOpusDecoder (main thread) or OggOpusDecoderWebWorker (asynchronous worker), wait for the ready promise to resolve, and then call decode() or decodeFile() with a Uint8Array of Ogg Opus data.

    import { OggOpusDecoder } from 'ogg-opus-decoder';
    
    const decoder = new OggOpusDecoder();
    
    // wait for the WASM to be compiled
    await decoder.ready;
    
    // Decode an individual Opus frame
    const {channelData, samplesDecoded, sampleRate} = await decoder.decode(oggOpusData);
    
    // When done, reset or free
    await decoder.reset();
    // or
    decoder.free();
  10. Install @wasm-audio-decoders/opus-ml via script tag

    main

    You can download the build and include it directly in your HTML. Ensure the script is read using UTF-8 encoding. If running in a browser, include the charset="UTF-8" attribute on the <script> tag or a <meta charset="utf-8" /> in your HTML.

    <script src="opus-ml-decoder.min.js" charset="UTF-8"></script>
    <script>
      const decoder = new window["opus-ml"].OpusMLDecoder();
    </script>
  11. Best practices for using OpusDecoderWebWorker

    main

    To prevent blocking the main thread, avoid using await on every decodeFrame call. Instead, use .then() to handle the decoded data. This allows the worker to queue up operations and process them in the background while your main thread continues other work.

    Recommended Pattern (Non-blocking)

    const playAudio = ({ channelData, samplesDecoded, sampleRate }) => {
      // does something to play the audio data.
    }
    
    // Operations are queued and processed in the worker thread
    decoder.decodeFrame(frameData1).then(playAudio);
    decoder.decodeFrame(frameData2).then(playAudio);
    decoder.decodeFrame(frameData3).then(playAudio);
    
    // Main thread remains responsive

    Avoid this pattern (Blocking)

    // This negates the benefit of the Web Worker by halting the main thread
    const decoded1 = await decoder.decodeFrame(frameData1);
    playAudio(decoded1);
    
    const decoded2 = await decoder.decodeFrame(frameData2);
    playAudio(decoded2);
    const playAudio = ({ channelData, samplesDecoded, sampleRate }) => {
      // does something to play the audio data.
    }
    
    decoder.decodeFrame(frameData1).then(playAudio);
    decoder.decodeFrame(frameData2).then(playAudio);
    decoder.decodeFrame(frameData3).then(playAudio);
    
    // do some other operations while the audio is decoded
  12. Install @wasm-audio-decoders/ogg-vorbis

    main

    You can install the Ogg Vorbis decoder via NPM for Browser and NodeJS support, or download the build directly for script inclusion.

    Via NPM

    Run the following command:

    npm i @wasm-audio-decoders/ogg-vorbis

    Via Script Tag

    Download the build and include it in your HTML. Note: The script must be read using UTF-8 encoding. Ensure your <script> tag includes charset="UTF-8" or your HTML includes <meta charset="utf-8" />.

    <script src="ogg-vorbis-decoder.min.js" charset="UTF-8"></script>
    <script>
      const decoder = new window["ogg-vorbis-decoder"].OggVorbisDecoder();
    </script>
    npm i @wasm-audio-decoders/ogg-vorbis