在多媒体处理领域,音频文件的合并是一项常见需求。本文将介绍如何使用C++编写程序来合并多个WAV音频文件。本项目包括一个C++类,该类可以用来打开、读取和写入WAV音频文件。这个类是从AudioFile类派生的,并且混合功能使用了AudioFile接口。这样,未来添加其他音频格式(如FLAC和AIF)时,混合功能仍然可以工作。对于混合音频文件,源音频文件需要具有相同的采样率、比特率和相同数量的通道(单声道或立体声)。本项目不需要外部库。
本项目在Visual Studio 2017中构建(使用了免费的Community版本)。注意,构建项目需要在Visual Studio中安装C++工具集,以及MFC。代码使用了现代C++特性,如std::thread、lambda函数、std::shared_ptr以及现代的集合迭代方式。
源代码包括一个用于选择和混合WAV音频文件的GUI应用程序(使用MFC编写)。应用程序的截图如下所示:
要将WAV文件添加到列表中,可以将文件拖放到GUI上,或者对于列表中的每行,都有一个"..."按钮,允许浏览并选择要添加的WAV文件。
WAV音频文件由文件开头的头部组成,其中包含用于识别文件类型("RIFF"和"WAVE")的字符串,以及有关文件中包含的音频的信息(通道数、采样率、每个通道的位数、数据大小等)。头部之后是所有的音频数据。数字音频数据是数值型的:每个样本是一个整数,代表该时间点的音频信号级别。
数字音频混合的基本思想相当简单:直到没有更多的音频样本,读取每个音频文件的下一个音频样本,然后将它们相加并保存到输出文件中。然而,为了处理数字音频剪辑,需要做一些额外的工作。数字音频剪辑是由于样本大小(即8位或16位)的数值范围限制引起的:当音频样本值相加(或如果音量增加)时,结果值可能会超出值的数值范围。当这种情况发生时,结果是(通常是响亮的)噼啪声和点击声,这是不受欢迎的。因此,为了混合WAV文件,mixAudioFiles()(在AudioFileTools.h和.cpp中)将首先分析每个音频文件以确定最高的音频样本,然后在混合它们时降低所有样本的音量以避免数字音频剪辑。
AudioFile类是处理音频文件的父类,其中包含一些纯虚方法,需要在派生类中实现,如包括的WAVFile类。WAVFile类可以打开、读取和写入WAV音频。大多数类方法返回AudioFileResultType,可以像使用bool一样使用(例如,在'if'语句中),如果为false,则包含错误消息,形式为std::string。
C++
WAVFile audioFile("someAudioFile.wav");
AudioFileResultType result = audioFile.open(AUDIO_FILE_READ);
if (result) {
size_t numSamples = audioFile.numSamples();
for (size_t i = 0; (i < numSamples) && result; ++i) {
int16_t audioSample = 0;
result = audioFile.getNextSample(audioSample);
}
} else {
cerr << "Error(s) getting audio samples:" << endl;
result.outputErrors(cerr);
}
audioFile.close();