wav文件本质是pcm数据加riff头,关键字段为subchunk2size(pcm总字节数)、chunksize(36+subchunk2size)、subchunk1size(固定16)及小端序的采样率/位深/声道数。

直接说结论:WAV 文件本质就是 PCM 数据加一个固定结构的 RIFF 头,手写头不难,但字节序、对齐、块大小算错一个就播不出。
WAV 文件头必须填对的 4 个关键字段
WAV 是 RIFF 容器格式,头里最易出错的是 Subchunk2Size、ChunkSize、Subchunk1Size 和采样率/位深/声道数的组合。它们不是独立填写的,而是强约束关系:
-
Subchunk2Size必须等于 PCM 数据总字节数(sample_count * channels * bits_per_sample / 8) -
ChunkSize= 36 +Subchunk2Size(因为 RIFF 头固定 8 字节 + fmt 子块 24 字节 + data 子块头 8 字节) -
Subchunk1Size固定为 16(PCM 格式),填 18 或 0 就被多数播放器拒识 - 所有多字节整数(如
SampleRate)必须用小端序(little-endian),C++ 写文件时别用std::cout 直接输出整数
用 fwrite 写 WAV 头的典型错误
常见现象是文件能生成、大小看起来合理,但 VLC 播放报“无法识别格式”或 Windows 媒体播放器静音——大概率是头里某字段没按小端写,或 ChunkSize 算少了 4。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 别用
int直接fwrite(&x, sizeof(int), 1, fp):int在不同平台可能是 4 或 8 字节,且不保证小端;改用uint32_t+ 手动拆字节或htole32()(Linux/macOS)或自写转换 -
fmt子块中AudioFormat字段必须是1(PCM),填0或65535会被当其他编码忽略 - 写完头后,必须用
fseek(fp, 4, SEEK_SET)回填ChunkSize,再fseek(fp, 40, SEEK_SET)回填Subchunk2Size;顺序错了会把数据覆盖成垃圾
16-bit PCM 单声道 vs 双声道的字节对齐陷阱
双声道数据不是“左+右交替写”就完事——每个样本必须严格按通道数对齐,否则播放器解包错位,声音发啸或变调。
- 单声道 16-bit:每个样本占 2 字节,
data[i]就是第 i 个样本 - 双声道 16-bit:每帧(frame)占 4 字节,结构是
[L0][L1][R0][R1],即左声道低字节、左声道高字节、右声道低字节、右声道高字节 - 如果误把双声道当成两个连续单声道数组写入,
Subchunk2Size仍对,但音频会完全失真——这问题不报错,只能靠听辨 - 写入前用
static_assert(sizeof(int16_t) == 2)确保位深匹配,别依赖sizeof(short)
真正麻烦的从来不是写头,而是确认 PCM 数据本身是否干净:有没有静音段填充、是否已做字节序翻转、是否混入了调试用的零值帧。这些错误不会让 WAV 头崩溃,但会让音频在第三台设备上突然无声。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










