C++标准库实现WAV文件读写

在上一篇文章RIFF和WAVE音频文件格式中对WAV的文件格式做了介绍,本文将使用标准C++库实现对数据为PCM格式的WAV文件的读写操作,只使用标准C++库函数,不依赖于其他的库。

WAV文件结构

WAV是符合RIFF标准的多媒体文件,其文件结构可以如下:

WAV 文件结构
RIFF块
WAVE FOURCC
fmt 块
fact 块(可选)
data块(包含PCM数据)

首先是一个RIFF块,有块标识RIFF,指明该文件是符合RIFF标准的文件;接着是一个FourCC,WAVE,该文件为WAV文件;fmt块包含了音频的一些属性:采样率、码率、声道等;fact 块是一个可选块,不是PCM数据格式的需要该块;最后data块,则包含了音频的PCM数据。实际上,可以将一个WAV文件看着由两部分组成:文件头和PCM数据,则WAV文件头各字段的意义如下:
这里写图片描述

本文实现的是一个能够读取PCM数据格式的单声道或者双声道的WAV文件,是没有fact块以及扩展块。

结构体定义

通过上面的介绍发现,WAV的头文件所包含的内容有两种:RIFF文件格式标准中需要的数据和关于音频格式的信息。对于RIFF文件格式所需的信息,声明结构体如下:

// The basic chunk of RIFF file format
struct Base_chunk{

    FOURCC fcc;    // FourCC id
    uint32_t cb_size; // 数据域的大小

    Base_chunk(FOURCC fourcc)
        : fcc(fourcc)
    {
        cb_size = 0;
    }
};

chunk是RIFF文件的基本单元,首先一个4字节的标识FOURCC,用来指出该块的类型;cb_size则是改块数据域中数据的大小。

文件头中另一个信息则是音频的格式信息,实际上是frm chunk的数据域信息,其声明如下:

// Format chunk data field
struct Wave_format{

    uint16_t format_tag;      // WAVE的数据格式,PCM数据该值为1
    uint16_t channels;        // 声道数
    uint32_t sample_per_sec;  // 采样率
    uint32_t bytes_per_sec;   // 码率,channels * sample_per_sec * bits_per_sample / 8
    uint16_t block_align;     // 音频数据块,每次采样处理的数据大小,channels * bits_per_sample / 8
    uint16_t bits_per_sample; // 量化位数,8、16、32等
    uint16_t ex_size;         // 扩展块的大小,附加块的大小

    Wave_format()
    {
        format_tag      = 1; // PCM format data
        ex_size         = 0; <
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,下面是使用标准C++实现WAV音频文件读写的示例: ```c++ #include <iostream> #include <fstream> using namespace std; // WAV文件头信息结构体 struct WAVHeader { char riff[4]; // "RIFF" int fileSize; // 文件总大小 char wave[4]; // "WAVE" char fmt[4]; // "fmt " int fmtSize; // fmt块大小 short audioFormat; // 音频格式 short numChannels; // 声道数 int sampleRate; // 采样率 int byteRate; // 码率 short blockAlign; // 区块对齐 short bitsPerSample; // 每个样本的位数 char data[4]; // "data" int dataSize; // 数据大小 }; int main() { // 读取WAV文件 ifstream fin("test.wav", ios::binary); if (!fin) { cout << "打开文件失败!" << endl; return 1; } WAVHeader header; fin.read((char*)&header, sizeof(header)); if (strncmp(header.riff, "RIFF", 4) != 0 || strncmp(header.wave, "WAVE", 4) != 0 || strncmp(header.fmt, "fmt ", 4) != 0 || strncmp(header.data, "data", 4) != 0) { cout << "不是有效的WAV文件!" << endl; return 1; } cout << "音频格式:" << header.audioFormat << endl; cout << "声道数:" << header.numChannels << endl; cout << "采样率:" << header.sampleRate << endl; cout << "码率:" << header.byteRate << endl; cout << "每个样本的位数:" << header.bitsPerSample << endl; cout << "数据大小:" << header.dataSize << endl; // 读取音频数据 char* data = new char[header.dataSize]; fin.read(data, header.dataSize); fin.close(); // 写入WAV文件 ofstream fout("output.wav", ios::binary); if (!fout) { cout << "创建文件失败!" << endl; return 1; } fout.write((char*)&header, sizeof(header)); fout.write(data, header.dataSize); fout.close(); delete[] data; return 0; } ``` 这个示例使用了标准C++库中的ifstream和ofstream类读写文件,并使用WAVHeader结构体来存储WAV文件头信息。通过读取WAV文件头信息,可以获取音频格式、声道数、采样率、码率、每个样本的位数和数据大小等信息,然后读取音频数据并写入新的WAV文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值