news 2026/3/8 6:48:10

C++:写wav音频文件(附带源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++:写wav音频文件(附带源码)

一、项目背景详细介绍

在音频处理、信号处理、多媒体系统与科学计算领域中,WAV(Waveform Audio File Format)是一种极其基础却又非常重要的音频文件格式。

你几乎在所有以下领域中都会遇到 WAV 文件:

  • 数字信号处理(DSP)实验

  • 语音合成 / 语音识别

  • 声学仿真

  • 音频算法原型验证

  • 游戏音效生成

  • 科学可视化(将数据“听”出来)

与 MP3、AAC 等压缩格式不同,WAV 文件通常保存:

未压缩或轻度压缩的 PCM 音频数据

这使得 WAV 文件具有以下优点:

  • 格式简单

  • 无损

  • 易于直接写入

  • 适合教学与工程底层实现


1.1 为什么要“自己写 WAV 文件”

很多工程师第一次接触音频时,都会选择:

  • 第三方音频库(libsndfile、FFmpeg)

  • 高级接口(PortAudio、JUCE)

但在以下场景中,“手写 WAV 文件”是非常有价值甚至必要的

  1. 教学:理解音频数据的本质

  2. 调试:验证 DSP 算法输出是否正确

  3. 嵌入式:环境受限、无第三方库

  4. 数值仿真:将浮点结果直接转成声音

  5. 文件格式研究


1.2 WAV 文件的本质

WAV 文件本质上是:

一个遵循 RIFF(Resource Interchange File Format)规范的二进制文件

其内容由多个“块(Chunk)”组成,其中最重要的两个是:

  • fmt:音频格式描述

  • data:真正的音频采样数据


1.3 本文目标

本文将从零开始,系统讲解并实现:

一个不依赖任何第三方库、完全使用 C++ 标准库写入 WAV 音频文件的工程级实现

并确保:

  • 理论清楚

  • 代码严谨

  • 可直接用于实际项目


二、项目需求详细介绍

2.1 功能需求

实现一个 C++ 程序,支持:

  1. 创建标准 PCM WAV 文件

  2. 支持:

    • 单声道 / 多声道

    • 8-bit / 16-bit / 32-bit PCM(重点 16-bit)

  3. 正确写入:

    • WAV 头

    • 音频数据

  4. 可播放于常见播放器(VLC、Windows Media Player)


2.2 工程需求

  • 使用 C++17

  • 不依赖第三方库

  • 所有代码集中展示

  • 清晰、可扩展


2.3 教学需求

  • 清楚解释 WAV 文件结构

  • 解释二进制写入细节

  • 解释字节序(Little Endian)


三、相关技术详细介绍

3.1 RIFF 与 WAV 的关系

WAV 文件是 RIFF 规范的一种具体应用,其结构如下:

RIFF Chunk ├── "RIFF" ├── ChunkSize ├── "WAVE" ├── "fmt " Subchunk └── "data" Subchunk


3.2 WAV 头部结构(PCM)

3.2.1 RIFF Chunk

字段大小含义
ChunkID4"RIFF"
ChunkSize4文件大小 - 8
Format4"WAVE"

3.2.2 fmt 子块

字段大小含义
Subchunk1ID4"fmt "
Subchunk1Size4PCM = 16
AudioFormat2PCM = 1
NumChannels2声道数
SampleRate4采样率
ByteRate4每秒字节数
BlockAlign2帧大小
BitsPerSample2位深

3.2.3 data 子块

字段大小含义
Subchunk2ID4"data"
Subchunk2Size4音频数据字节数
DataNPCM 数据

3.3 PCM 音频数据说明

对于 16-bit PCM:

  • 每个采样点是一个int16_t

  • 数值范围:[-32768, 32767]

  • 小端字节序(Little Endian)


四、实现思路详细介绍

4.1 总体实现步骤

  1. 生成音频采样数据(如正弦波)

  2. 构造 WAV 头部字段

  3. 按小端序写入二进制文件

  4. 写入音频数据

  5. 关闭文件


4.2 设计原则

  • 使用std::ofstream二进制模式

  • 明确类型大小(uint32_t,int16_t

  • 不依赖平台字节序假设(WAV 固定小端)


4.3 可扩展性

  • 可扩展为多声道

  • 可扩展为浮点 WAV

  • 可封装为通用WavWriter


五、完整实现代码

/************************************************************ * File: wav_writer.cpp * Description: * Write a PCM WAV audio file using pure C++. * Standard: C++17 ************************************************************/ #include <iostream> #include <fstream> #include <vector> #include <cstdint> #include <cmath> /*********************** WAV Writer *************************/ class WavWriter { public: WavWriter( const std::string& filename, uint16_t channels, uint32_t sampleRate, uint16_t bitsPerSample ) : m_filename(filename), m_channels(channels), m_sampleRate(sampleRate), m_bitsPerSample(bitsPerSample) {} void write(const std::vector<int16_t>& samples) { std::ofstream ofs(m_filename, std::ios::binary); if (!ofs) { throw std::runtime_error("Failed to open output file"); } uint32_t dataSize = samples.size() * sizeof(int16_t); write_header(ofs, dataSize); ofs.write(reinterpret_cast<const char*>(samples.data()), dataSize); } private: std::string m_filename; uint16_t m_channels; uint32_t m_sampleRate; uint16_t m_bitsPerSample; void write_header(std::ofstream& ofs, uint32_t dataSize) { uint32_t byteRate = m_sampleRate * m_channels * m_bitsPerSample / 8; uint16_t blockAlign = m_channels * m_bitsPerSample / 8; uint32_t chunkSize = 36 + dataSize; // RIFF chunk ofs.write("RIFF", 4); write_uint32(ofs, chunkSize); ofs.write("WAVE", 4); // fmt subchunk ofs.write("fmt ", 4); write_uint32(ofs, 16); // PCM write_uint16(ofs, 1); // AudioFormat = PCM write_uint16(ofs, m_channels); write_uint32(ofs, m_sampleRate); write_uint32(ofs, byteRate); write_uint16(ofs, blockAlign); write_uint16(ofs, m_bitsPerSample); // data subchunk ofs.write("data", 4); write_uint32(ofs, dataSize); } void write_uint16(std::ofstream& ofs, uint16_t value) { ofs.put(static_cast<char>(value & 0xFF)); ofs.put(static_cast<char>((value >> 8) & 0xFF)); } void write_uint32(std::ofstream& ofs, uint32_t value) { ofs.put(static_cast<char>(value & 0xFF)); ofs.put(static_cast<char>((value >> 8) & 0xFF)); ofs.put(static_cast<char>((value >> 16) & 0xFF)); ofs.put(static_cast<char>((value >> 24) & 0xFF)); } }; /***************************** Main **************************/ int main() { const uint32_t sampleRate = 44100; const double frequency = 440.0; // A4 const double duration = 2.0; // seconds size_t totalSamples = static_cast<size_t>(sampleRate * duration); std::vector<int16_t> samples(totalSamples); for (size_t i = 0; i < totalSamples; ++i) { double t = static_cast<double>(i) / sampleRate; double value = std::sin(2.0 * M_PI * frequency * t); samples[i] = static_cast<int16_t>(value * 32767); } WavWriter writer("output.wav", 1, sampleRate, 16); writer.write(samples); std::cout << "WAV file written: output.wav\n"; return 0; }

六、代码详细解读(仅解读方法作用)

6.1WavWriter

  • 封装 WAV 文件写入逻辑

  • 隔离文件格式细节

  • 提供清晰的工程接口


6.2write_header

  • 构造 RIFF/WAV 头部

  • 正确计算所有尺寸字段

  • 确保播放器兼容性


6.3write_uint16 / write_uint32

  • 明确控制小端字节序

  • 避免平台差异问题


6.4main中的正弦波生成

  • 构造测试音频

  • 验证 WAV 文件正确性


七、项目详细总结

通过本项目,你已经完整掌握了:

  • WAV 文件的二进制结构

  • PCM 音频数据的工程表示

  • 小端序在音频文件中的重要性

  • 如何用纯 C++ 写入可播放的音频文件

这是:

DSP / 音频 / 科学计算工程师的必备底层技能


八、项目常见问题及解答(FAQ)

Q1:为什么播放器能直接播放?

因为 WAV 是未压缩 PCM,解码极其简单。


Q2:如何支持立体声?

将 samples 按 LRLR 顺序交错即可。


Q3:能写浮点 WAV 吗?

可以,需要 AudioFormat = 3(IEEE Float)。


九、扩展方向与性能优化

9.1 格式扩展

  • 24-bit PCM

  • IEEE float WAV

  • 多声道(5.1)


9.2 工程优化

  • 流式写入大文件

  • 内存映射(mmap)

  • 实时音频输出


9.3 教学扩展

  • WAV vs AIFF

  • WAV vs MP3

  • 数字音频采样理论

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/4 8:11:47

麦橘超然建筑可视化应用:室内设计效果图生成实战

麦橘超然建筑可视化应用&#xff1a;室内设计效果图生成实战 你有没有遇到过这样的情况&#xff1a;脑子里有个绝妙的室内设计想法&#xff0c;却因为不会画图、建模太慢&#xff0c;最后只能停留在想象中&#xff1f;现在&#xff0c;借助“麦橘超然”这个AI图像生成工具&…

作者头像 李华
网站建设 2026/3/5 3:45:42

精通RTL8812AU无线网卡驱动:从零到监控模式的深度实战指南

精通RTL8812AU无线网卡驱动&#xff1a;从零到监控模式的深度实战指南 【免费下载链接】rtl8812au RTL8812AU/21AU and RTL8814AU driver with monitor mode and frame injection 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8812au RTL8812AU无线网卡驱动是Linux系…

作者头像 李华
网站建设 2026/3/7 1:11:04

音频太长识别失败?科哥镜像处理限制说明

音频太长识别失败&#xff1f;科哥镜像处理限制说明 你有没有遇到过这样的情况&#xff1a;辛辛苦苦录了一段十几分钟的会议音频&#xff0c;满怀期待地上传到语音识别系统&#xff0c;结果点击“开始识别”后&#xff0c;界面直接报错&#xff0c;提示“音频过长”或“处理失…

作者头像 李华
网站建设 2026/3/5 13:52:03

Pyfa:5分钟掌握EVE Online舰船配置终极技巧

Pyfa&#xff1a;5分钟掌握EVE Online舰船配置终极技巧 【免费下载链接】Pyfa Python fitting assistant, cross-platform fitting tool for EVE Online 项目地址: https://gitcode.com/gh_mirrors/py/Pyfa Pyfa是一款专为EVE Online玩家设计的开源Python舰船配置助手&a…

作者头像 李华
网站建设 2026/3/4 8:53:11

小白必看!UI-TARS-desktop保姆级入门教程,轻松玩转AI助手

小白必看&#xff01;UI-TARS-desktop保姆级入门教程&#xff0c;轻松玩转AI助手 你是否想过&#xff0c;只需用自然语言就能让电脑自动完成打开浏览器、查找资料、操作文件甚至运行命令&#xff1f;现在&#xff0c;这一切不再是科幻。UI-TARS-desktop 正是一款能听懂你“说话…

作者头像 李华
网站建设 2026/3/4 7:07:21

学长亲荐2026TOP10AI论文软件:MBA开题报告神器测评

学长亲荐2026TOP10AI论文软件&#xff1a;MBA开题报告神器测评 2026年AI论文工具测评&#xff1a;为何值得一看&#xff1f; 随着人工智能技术的持续发展&#xff0c;越来越多的MBA学生和研究者开始依赖AI论文软件来提升写作效率与学术质量。然而&#xff0c;面对市场上琳琅满…

作者头像 李华