Files
skills/docs/media/audio/audio-decode-wav/src/utils/inspect.md
2026-05-29 08:20:56 +01:00

3.2 KiB

utils/inspect

(no submodules)

Purpose

inspectWavHeader(bytes) is the wrapper-layer pre-scan that classifies a WAV byte buffer before the upstream @audio/decode-wav library is invoked. The upstream library throws an undifferentiated TypeError for "Not a WAV file", unsupported formats and missing chunks, so the wrapper's spec requirement to distinguish CORRUPT_HEADER, TRUNCATED_BODY and UNSUPPORTED_FORMAT is satisfied here, in pure JavaScript, without speculative decoding. The function returns a tagged-union result and never throws.

Features

  • Walks the RIFF chunk list (fmt, data, plus any auxiliary chunks) without allocating.
  • Distinguishes corrupt (RIFF/WAVE magic missing, fmt chunk too short, no data chunk, non-progressing chunk size, data-before-fmt) from truncated (data chunk declares more bytes than the buffer holds) from unsupported (format code recognised but non-PCM/non-IEEE-float).
  • Recognises seven WAV format codes: PCM (0x0001), MS-ADPCM (0x0002), IEEE float (0x0003), A-law (0x0006), μ-law (0x0007), IMA-ADPCM (0x0011), WAVE_FORMAT_EXTENSIBLE (0xFFFE). Unknown codes map to format: "unknown".
  • Honours odd-byte padding inside the chunk walk (every chunk's size & 1 adds a pad byte before the next chunk).

Usage: Basic

import { inspectWavHeader } from "@suaveplan/audio-decode-wav";

const result = inspectWavHeader(wavBytes);
if (result.kind === "ok") {
    console.log(result.sampleRate, result.channels, result.bitsPerSample);
}

Usage: Advanced

import { inspectWavHeader } from "@suaveplan/audio-decode-wav";

function summarise(bytes: Uint8Array): string {
    const r = inspectWavHeader(bytes);
    switch (r.kind) {
        case "ok":
            return `${r.channels} ch @ ${r.sampleRate} Hz, ${r.bitsPerSample}-bit, data=${r.dataBytesDeclared}`;
        case "truncated":
            return `truncated: ${r.bytesAvailable}/${r.bytesDeclared}`;
        case "unsupported":
            return `unsupported: ${r.format}`;
        case "corrupt":
            return `corrupt: ${r.reason}`;
    }
}

API Reference

  • function inspectWavHeader(bytes: Uint8Array): InspectResult — never throws.
  • type InspectResult = InspectOk | InspectCorrupt | InspectTruncated | InspectUnsupported.
  • interface InspectOk — { kind: "ok"; sampleRate; channels; bitsPerSample; dataStart; dataBytesDeclared }.
  • interface InspectCorrupt — { kind: "corrupt"; reason: string }.
  • interface InspectTruncated — { kind: "truncated"; bytesAvailable; bytesDeclared }.
  • interface InspectUnsupported — { kind: "unsupported"; format: AudioFormatType }.

Implementation Notes

The function reads chunk identifiers as ASCII via String.fromCharCode rather than decoding UTF-8 — RIFF chunk IDs are guaranteed ASCII per the spec, so this is faster and avoids host text-decoder dependencies. The buffer-overrun guard (pos + 8 + chunkSize > bytes.length) catches both a too-short fmt chunk and a malformed data chunk before the upstream library has a chance to throw. The order of checks matters: fmt must precede data, so a data-before-fmt layout is classified corrupt, not truncated.