Format reference · .wav

From sample bytes to sound

Listen to an original sound, inspect its PCM bytes, and follow the three container paths that the engine recognizes.

Main container
Microsoft RIFF / WAVE
Stock audio
PCM · 8 or 16 bits
Legacy forms
Raw PCM and DIGI
Common effects
Mono · 11,025 Hz · 8-bit

A sound you can inspect

Most Total Annihilation .wav files are standard RIFF WAVE containing PCM samples. There is no TA-specific metadata in that canonical container. Two legacy forms matter too: raw sample bytes with no header, and a fixed-layout DIGI container.

Listen on demand

Same chirp, two sample widths

An original 400-millisecond chirp waveform with a short attack and fading tail; unsigned eight-bit silence is centered at 128.

8-bit PCM · 4,454 bytes

Download the 8-bit RIFF

16-bit PCM · 8,864 bytes

Download the 16-bit RIFF

An original 400-millisecond descending chirp, generated for this guide. Both versions use 11,025 Hz mono PCM and the same synthesized waveform before quantization. The waveform above shows the 8-bit payload. Playback begins only when you press Play; these are browser audio controls, not a recreation of the retail audio backend.

Eight-bit PCM represents a sample as an unsigned byte centered around 128; 16-bit PCM uses a signed little-endian value centered around zero. More bits provide finer amplitude steps. In this example the 16-bit payload is twice the size; sample count, rate, and duration remain the same.

Sound effects and voices live in sounds/, referenced without extension by weapon TDFs, sound categories, and GUI events. Mission narration lives in camps/briefs/, selected by OTA fields such as narration= and glamoursound=.

First identify the container

The extension is not enough. The traced reader chooses a path from fixed signatures, in this order [02 §7; R-MALF-01 §10].

MatchSelected pathPayload and metadata
DIGI at 0, HSHD at 8, SDAT at 32Legacy DIGIRate at byte 22; bytes 40 through EOF; 8-bit mono.
Otherwise RIFF at 0 and WAVE at 8RIFF WAVEFirst fmt and first data chunks.
OtherwiseRawEntire file as unsigned 8-bit mono at 11,025 Hz.

An unrecognized header can therefore become sample data, including its supposed header bytes. Recognized but malformed containers are a different case from a failed signature match.

Byte layouts

RIFF container and chunks

All numeric fields here are little-endian. The top-level offsets are file-relative.

Scroll table horizontally to see all fields →

OffsetBytesTypeFieldMeaning
0x004ASCIIChunk IDRIFF.
0x044u32RIFF sizeDeclared container span minus 8.
0x084ASCIIForm typeWAVE.
0x0CVariableChunksChunk listWalk to the declared RIFF span.

Every child chunk starts with an eight-byte prefix. The literal space in fmt is part of its four-byte ID.

Scroll table horizontally to see all fields →

Chunk-relative offsetBytesTypeFieldMeaning
+0x004ASCIIIDFor example fmt or data.
+0x044u32SizePayload length, excluding the eight-byte prefix.
+0x08sizeBytesPayloadMetadata, sample bytes, or another chunk’s contents.

PCM format payload

These offsets are relative to the start of the fmt payload, after its eight-byte chunk prefix. The first format chunk must have at least 16 payload bytes.

Scroll table horizontally to see all fields →

OffsetBytesTypeFieldRetail read?
+0x002u16Format tagNo; stock PCM is tag 1.
+0x022u16ChannelsYes.
+0x044u32Sample rateYes.
+0x084u32Byte rateNo; wrapper derives it.
+0x0C2u16Block alignmentNo; wrapper derives it.
+0x0E2u16Bits per sampleYes.

For ordinary PCM, frame_bytes = channels × bits_per_sample / 8, and byte_rate = sample_rate × frame_bytes. A frame contains one sample per channel. The parser preserves the authored metadata words; the playback adapter separately derives its alignment.

DIGI fixed positions

Offsets are file-relative. This table describes the traced reader, not the full historical container specification.

Scroll table horizontally to see all fields →

OffsetBytesTypeFieldRetail behavior
0x004ASCIISignatureRequire DIGI for this path.
0x044BytesContainer size fieldNot used for locating the sample.
0x084ASCIIHeader signatureRequire HSHD.
0x0C10BytesOther header bytesNot used by the described sample extraction.
0x16 (22)4u32Sample rateLittle-endian; 11,000 is adjusted to 11,025.
0x1A6BytesOther header bytesNot used by the described sample extraction.
0x20 (32)4ASCIISample signatureRequire SDAT.
0x244BytesSDAT size fieldIgnored; sample extends to EOF.
0x28 (40)size − 40u8[]Sample bytesUnsigned 8-bit mono.

