WAV 文件是一种音频文件格式,通常基于 Microsoft 的 RIFF(Resource Interchange File Format)结构。它的**头部(Header)**定义了音频的基本信息,如采样率、声道数、位深、数据长度等。
下面是一个标准的 PCM 编码 WAV 文件头部的组成(44 字节)及每一部分所占字节数:
✅ WAV 文件头结构(44 字节)
偏移量 | 字段名 | 长度(字节) | 内容(ASCII或数值) |
---|---|---|---|
0 | ChunkID | 4 | 'RIFF' |
4 | ChunkSize | 4 | 文件总大小 – 8(= 36 + Subchunk2Size) |
8 | Format | 4 | 'WAVE' |
12 | Subchunk1ID | 4 | 'fmt ' |
16 | Subchunk1Size | 4 | 16(对于 PCM) |
20 | AudioFormat | 2 | 1 表示 PCM,其他为压缩格式 |
22 | NumChannels | 2 | 声道数:1=单声道,2=立体声 |
24 | SampleRate | 4 | 采样率,如 44100 |
28 | ByteRate | 4 | = SampleRate × NumChannels × BitsPerSample ÷ 8 |
32 | BlockAlign | 2 | = NumChannels × BitsPerSample ÷ 8 |
34 | BitsPerSample | 2 | 每个样本的位数,如 16 |
36 | Subchunk2ID | 4 | 'data' |
40 | Subchunk2Size | 4 | 实际音频数据的字节数 |
🧠 示例:立体声 16bit 44.1kHz 的 WAV 文件头内容说明
假设音频数据 1 秒,立体声(2通道),16 位:
参数 | 值 | 计算说明 |
---|---|---|
SampleRate | 44100 | 每秒采样 44100 次 |
BitsPerSample | 16 | 每个采样 16 位(2 字节) |
NumChannels | 2 | 左右两个声道 |
ByteRate | 44100 × 2 × 16 ÷ 8 = 176400 | 每秒多少字节 |
BlockAlign | 2 × 16 ÷ 8 = 4 | 一个样本块(所有通道)共 4 字节 |
Subchunk2Size | 176400 | 1 秒的数据量 |
ChunkSize | 36 + Subchunk2Size = 176436 | 总文件大小 – 8 字节 |
🧾 总结各字段含义及长度
字段名 | 意义 | 占字节 |
---|---|---|
ChunkID | 固定为 'RIFF' | 4 |
ChunkSize | 整个文件大小减去前8字节 | 4 |
Format | 固定为 'WAVE' | 4 |
Subchunk1ID | 固定为 'fmt ' | 4 |
Subchunk1Size | PCM 固定为 16 | 4 |
AudioFormat | PCM 为 1 | 2 |
NumChannels | 声道数量 | 2 |
SampleRate | 采样率(单位:Hz) | 4 |
ByteRate | 每秒数据字节数 = SampleRate × Channels × BitsPerSample ÷ 8 | 4 |
BlockAlign | 一个样本帧的字节数 = Channels × BitsPerSample ÷ 8 | 2 |
BitsPerSample | 位深(如 8/16/24) | 2 |
Subchunk2ID | 固定为 'data' | 4 |
Subchunk2Size | 实际音频数据的字节长度 | 4 |
🛠 如何读取/构造 WAV 头部(C# 示例)
csharp复制编辑// 简化例子:构造一个 WAV PCM 头部
public static void WriteWavHeader(Stream stream, int sampleRate, short bitsPerSample, short channels, int dataLength)
{
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.ASCII, true))
{
int byteRate = sampleRate * channels * bitsPerSample / 8;
short blockAlign = (short)(channels * bitsPerSample / 8);
writer.Write(Encoding.ASCII.GetBytes("RIFF"));
writer.Write(36 + dataLength); // ChunkSize
writer.Write(Encoding.ASCII.GetBytes("WAVE"));
writer.Write(Encoding.ASCII.GetBytes("fmt "));
writer.Write(16); // Subchunk1Size
writer.Write((short)1); // PCM format
writer.Write(channels);
writer.Write(sampleRate);
writer.Write(byteRate);
writer.Write(blockAlign);
writer.Write(bitsPerSample);
writer.Write(Encoding.ASCII.GetBytes("data"));
writer.Write(dataLength); // Subchunk2Size
}
}