WASM Audio Decoders
repository·main·Indexed 20 days ago
https://github.com/eshaz/wasm-audio-decodersA 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.
What's inside wasm-audio-decoders
- 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.
Understand multichannel output and speaker mapping
mainThe 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)
Understand multichannel output mapping
mainThe 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.
How to properly use OggOpusDecoderWebWorker to avoid blocking
mainTo maximize concurrency and avoid blocking the main thread, do not
awaiteverydecode()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);Multichannel Output Speaker Mapping
mainThe 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)
Configure multichannel speaker mapping
mainThe 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.
Understand the decoded audio data format
mainThe
decodemethods return a promise that resolves to an object containing the PCM audio data and metadata. ThechannelDataarray containsFloat32Arrayobjects 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.
How MPEGDecoder and MPEGDecoderWebWorker work together
mainThe library provides two main classes for decoding MPEG Layer (I/II/III) audio:
MPEGDecoder: Decodes data synchronously on the main thread. Use this for simple tasks where blocking the main thread is acceptable.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
.readypromise 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;Quickstart: Decode Ogg Opus data
mainTo decode audio, create an instance of
OggOpusDecoder(main thread) orOggOpusDecoderWebWorker(asynchronous worker), wait for thereadypromise to resolve, and then calldecode()ordecodeFile()with aUint8Arrayof 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();Install @wasm-audio-decoders/opus-ml via script tag
mainYou 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>Best practices for using OpusDecoderWebWorker
mainTo prevent blocking the main thread, avoid using
awaiton everydecodeFramecall. 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 responsiveAvoid 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 decodedInstall @wasm-audio-decoders/ogg-vorbis
mainYou 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-vorbisVia 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 includescharset="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