The sample-rate word’s little-endian interpretation is established independently of the unused container-size fields. Raw PCM has no layout table: byte 0 is already sample 0.

Walking chunks: the padding trap

Retail advances by chunk_size + 8, with no odd-byte padding. Standard RIFF padding can therefore shift the next chunk away from where this reader expects it.

One-byte chunk beginning at offset 12Position
Chunk prefix12–19
One payload byte20
Retail’s next chunk start21
Standard padding byte21
Standard next chunk start22

This is a one-byte difference in the next header’s address, not an audio sample conversion. The supplied RIFF fixtures have even-sized chunks, so this distinction does not affect them.

The first fmt and first data are selected independently from the beginning of the list: data can precede format. The walk stops when the next offset reaches RIFF size + 8. The first data chunk must declare a positive size and read back in full; otherwise the sample is null and the alias plays silently [02 R-MALF-01 §10].

The example’s 44-byte prefix

The 8-bit fixture uses a conventional 16-byte PCM format chunk followed immediately by data. Its header is 44 bytes because of this chosen chunk order and size; 44 bytes is not a universal WAVE header length.

File offsetContentsExample value
0x00RIFF + size + WAVERIFF size 4,446; file size 4,454.
0x0Cfmt + payload size16-byte format payload.
0x14PCM format payloadTag 1, mono, 11,025 Hz, 8-bit.
0x24data + payload size4,410 bytes.
0x2CSample payload4,410 complete one-byte frames.

4,410 / 11,025 = 0.4 seconds. The 16-bit version has 8,820 payload bytes and the same 4,410 frames, giving an 8,864-byte file. The two legacy downloads retain the same exact payload bytes as the 8-bit RIFF: raw totals 4,410 bytes, DIGI 4,450 bytes.

The original chirp’s attack and fading tail are encoded directly into the sample amplitudes. In-game volume, attenuation, and 3D positioning are runtime behavior, not extra WAV fields.

Profiles found in the research corpus

These counts describe the inspected corpus; they are neither format limits nor a promise that every installation contains the same files.

PCM profileObserved countTypical use
Mono · 11,025 Hz · 8-bit482Effects and unit voices.
Mono · 22,050 Hz · 16-bit74Mission briefing narration.
Stereo · 44,100 Hz · 16-bit4Core Contingency victory music.
Mono · 22,254 Hz · 8-bit1sounds/CDOGGY.WAV; a classic Macintosh-rate authoring leftover.

The inspected installation also contains one raw file, sounds/HONK.WAV, and one DIGI file, sounds/SING.WAV; both play as unsigned 8-bit mono at 11,025 Hz. The research’s retail button-click example was omitted from publication; the sound on this page is independently synthesized.

Parsing ends at a device boundary

Nanolathe’s shared formats.LoadAudio preserves container identity, authored PCM fields, and the full payload span. It checks file bounds and rejects truncated recognized containers. RIFF enumeration uses the declared span and the researched unpadded chunk stepping.

For retail static and transient samples, the wrapper derives PCM parameters and passes the selected sample length directly to DirectSound. There is no separate zero-length rejection or repair fallback. Creation failure gives a null sample; lock, short-read, or unlock failure releases the buffer and also returns null.

Empty raw input pathEstablished wrapper actionWhat remains unproven
Static / transientRequest a zero-byte device buffer.Whether the target backend accepts that request.
StreamingRequest a normal two-second buffer, then fill the initial EOF remainder with unsigned-8-bit silence and record the endpoint.Whether that backend successfully creates or plays it.

Streaming capacity comes from two seconds of the selected PCM parameters, independently of payload size [03 R-AUD-02 §1]. It therefore differs from the zero-size static request.

Sources and example files

Adapted from the owning WAV research at the pinned sidebar revision. The complete source snapshot retains its upstream bibliography and evidence labels. Numeric PCM field offsets are also reflected in the same revision’s shared audio parser.

All four audio files and the waveform were authored for this guide. scripts/wav-example.py --check reproduces them and independently reads both RIFF files with Python’s standard-library WAVE parser to verify rate, sample width, frame count, and payload. No retail sound recording is included.