news 2026/6/15 12:49:38

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/5/30 5:12:47

Qwen3-Embedding-0.6B开源优势解析:自主可控的嵌入模型部署选择

Qwen3-Embedding-0.6B开源优势解析&#xff1a;自主可控的嵌入模型部署选择 1. Qwen3-Embedding-0.6B 介绍 Qwen3 Embedding 模型系列是 Qwen 家族中专为文本嵌入与排序任务打造的新一代模型&#xff0c;基于强大的 Qwen3 系列密集基础模型构建。该系列提供多种参数规模&…

作者头像 李华
网站建设 2026/6/13 0:06:27

猫抓cat-catch资源嗅探浏览器扩展终极指南:从零开始掌握

猫抓cat-catch资源嗅探浏览器扩展终极指南&#xff1a;从零开始掌握 【免费下载链接】cat-catch 猫抓 chrome资源嗅探扩展 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 还在为网页上的精彩视频无法下载而烦恼吗&#xff1f;猫抓cat-catch这款开源浏览器…

作者头像 李华
网站建设 2026/6/15 12:37:41

升级你的大模型!Glyph让上下文长度翻倍提升

升级你的大模型&#xff01;Glyph让上下文长度翻倍提升 你有没有遇到过这样的问题&#xff1a;想让大模型读一篇超长报告、分析一整本电子书&#xff0c;或者处理一份几十页的合同&#xff0c;结果发现模型“记不住”前面的内容&#xff1f;传统大模型通常只能处理几千到几万t…

作者头像 李华
网站建设 2026/6/15 12:01:44

Z-Image-Turbo用于广告设计的真实案例分享

Z-Image-Turbo用于广告设计的真实案例分享 1. 引言&#xff1a;当广告创意遇上极速生成 你有没有遇到过这样的情况&#xff1f;客户临时要求出三版主图文案&#xff0c; deadline 是两小时后&#xff0c;而设计师还在手动调图、反复修改。传统设计流程中&#xff0c;从构思到…

作者头像 李华
网站建设 2026/6/15 12:02:35

中文心理咨询语料库实战指南:构建高效AI助手的创新方案

中文心理咨询语料库实战指南&#xff1a;构建高效AI助手的创新方案 【免费下载链接】efaqa-corpus-zh 项目地址: https://gitcode.com/gh_mirrors/ef/efaqa-corpus-zh 你是否曾为开发智能心理助手而苦恼&#xff1f;面对海量用户的心理咨询需求&#xff0c;却缺乏高质量…

作者头像 李华
网站建设 2026/6/10 12:25:39

YOLOSHOW:零基础玩转目标检测的终极图形界面工具

YOLOSHOW&#xff1a;零基础玩转目标检测的终极图形界面工具 【免费下载链接】YOLOSHOW YOLO SHOW - YOLOv10 / YOLOv9 / YOLOv8 / YOLOv7 / YOLOv5 / RTDETR GUI based on Pyside6 项目地址: https://gitcode.com/gh_mirrors/yo/YOLOSHOW 还在为复杂的YOLO命令行参数而…

作者头像 李华