Sun/NeXT audio (.au / .snd) file header encoding and decoding.

An .au file opens with a 24-byte big-endian header, an optional variable-length annotation field, and then the raw audio samples:

 0      7 8     15 16    23 24    31
+--------+--------+--------+--------+
|         Magic (".snd")            |
+--------+--------+--------+--------+
|           Data Offset             |
+--------+--------+--------+--------+
|            Data Size              |
+--------+--------+--------+--------+
|            Encoding               |
+--------+--------+--------+--------+
|           Sample Rate             |
+--------+--------+--------+--------+
|            Channels               |
+--------+--------+--------+--------+
|     Annotation (variable)         |
+-----------------------------------+

Every field is big-endian regardless of the host platform — the format originates from big-endian Sun hardware and never gained a little-endian variant.

dataOffset is the byte offset from the start of the file to the first audio sample, so the annotation field is dataOffset - 24 bytes long and is conventionally used for a NUL-padded comment. The minimum legal dataOffset is therefore 24 (empty annotation).

This coder covers the header and annotation only. Audio samples are left to the caller: dataSize is permitted to be 0xffffffff (AU_DATA_SIZE_UNKNOWN) meaning "unknown, read to end of file", which no fixed-length coder can express.

Examples

Round-trip a 16-bit stereo header

import { assertEquals } from "@std/assert";
import { auHeader, AU_ENCODING, AU_MAGIC } from "@binstruct/au";

const coder = auHeader();
const header = {
  magic: AU_MAGIC,
  dataOffset: 24,
  dataSize: 1024,
  encoding: AU_ENCODING.LINEAR_16,
  sampleRate: 44100,
  channels: 2,
  annotation: new Uint8Array(0),
};

const buffer = new Uint8Array(24);
const written = coder.encode(header, buffer);
const [decoded, read] = coder.decode(buffer);

assertEquals(written, 24);
assertEquals(read, 24);
assertEquals(decoded.sampleRate, 44100);
assertEquals(decoded.channels, 2);
assertEquals(decoded.encoding, AU_ENCODING.LINEAR_16);