first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
# `utils/inspect`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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
```ts
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
```ts
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`.