After the 32-byte header, a block is a sequence of sub-blocks, filling it exactly. Everything a block needs is in these, from its predictor settings to its audio.
Sub-block header
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 1 | ID | The low 6 bits are the ID; the top bits are flags, below |
| 1 | 1 | Size | The size of the data in 16-bit words |
| 2 | 2 | Size, high part | Only with the large flag: bits 8 to 23 of the word count |
| Mask | Name | Meaning |
|---|---|---|
0x3F | ID_UNIQUE | Mask for the ID |
0x20 | ID_OPTIONAL_DATA | A decoder that does not know this ID may skip it |
0x40 | ID_ODD_SIZE | The data is one byte shorter than the size says, and one padding byte follows it |
0x80 | ID_LARGE | The size uses three bytes |
The byte length is twice the word count, minus one with the odd flag. Data is padded to an even length, so the next sub-block starts on an even byte.
An unknown ID without the optional bit makes the reference library reject the block.
Worked example
Decorrelation terms with one term, 18, and a delta of 2. The term byte is
(18 + 5) | (2 << 5), which is 0x57. It is one byte, so the odd flag is set
and a padding byte follows:
42 01 57 00 id 0x02 | ID_ODD_SIZE, 1 word, term byte, padding
Sub-block IDs
| ID | Name | Holds |
|---|---|---|
0x00 | ID_DUMMY | Padding. Ignored |
0x01 | ID_ENCODER_INFO | Information about the encoder. Decoders ignore it, and its layout could not be confirmed |
0x02 | ID_DECORR_TERMS | Decorrelation terms and deltas |
0x03 | ID_DECORR_WEIGHTS | Weights |
0x04 | ID_DECORR_SAMPLES | Decorrelation sample history |
0x05 | ID_ENTROPY_VARS | Medians for the entropy coder |
0x06 | ID_HYBRID_PROFILE | Hybrid parameters |
0x07 | ID_SHAPING_WEIGHTS | Noise-shaping weights |
0x08 | ID_FLOAT_INFO | Floating-point settings |
0x09 | ID_INT32_INFO | Settings for wide integers |
0x0A | ID_WV_BITSTREAM | The audio bit stream |
0x0B | ID_WVC_BITSTREAM | The correction bit stream of a .wvc file |
0x0C | ID_WVX_BITSTREAM | Extended precision bits |
0x0D | ID_CHANNEL_INFO | Channel count and mask |
0x0E | ID_DSD_BLOCK | DSD audio |
0x21 | ID_RIFF_HEADER | The start of the original file, before the audio |
0x22 | ID_RIFF_TRAILER | The end of the original file, after the audio |
0x23 | ID_ALT_HEADER | The same as 0x21, for other file types |
0x24 | ID_ALT_TRAILER | The same as 0x22, for other file types |
0x25 | ID_CONFIG_BLOCK | Encoder settings |
0x26 | ID_MD5_CHECKSUM | 16-byte MD5 of the audio |
0x27 | ID_SAMPLE_RATE | A rate that is not in the table |
0x28 | ID_ALT_EXTENSION | The original file’s extension |
0x29 | ID_ALT_MD5_CHECKSUM | 16-byte MD5 for other file types |
0x2A | ID_NEW_CONFIG_BLOCK | Newer encoder settings |
0x2B | ID_CHANNEL_IDENTITIES | Named channels |
0x2C | ID_WVX_NEW_BITSTREAM | Extended precision bits, newer form |
0x2F | ID_BLOCK_CHECKSUM | A checksum of the block |
Bit streams
The WV and WVC streams have a nonzero, even length, and hold nothing but the bit stream. The WVX stream is longer than 4 bytes and even: it starts with a 32-bit little-endian CRC, and the bit stream starts at offset 4.
The newer WVX form 0x2C reads two 5-bit fields from the start of the bit stream. For floating point these are the minimum shifted zeros and the maximum shifted ones; otherwise one field gives the largest integer width.
Channel information
The payload of ID_CHANNEL_INFO is 1 to 7 bytes. A length of 6 or more is the newer form.
| Form | Bytes | Field |
|---|---|---|
| 1 to 5 bytes | 0 | Number of channels |
| 1 to 4 | Channel mask, little-endian | |
| The maximum stream count is 8, or the channel count if higher | ||
| 6 or 7 bytes | 0, and the low 4 bits of byte 2 | Channels minus 1, 12 bits |
| 1, and the high 4 bits of byte 2 | Streams minus 1, 12 bits | |
| 3 to 5 | Channel mask, bits 0 to 23 | |
| 6 | Channel mask, bits 24 to 31, if present |
The channel count cannot exceed twice the stream count, and the mask cannot have more bits than there are channels. There can be at most 4,096 streams.
ID_CHANNEL_IDENTITIES holds one byte for each channel. No byte may be 0; 0xFF means unknown.
Configuration
| ID | Offset | Field |
|---|---|---|
| ID_CONFIG_BLOCK | 0 to 2 | Bits 8 to 31 of the encoder’s configuration flags |
| 3 | If CONFIG_EXTRA_MODE is set: the extra mode | |
| 3 or 4 | If a byte remains: the low byte of qmode. Marks a WavPack 5 stream | |
| ID_NEW_CONFIG_BLOCK | 0 | File format code, below |
| 1 | The low byte of qmode | |
| 2 | Channel layout, as bits 16 to 23 | |
| 3, then 4 onwards | Channel count for the layout, then a channel reordering table |
| File format | Original file |
|---|---|
| 0 | Microsoft RIFF, including BWF and RF64 |
| 1 | Sony Wave64 |
| 2 | Apple Core Audio |
| 3 | Philips DSDIFF |
| 4 | Sony DSD Stream |
| 5 | Apple AIFF |
| qmode bit | Name | Meaning |
|---|---|---|
0x01 | QMODE_BIG_ENDIAN | The original data is big-endian |
0x02 | QMODE_SIGNED_BYTES | Bytes in the original data are signed |
0x04 | QMODE_UNSIGNED_WORDS | Words in the original data are unsigned |
0x08 | QMODE_REORDERED_CHANS | Channels were reordered |
0x10 | QMODE_DSD_LSB_FIRST | DSD bytes hold bits lowest first |
0x20 | QMODE_DSD_MSB_FIRST | DSD bytes hold bits highest first |
0x40 | QMODE_DSD_IN_BLOCKS | DSD data was in channel blocks, as in DSF |
0x1000 | QMODE_RAW_PCM | Raw PCM with no header. Above the low byte, so a program flag rather than a stored bit |
Other payloads
| ID | Payload |
|---|---|
| ID_RIFF_HEADER, ID_RIFF_TRAILER, ID_ALT_HEADER, ID_ALT_TRAILER | The bytes kept from the original file. The reference library accepts up to 16 MiB in total |
| ID_MD5_CHECKSUM, ID_ALT_MD5_CHECKSUM | Exactly 16 bytes |
| ID_SAMPLE_RATE | 3 bytes: the rate, little-endian. If 4 bytes: byte 3’s low 7 bits are bits 24 to 30 |
| ID_ALT_EXTENSION | Text of the extension; the reference library keeps only letters and digits |
The block checksum
The payload is 2 or 4 bytes, never odd. It is calculated over the 16-bit little-endian words of the block, from its first byte up to, but not including, this sub-block’s own header:
csum = 0xFFFFFFFF
for each word w: csum = csum × 3 + w
4-byte payload: compare csum
2-byte payload: csum ^= csum >> 16, then compare the low 16 bits