RIFF chunks
A WAV file is a RIFF file: one outer chunk that holds a list of inner chunks. Every chunk has the same eight-byte header, so a reader can step over chunks it does not know.
The RIFF header
The file starts with the outer chunk’s header and its form type.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 4 | char[4] | ckID | RIFF, or RF64 for a file over 4 GB |
| 4 | 4 | u32 | ckSize | the size of everything after this field: the file size minus 8 |
| 8 | 4 | char[4] | formType | WAVE |
The chunk layout
The rest of the file is a run of chunks, back to back. All numbers are little-endian.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| +0 | 4 | char[4] | ckID | four ASCII characters naming the chunk, padded with spaces, such as fmt and data |
| +4 | 4 | u32 | ckSize | the size of the chunk’s data, not counting this header or the pad byte |
| +8 | ckSize | bytes | ckData | the chunk’s contents |
+8+ckSize | 0 or 1 | u8 | pad | a zero byte, present only when ckSize is odd |
The pad byte keeps every chunk on an even offset. It is easy to forget: an 8-bit mono
file with an odd number of samples has an odd data size, and the next
chunk starts one byte later than the size alone suggests.
Chunk order
The format chunk must come before the data chunk, because the data cannot be read without it. Other chunks can appear before or after, in any order. Writers often put small metadata chunks first and the data chunk last, or append metadata after the samples once a recording has finished.
A reader should look for chunks by ID and skip any it does not recognise, using the
size and the pad rule. A JUNK chunk holds nothing useful and is there
only to reserve space or align the data.
| Chunk | Holds | Required |
|---|---|---|
fmt | how the audio is encoded | yes |
data | the samples | yes |
fact | the number of sample frames | for compressed formats |
LIST | text tags, or labels for cue points | no |
cue | markers at sample positions | no |
smpl | root note and loop points for samplers | no |
bext | broadcast production details | no |
JUNK | reserved space, ignored | no |
A complete file
The smallest useful WAV file is 44 bytes of headers and then the samples. This one holds four frames of 16-bit stereo audio at 44,100 Hz.
00000000 52 49 46 46 34 00 00 00 57 41 56 45 66 6D 74 20 RIFF4...WAVEfmt
00000010 10 00 00 00 01 00 02 00 44 AC 00 00 10 B1 02 00 ........D.......
00000020 04 00 10 00 64 61 74 61 10 00 00 00 00 00 00 00 ....data........
00000030 FF 7F 01 80 FF FF 01 00 00 01 00 FF ............
| Offset | Bytes | Meaning |
|---|---|---|
| 0 | 52 49 46 46 | RIFF |
| 4 | 34 00 00 00 | 52 bytes follow: the file is 60 bytes |
| 8 | 57 41 56 45 | WAVE |
| 12 | 66 6D 74 20 | fmt chunk |
| 16 | 10 00 00 00 | 16 bytes of format data |
| 20 | 01 00 | format code 1, PCM |
| 22 | 02 00 | 2 channels |
| 24 | 44 AC 00 00 | 44,100 samples per second |
| 28 | 10 B1 02 00 | 176,400 bytes per second |
| 32 | 04 00 | 4 bytes per frame |
| 34 | 10 00 | 16 bits per sample |
| 36 | 64 61 74 61 | data chunk |
| 40 | 10 00 00 00 | 16 bytes of samples: 4 frames |
| 44 | 16 bytes | the samples, decoded on Sample data |
Finding the samples
A robust reader never assumes the 44-byte layout. It walks the chunks:
- Read 12 bytes and check for
RIFFandWAVE. - Read an 8-byte chunk header.
- If the ID is
fmt, read the format. If it isdata, note where the samples start and how long they are. - Skip
ckSizebytes, plus one more ifckSizeis odd, and go back to step 2 until the end of the file.