c++ audio音频处理 c++如何读取wav文件并处理音频数据

梦枫小哥_4434

梦枫小哥_4434

2026-03-31

787人浏览

原创

解析wav文件必须先跳过riff头和fmt子块定位到"data"chunk起始处,严格按waveformatex顺序读字段,校验wformattag,处理字节序与对齐,按声道拆分交错数据,并遍历所有chunk而非假设顺序。

c++ audio音频处理 c++如何读取wav文件并处理音频数据

WAV 文件头解析不校验直接读数据,必崩

WAV 是 RIFF 容器格式,不是纯 PCM;fread 从文件开头硬读音频样本,大概率读到的是 riff 头或 fmt 子块,导致数据错位、静音或崩溃。必须先跳过合法头结构,定位到 "data" chunk 起始位置。

实操建议:

  • 用 fread 读前 12 字节,检查是否为 "RIFF....WAVE"(注意字节序和 padding)
  • 读取 fmt 子块长度(4 字节),再跳过该长度,直到遇到 "data" 标识符
  • 紧接着的 4 字节是采样数据总字节数,之后才是真正的 int16_t 或 float32 样本
  • 别信文件扩展名——有些 .wav 实际是 IEEE float 格式,wFormatTag 字段必须检查,常见值:0x0001(PCM)、0x0003(IEEE float)

用 std::ifstream 读二进制 WAV,seekg 容易偏移错

WAV 的 chunk 对齐要求是 2 字节边界,但 fmt 块末尾可能有 pad byte;如果只按字段长度累加偏移,seekg 会落在 "data" 标识符中间,后续读出全乱码。

实操建议:

  • 每次读完一个 chunk 后,用 file.tellg() 记录当前位置,再读 chunk size,计算下一个 chunk 起始 = 当前位置 + 8(chunk header 长度)+ size
  • 读 fmt 块时,先读 2 字节 wFormatTag,再读 2 字节 nChannels,再读 4 字节 nSamplesPerSec……严格按 WAVEFORMATEX 定义顺序,别靠 sizeof(struct)
  • 遇到未知 chunk 类型(比如 "LIST" 或 "fact"),按 size 跳过,别假设只有 "fmt " 和 "data"

std::vector<int16_t></int16_t> 存 PCM 数据,但声道交错没拆开

绝大多数 WAV 是 interleaved:左声道第 0 样本、右声道第 0 样本、左声道第 1 样本……连续存放。如果直接把整块数据当单声道处理,做 FFT 或滤波就会出错。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

实操建议:

  • 读完 data chunk 后,根据 nChannels 和 wBitsPerSample 算出每帧字节数:bytes_per_frame = (wBitsPerSample / 8) * nChannels
  • 用 std::vector<:vector>></:vector> 按声道拆分:对每个样本索引 i,左声道取 data[i * nChannels + 0],右声道取 data[i * nChannels + 1]
  • 如果后续要做卷积或重采样,提前拆成单声道向量更安全;临时需要 interleave 再合并,别反复来回转换
  • 注意:wBitsPerSample == 24 时,不能直接 reinterpret_cast<int16_t></int16_t>,得手动提取 3 字节转 int32_t 再归一化

跨平台读 WAV 时,short 大小和字节序不一致

Windows 上 short 是 2 字节,Linux/macOS 也是,但某些嵌入式工具链或旧编译器可能不同;更关键的是 WAV 标准规定所有整数字段为 little-endian,而你的 CPU 可能是 big-endian(比如部分 ARM 设备)。

实操建议:

  • 所有从文件读出的多字节整数(uint32_t, uint16_t),必须用 le16toh() / le32toh() 转换(POSIX)或手写翻转逻辑
  • 别依赖 sizeof(short) == 2,显式用 int16_t 和 uint32_t,并确认头文件包含 <cstdint></cstdint>
  • 测试时找一个已知参数的 WAV(如 44.1kHz / 16-bit / stereo),用 ffprobe -v quiet -show_entries stream=sample_rate,channels,bits_per_sample test.wav 对照验证

事情说清了就结束。最常被忽略的是:WAV 不保证只有一个 "data" chunk,也不保证 "fmt " 在 "data" 前面——虽然几乎总是这样,但生产环境必须按规范遍历 chunk 链。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

2024.04.28

6507

8

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

2025.10.23

744

4

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.12.04

14520

5

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

1103

5

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

2025.06.11

8190

9

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.07

3242

7

css中的padding属性作用
css中的padding属性作用

在CSS中,padding属性用于设置元素的内边距。想了解更多padding的相关内容,可以阅读本专题下面的文章。

2023.12.07

2852

3

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.26

3239

3

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.07.27

2798

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习