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) fromtruncated(data chunk declares more bytes than the buffer holds) fromunsupported(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 toformat: "unknown". - Honours odd-byte padding inside the chunk walk (every chunk's
size & 1adds 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.