Inspect a WAV file's header
Reads the header of a WAV file in your browser and reports the sample rate, bit depth, channel count, encoding and exact length, along with every RIFF chunk the file contains and what each one is for. The file is never uploaded.
Any RIFF WAVE file, including Broadcast Wave and RF64. It is read in this tab and never sent anywhere.
How it works
What this does
Answers the questions a WAV file will not answer by being played: what rate it was recorded at, how many bits deep it is, how it is encoded, and exactly how long it is. Those are the figures that decide whether a file will import, and they live in forty-four bytes at the front that no player shows you.
The reason it is worth reading them is that a WAV header can be wrong. Sample rate, channel count and audio length are all recorded independently of the audio itself, so a file can be internally inconsistent and still open. When a recording plays at the wrong speed, arrives half a second short, or is refused by a mastering tool that will not say why, the answer is usually visible here.
The method
A WAV file is a RIFF container: twelve bytes of preamble, then a flat list of
chunks. Each chunk is four ASCII characters of identifier, a 32-bit length, and
that many bytes of payload. Two chunks are required — fmt , which describes
the encoding, and data, which holds the samples — and everything else is
metadata that recorders and editors add.
Three details in that walk are where a naive reader goes wrong, and all three appear in ordinary files:
A payload is padded to an even length, and the pad byte is not counted. Skip it and every chunk after the first odd-length one is read one byte off the mark, which does not produce an error — it produces a plausible list of nonsense.
A declared length may be longer than the file. That is a truncated recording, and it is common enough that refusing the file would be the wrong answer. The length is clamped to what is present and both figures are reported.
A chunk may declare a length of zero. That is legal, and a walk that advanced by the declared length would sit on it forever. The offset here always moves by at least the eight bytes of the chunk header.
The length itself is not stored anywhere in a WAV file. It is derived: the
number of bytes of audio, divided by the number of bytes in one sample frame,
divided by the number of frames per second. For PCM, float, A-law and mu-law
that division is exact, because every frame is the same width. For a compressed
format it is not — the number of frames in a block varies — so the length comes
from the fact chunk, which exists for exactly that reason, and falls back to
the average byte rate when a file omits it.
One more thing is unwrapped. Anything above two channels or above 16 bits is
meant to declare the format tag WAVE_FORMAT_EXTENSIBLE, which is not a format
at all: the real tag is the first bytes of a 16-byte GUID twenty-four bytes
further into the chunk. A reader that stops at the front of fmt reports a
perfectly ordinary 24-bit master as an unknown encoding.
Before you read on
A WAV chunk declares a payload of 4,001 bytes — an odd number. Where does the next chunk begin?
4,002 bytes on. A RIFF payload is padded to an even length and the pad byte is not counted in the declared length, so a reader that advances by the length alone drifts one byte for every odd chunk it passes. What makes it the worst kind of bug is that it does not produce an error — it produces a plausible list of nonsense, four bytes of misaligned payload read as a chunk identifier, and a file that looks parsed. Two related cases sit beside it here: a declared length longer than the file is a truncated recording rather than a reason to refuse it, and a chunk may legally declare zero, so the walk always advances by at least the eight bytes of a chunk header.
4,000 bytes of audioThe declared length of the data chunk, and the only figure about duration the file actually contains.
/ 2 bytes per frame = 2,000 framesA frame is every channel sampled at one instant. Here that is one channel at 16 bits, so two bytes.
/ 8,000 frames per second = 0.25 sShown as 0:00.250. Nothing in the header says this; it is derived every time.
exact only when every frame is the same widthTrue for PCM, float, A-law and mu-law. For a compressed format the frames per block vary, so the count comes from the fact chunk — which exists for precisely this reason — and falls back to the average byte rate when a file omits it.
A worked example
The file tone.wav used by this tool’s browser test is 4,044 bytes. Its header
reads:
offset bytes meaning
0 52 49 46 46 "RIFF"
4 c4 0f 00 00 4,036 — the size of everything after this field
8 57 41 56 45 "WAVE"
12 66 6d 74 20 "fmt "
16 10 00 00 00 16 — the fmt payload is 16 bytes long
20 01 00 format tag 1: PCM
22 01 00 1 channel
24 40 1f 00 00 8,000 frames per second
28 80 3e 00 00 16,000 bytes per second
32 02 00 2 bytes per frame
34 10 00 16 bits per sample
36 64 61 74 61 "data"
40 a0 0f 00 00 4,000 bytes of audio
44 ... the audio
Every number in the multi-byte fields is little-endian, so 40 1f 00 00 is
0x00001f40, which is 8,000.
From that:
| Figure | Working | Result |
|---|---|---|
| Sample frames | 4,000 bytes ÷ 2 bytes per frame | 2,000 |
| Length | 2,000 frames ÷ 8,000 per second | 0.25 s, shown as 0:00.250 |
| Bit rate | 16,000 bytes × 8 ÷ 1,000 | 128 kbps |
| Chunks | fmt at offset 12, data at offset 36 | 2 |
Two cross-checks that the file is internally consistent: 44 bytes of header plus 4,000 bytes of audio is 4,044, which is the size of the file; and the declared RIFF size of 4,036 is that figure minus the eight bytes of the RIFF identifier and its own length field.
These are the same numbers asserted in this tool’s test file, against the same bytes on disk, so if the parser ever changes without this page changing with it the build fails.
What it does not do
It does not decode any audio, so it cannot tell you whether a take is clipped,
silent, noisy or corrupt — only what the file says it is. It reads WAV files
and nothing else: an MP3, a FLAC, an AIFF or an M4A is recognised only well
enough to say so in the error. It does not read the contents of metadata chunks,
so a bext chunk is listed with its size and its purpose but its timecode and
originator are not shown. It changes nothing and writes nothing back — the only
thing it produces is a JSON description you can download.
And it describes a file rather than fingerprinting one. If the question is whether two copies are byte-for-byte identical, no header can answer it — a file checksum can. If the header is sound and the next job is to keep one time range, trim a WAV file after inspecting it.
How it is done
- Read the first twelve bytes and check that they say RIFF (or RIFX, or RF64) followed by a size and then WAVE. Anything else is a different format, and the message names what it appears to be instead.
- Walk the chunk list from byte twelve. Each chunk is four ASCII bytes of identifier, a 32-bit length, and that many bytes of payload, padded with one unused byte when the length is odd.
- Clamp every declared length to the bytes actually present and always advance at least eight bytes, so a file with a corrupt chunk table produces an answer rather than a hang or a crash.
- Read the fmt chunk for the format tag, the channel count, the sample rate, the byte rate, the block alignment and the bits per sample.
- When the format tag is WAVE_FORMAT_EXTENSIBLE, read the real tag from the first bytes of the sub-format GUID twenty-four bytes further in, and the count of valid bits from the extension.
- Decide how many bytes of audio there are — the size the data chunk declares, unless it is zero or larger than the file, in which case use the bytes actually present.
- Divide the audio by the block alignment to get sample frames for a fixed-width format, or take the frame count from the fact chunk for a compressed one, then divide the frames by the sample rate to get the length in seconds.
- Write the figures out, and offer the whole header including the chunk map as a JSON download. Nothing is uploaded at any point.
What it assumes
- A WAV file does not store its duration anywhere. The length shown is worked out from the size of the audio and the rate the header claims, which is exactly what a player does, so a file with a wrong sample rate in its header reports a wrong length here and plays at the wrong speed everywhere.
- For a fixed-width format the frame count is the audio size divided by the block alignment, rounded down. A trailing partial frame is discarded, because a fraction of a frame cannot be played.
- Bit depth is the container width the header declares, not the number of bits carrying signal. Audio recorded at 24 bits and packed into 32-bit words reports 32, and the encoding line says how many of those bits are valid.
- A compressed format packs a varying number of frames into each block, so its length comes from the fact chunk. Without one, the byte rate is an average and the length is an estimate rather than an exact figure.
- Only the header is read and the audio is never decoded. A file whose header is correct and whose samples are silence, noise or corruption looks perfectly healthy here.
- When the declared audio size is sound it is used, and the length is exact. When it is zero or larger than the file, the fallback counts every byte from the audio to the end of the file, which over-reports by the size of any metadata sitting behind the audio. That is the safer error: the alternative under-reports an interrupted recording by all of its audio.
- The whole file is read into this tab even though only the first few hundred bytes are needed, which is why it is capped at 256 MB. Nothing is sent anywhere.
Common questions
Is my audio file uploaded anywhere?
No. The file is read in this browser tab and parsed by a worker running on your own machine. There is no server to send it to, and the automated test for this page fails if any request leaves this site while a file is loaded.
Why does this say 32-bit when my recorder says 24-bit?
Because those are two different numbers and the file carries both. A 24-bit sample does not fit a whole number of bytes comfortably, so many recorders and editors write it into a 32-bit container and set the valid bit count to 24. The bit depth shown is the container; the encoding line says how many bits are actually carrying signal.
Why is the length a fraction of a second different from my player?
Most likely because the data chunk declares a size that does not match the bytes present. A recording interrupted by a flat battery or a full card often leaves the declared size at zero or stops short of it, and different software resolves that differently. Under "More options" you can see both figures by switching between the size the header declares and every byte to the end of the file.
It says this is not a WAV file, but the name ends in .wav
The extension is a label, not a guarantee, and plenty of software writes an MP3 or an AIFF and calls it .wav. The check here is on the bytes at the front of the file, and the message names what the file appears to be instead — an MP3, an Ogg, a FLAC, an AIFF or an MP4 container.
What are all these extra chunks?
A WAV file is a list of chunks and only two of them are required. Everything else is metadata a recorder or an editor added — bext for broadcast timecode, iXML for production notes, LIST for artist and comment tags, cue and smpl for markers and loop points, and JUNK or FLLR as padding left so a later edit can grow the header without rewriting the file.
Can it tell me whether the recording is any good?
No. It reads the header and never decodes a sample, so it can tell you a file claims to be 96 kHz stereo but not whether there is anything above 20 kHz in it, and not whether the take is clipped, silent or corrupt.