audio-decode

repository·master·Indexed 42 days ago

https://github.com/audiojs/decode

A collection of audio decoders for Node.js and the browser that convert various formats into PCM float samples. The core @audio/decode package supports wav, mp3, flac, ogg, opus, aac, qoa, aiff, caf, webm, amr, and wma. Specialized codec packages include @audio/decode-aac (AAC/M4A, ALAC), @audio/decode-ac3 (Dolby Digital), @audio/decode-aiff (AIFF/AIFF-C), @audio/decode-amr (AMR-NB/WB), @audio/decode-ape (Monkey's Audio), and @audio/decode-avi (AVI demuxing).

Tokens
67.6K
Snippets
307
Records
376
Agent score
52%

What's inside audio-decode

  1. Decode tracker modules with @audio/decode-mod

    master

    @audio/decode-mod decodes tracker modules (MOD, XM, S3M, IT, MPTM, etc.) into PCM float samples using a WASM-compiled version of libopenmpt. It is designed for playing back chiptunes in the browser or bulk-converting tracker files to PCM/WAV.

    Important Note: A tracker module is a program (samples + patterns + playback sequence), not raw audio. Because of this, decode() requires the complete file; it cannot perform meaningful partial parsing of a truncated module.

    import decode, { decoder, info } from '@audio/decode-mod'
    
    // Basic decoding to PCM
    let { channelData, sampleRate } = await decode(modBytes)
    
    // Extract metadata without rendering audio
    let meta = await info(modBytes)
    // meta contains: { title, artist, type, typeLong, tracker, message, duration, channels, patterns, orders, instruments, samples }
  2. Decode MP4, MOV, M4A, M4V, and 3GP files

    master

    @audio/decode-mp4 is a pure-JS ISO BMFF demuxer that extracts the audio track from MP4-based containers (including MOV, M4A, M4V, and 3GP) and decodes it to PCM float samples. It automatically routes audio tracks to the appropriate codec package (e.g., AAC, MP3, Opus) which are loaded on demand.

    Important Note: Because codec packages are imported dynamically, this library cannot be used inside an AudioWorklet. You must perform decoding in the main thread or a Web Worker.

    import decode, { decoder } from '@audio/decode-mp4'
    
    // Decode a complete file
    let { channelData, sampleRate } = await decode(mp4Bytes)
  3. How APE decoding works in @audio/decode-ape

    master

    This package uses a single-file WASM ES module containing FFmpeg's ape decoder.

    Container Parsing: Since FFmpeg's ape decoder does not include a demuxer, this package implements the APE container parsing in JavaScript. It replicates libavformat/ape.c to handle the descriptor/header block, seek table, and per-frame packet layout.

    Supported Formats:

    • Monkey's Audio versions 3.80 through 3.99.
    • Mono or stereo.
    • 8, 16, or 24-bit depth.
    • All compression levels (fast, normal, high, extra high, insane).

    Frame Boundaries: Frame boundaries are derived from the header's seek table. The decoder processes frames as soon as their bytes are buffered. The final frame is handled during flush() to account for the fact that its length is not explicitly stored in the seek table.

  4. How E-AC-3 and AC-3 decoding works in @audio/decode-eac3

    master

    This package uses a single-file WASM ES module compiled from FFmpeg's eac3 decoder. It is a slim LGPL-2.1-or-later build with no GPL components.

    Key Behaviors:

    • Dual Format Support: It automatically detects and decodes both E-AC-3 (bitstream ID 16) and classic AC-3 (bitstream ID $\le$ 10).
    • Dynamic Range Compression (DRC): The drc_scale is forced to 0, effectively disabling DRC to ensure output levels are consistent with other packages like @audio/decode-ac3.
    • No Dialnorm: The decoder does not read or apply dialnorm.
    • Environment Compatibility: Because it is a single-file WASM module with no side files, it can be loaded from any CDN and works in Node.js, Web Workers, and AudioWorklets.
  5. WavPack decoding capabilities and limitations

    master

    This package uses a WASM-compiled version of libwavpack and supports:

    • Formats: Lossless, hybrid/lossy, and DSD-as-PCM (decimated to 24-bit PCM).
    • Bit depths: 8, 16, 24, and 32-bit integer, and 32-bit float.
    • Channels: Mono through multichannel.

    Limitations & Notes:

    • Correction Files: The .wvc correction file (used in lossless-hybrid two-file mode) is not read. Only the standalone .wv bitstream is supported.
    • Error Handling: Providing garbage or non-WavPack input will throw an error rather than returning empty or incorrect data.
  6. How streaming works in @audio/decode-mpc

    master

    The decoder uses a growable buffer inside WASM. To prevent bitstream desynchronization, frames are only decoded once at least 4352 bytes (MAX_FRAME_SIZE) are buffered ahead of the reader's cursor. This makes the decoder safe for any chunk size, including 1 byte at a time.

    Stream Version Behavior:

    • SV7 (MP+): Progressively emits frames as soon as the ~30-byte header is parsed.
    • SV8 (MPCK): Buffers (close to) the entire stream before the first frame is emitted because the seek table is located near the end of the file and must be read during initialization.
  7. DTS Input Requirements and Limitations

    master

    The decoder expects a raw DTS core frame stream (e.g., .dts files or tracks extracted by demuxers like @audio/decode-mp4, @audio/decode-webm, or @audio/decode-avi).

    Key technical details:

    • DTS-HD: DTS-HD Master Audio and High Resolution streams are decoded via their lossy core; extension substreams are skipped.
    • Variants: Supports 14-bit and little-endian sync variants.
    • Output Level: Output is full scale.
    • Channel Limit: Supports up to 5.1 channels.
  8. Perform synchronous decoding with specific codecs

    master

    While the umbrella @audio/decode is asynchronous (for detection and lazy loading), you can perform synchronous decoding by importing a codec package directly.

    JS-based synchronous codecs (wav, qoa, aiff, caf):

    import decode from '@audio/decode-wav'
    let pcm = decode(wavBytes)

    WASM-based codecs (require async initialization, then decode synchronously):

    import { decoder } from '@audio/decode-flac'
    let dec = await decoder()
    let pcm = dec.decode(bytes)
    let tail = dec.flush()
    dec.free()
  9. Understand the AudioData output format

    master

    The output of the decoding process is an AudioData object containing the decoded PCM float samples and the sample rate.

    Channel Ordering: Channels are returned in WAV order. For a 5.1 stream, the order is: FL (Front Left), FR (Front Right), FC (Front Center), LFE (Low Frequency Effects), BL (Back Left), BR (Back Right). The decoder supports up to 5.1 channels.

    Technical Details:

    • Output level is full scale (no dialnorm applied).
    • Input must be raw AC-3 frames (e.g., extracted from an MP4 or AVI container).
    • Note: E-AC-3 (Dolby Digital Plus) is not supported.
    interface AudioData {
      channelData: Float32Array[];
      sampleRate: number;
    }
  10. Supported DSD Formats (DSF and DFF)

    master

    The decoder supports the following formats:

    • DSF (Sony DSD Stream File): Supports DSD, fmt, and data chunks. Supports up to 5.1 channels and DSD64/128/256/512 sample rates. Supports 1-bit LSB-first or MSB-first packing. Data is interleaved in fixed 4096-byte-per-channel blocks. Metadata (ID3v2) can be accessed via @audio/decode-dsd/meta.
    • DFF (Philips DSDIFF): Supports FRM8, FVER, PROP, and DSD chunks. Data is interleaved byte-per-channel and is always MSB-first.

    Limitations:

    • DST Compression: Files with CMPR = 'DST ' will throw Unsupported: DST. DST is a separate codec.
    • Edited-master chunks: DIIN, DITI, etc., are ignored.
    • Metadata: Non-standard ID3 chunks are readable via @audio/decode-dsd/meta.
  11. How CRC32 errors are handled in TTA decoding

    master

    TTA1 uses CRC32 checksums for the header, seek table, and every frame:

    1. Header or Seek-table mismatch: Throws an error, as these define the stream structure.
    2. Frame mismatch: Not fatal. Because each frame resets its filter/predictor/Rice state, a bad frame is simply dropped, the errors count is incremented, and decoding continues with the next frame.