为什么每次从磁盘读取音频文件时,这种双重缓冲方案都会产生可听见的点击声



下面的双缓冲方案似乎对我来说应该有效,但由于某种原因,每次for循环在顶部再次启动时都会听到咔嗒声。

这里有一个测试wav文件,你可以使用:https://github.com/JoshuaD84/jwaveform/blob/master/test4.wav,但该错误并不是特定于任何一个测试文件的。

#include <windows.h>
#include <mmsystem.h>
#include <iostream>
#include <fstream>
#include <bitset>
#pragma comment(lib, "winmm.lib")
HWAVEOUT hWaveOut = 0;
WAVEFORMATEX wfx;
int main() {
wfx = { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0 };
waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);

const int increment = 80000;
WAVEHDR* oldHeader = nullptr;
for (int k = 0; k < 50; k++) {
std::ifstream inStream;
inStream.open("test4.wav", std::ios::in | std::ios::binary);
char headerInfo[44]; //get past the wav header to the audio data
inStream.read(headerInfo, 44);
while (true) {
char* buffer = new char[increment];
inStream.read(buffer, increment);
DWORD bytesRead = inStream.gcount();
if (bytesRead <= 0) {
break;
} 
WAVEHDR* header = new WAVEHDR{ buffer, bytesRead, 0, 0, 0, 0, 0, 0 };
waveOutPrepareHeader(hWaveOut, header, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, header, sizeof(WAVEHDR));
if (oldHeader != nullptr) {
while (!(oldHeader->dwFlags & WHDR_DONE)) {
Sleep(1);
}
waveOutUnprepareHeader(hWaveOut, oldHeader, sizeof(oldHeader));
delete[] oldHeader->lpData;
delete oldHeader;
}
oldHeader = header;
}
}
}

我确信这是一件愚蠢的事情,但我已经修改了两个晚上,我不知道我在哪里犯了错误。

(为了方便起见:我可以在64位VS开发人员命令提示符下使用命令cl /EHsc test.cpp将其编译为单个文件(。

注:

  1. 我已经检查了文件,它以0开始和结束,所以剪辑不是由音频的形状引起的。

  2. 如果我从文件最后一个缓冲区的末尾修剪大约100个字节,我就不会得到剪辑。

  3. 如果我读取头subChunkSize字段,不管文件是什么,它都会报告数据字段比我能够读取的大312字节。

问题不在于双缓冲方案;没关系。

问题是,您假设音频文件的其余部分是有效的音频数据,但在该文件末尾的音频数据后面有垃圾数据。当你播放垃圾数据时,听起来像是点击。

为了避免点击,只读取Subchuk2Size中指定的字节数,如wav格式中指定的。

最新更新