Reference
Specification
Wave File Format
Wave 文件有一个主 RIFF 块,其中包括一个 WAVE 标识符,后跟子块。
数据以小端字节序存储。
Field | Length | Contents |
---|---|---|
ckID | 4 | Chunk ID: “RIFF” |
cksize | 4 | Chunk size: 4+n |
WAVEID | 4 | WAVE ID: “WAVE” |
WAVE chunks | n | Wave chunks containing format information and sampled data |
fmt Chunk
fmt
指定数据的格式。采样数据的 Format Chunk
有 3 种变体。它们的不同之处在于对基本 fmt
块的扩展。
Field | Length | Contents |
---|---|---|
ckID | 4 | Chunk ID: “fmt” |
cksize | 4 | Chunk size: 16, 18 or 40 |
wFormatTag | 2 | Format code |
nChannels | 2 | Number of interleaved channels |
nSamplesPerSec | 4 | Sampling rate (blocks per second) |
nAvgBytesPerSec | 4 | Data rate |
nBlockAlign | 2 | Data block size (bytes) |
wBitsPerSample | 2 | Bits per sample |
cbSize | 2 | Size of the extension (0 or 22) |
wValidBitsPerSample | 2 | Number of valid bits |
dwChannelMask | 4 | Speaker position mask |
SubFormat | 16 | GUID, including the data format code |
波形数据的标准格式代码如下。上面的参考资料为压缩数据提供了更多的格式代码,其中很大一部分现已过时。
Format Code | PreProcessor Symbol | Data |
---|---|---|
0x0001 | WAVE_FORMAT_PCM | PCM |
0x0003 | WAVE_FORMAT_IEEE_FLOAT | IEEE float |
0x0006 | WAVE_FORMAT_ALAW | 8-bit ITU-T G.711 A-law |
0x0007 | WAVE_FORMAT_MULAW | 8-bit ITU-T G.711 µ-law |
0xFFFE | WAVE_FORMAT_EXTENSIBLE | Determined by SubFormat |
PCM Format
Format Chunk
的第一部分用于描述 PCM 数据。
- 对于 PCM 数据,header 中的
Format Chunk
声明每个样本中的位数/样本数 (wBitsPerSample
)。原始文档(修订版 1)指定每个样本的位数将四舍五入到下一个 8 位的倍数。这个四舍五入的值是容器大小。此信息是多余的,因为每个样本的容器大小(以字节为单位)也可以通过块大小除以通道数 (nBlockAlign
/nChannels
) 来确定。 - PCM 数据是二进制补码,除了 1-8 位的分辨率,它们表示为偏移二进制。
Non-PCM Formats
扩展 Format Chunk
用于非 PCM 数据。cbSize
字段给出了扩展的大小。
- 对于除 PCM 之外的所有格式,
Format Chunk
必须有一个扩展部分。扩展名的长度可以为零,但必须存在大小字段(值为 0)。 - 对于浮点数据,满量程为 1。位/样本通常为 32 或 64。
- 对于 log-PCM 格式(μ-law 和 A-law),Rev. 3 文档指出位/样本字段 (
wBitsPerSample
) 应设置为 8 位。 - 非 PCM 格式必须有一个
fact Chunk
。
Extensible Format
WAVE_FORMAT_EXTENSIBLE
格式代码表示 Format Chunk
有扩展。扩展有一个字段,用于声明有效位数/样本(wValidBitsPerSample
)。另一个字段 (dwChannelMask
) 包含指示从通道到扬声器位置的映射的位。最后一个字段 (SubFormat
) 是一个 16 字节的全局唯一标识符 (GUID)。
- 对于
WAVE_FORMAT_EXTENSIBLE
格式,原始位/样本字段 (wBitsPerSample
) 必须与容器大小 (8 *nBlockAlign
/nChannels
) 匹配。这意味着wBitsPerSample
必须是 8 的倍数。容器大小内降低的精度现在由wValidBitsPerSample
指定。 - 有效位数 (
wValidBitsPerSample
) 仅供参考。数据以容器尺寸的精度正确表示。有效位的数量可以是从 1 到容器大小(以位为单位)之间的任何值。 - 扬声器位置掩码使用 18 位,每个位对应一个扬声器位置(例如左前或右上),以指示声道到扬声器的映射。更多细节在上面引用的文件中。该字段是信息性的。全零字段表示通道按顺序映射到输出:第一个通道到第一个输出,第二个通道到第二个输出,等等。
- GUID 的前两个字节形成指定数据格式代码的子代码,例如
WAVE_FORMAT_PCM
。剩下的 14 个字节包含一个固定的字符串,\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71
。
在以下情况下应使用 WAVE_FORMAT_EXTENSIBLE
格式:
- PCM 数据超过 16 位/样本。
- 通道数大于2。
- 实际位数/样本不等于容器大小。
- 需要指定从声道到扬声器的映射。
fact Chunk
所有(压缩的)非 PCM 格式都必须有一个fact Chunk
(Rev. 3 文档)。该块至少包含一个值,即文件中的样本数。
Field | Length | Contents |
---|---|---|
ckID | 4 | Chunk ID: “fact” |
cksize | 4 | Chunk size: minimum 4 |
dwSampleLength | 4 | Number of samples (per channel) |
- Rev. 3 文档指出,所有新的 WAVE 格式都需要
fact Chunk
,但标准WAVE_FORMAT_PCM
文件不需要。假设具有 IEEE 浮点数据的文件(在 Rev. 3 文档之后引入)需要一个fact Chunk
。 - 样本数字段对于采样数据是多余的,因为
data Chunk
指示数据的长度。样本的数量可以根据数据的长度和由Format Chunk
确定的容器大小来确定。 - 对于多通道数据的样本数的含义存在歧义。Rev. 3 文档中的含义是它应该被解释为每个通道的样本数。Rev. 3 文档中的声明是:
波形标头中的nSamplesPerSec
字段与dwSampleLength
字段结合使用以确定以秒为单位的数据长度。
在此计算中没有提及通道数,这意味着dwSampleLength
是每个通道的样本数。 - 关于
fact Chunk
是否应该用于(包括那些带有 PCM 的)WAVE_FORMAT_EXTENSIBLE
文件存在一个问题。带有来自 Microsoft 的 PCM 数据的WAVE_FORMAT_EXTENSIBLE
的一个示例没有fact Chunk
。
data Chunk
data Chunk
包含采样数据。
Field | Length | Contents |
---|---|---|
ckID | 4 | Chunk ID: “data” |
cksize | 4 | Chunk size: n |
sampled data | n | Samples |
pad byte | 0 or 1 | Padding byte if n is odd |
demo
以解析 KickDrum.wav 为例,分析 WAV 封装格式。
文件流转16进制
源代码
|
|
转换结果
|
|
分析
Field | Length | 16进制 | Contents | 所在行号 |
---|---|---|---|---|
ckID | 4 | 52 49 46 46 | RIFF |
00000001 |
cksize | 4 | c0 0b 01 00 | 0x00010bc0 = 68544字节 = 4284行 即下一层 的数据大小为:4284行,也就是到第4285行的前8个数据为止 |
00000001 |
WAVEID | 4 | 57 41 56 45 | WAVE |
00000001 |
ckID | 4 | 66 6d 74 20 | fmt |
00000001 |
cksize | 4 | 10 00 00 00 | 0x00000010 = 16 | 00000002 |
wFormatTag | 2 | 01 00 | 0x0001 = WAVE_FORMAT_PCM |
00000002 |
nChannels | 2 | 01 00 | 0x0001 | 00000002 |
nSamplesPerSec | 4 | 44 ac 00 00 | 0x0000ac44 = 44100Hz | 00000002 |
nAvgBytesPerSec | 4 | 88 58 01 00 | 0x00015888 = 88200Hz | 00000002 |
nBlockAlign | 2 | 02 00 | 0x0002 = 2 | 00000003 |
wBitsPerSample | 2 | 10 00 | 0x0010 = 16 | 00000003 |
ckID | 4 | 64 61 74 61 | data |
00000003 |
cksize | 4 | 94 09 01 00 | 0x00010994 = 67988 = 4249行余4 | 00000003 |
sampled data | 67988 | 第3行的后4个数据 ~ 第4252行结束 | 00000003 ~ 00004252 | |
ckID | 4 | 53 41 55 52 | SAUR |
00004253 |
cksize | 4 | 00 02 00 00 | 0x00000200 = 512 = 32行 | 00004253 |
数据 | 512 | 第4253行的后8个数据 ~ 第4285行的前8个数据 | 00004253 ~ 00004285 |