下面的双缓冲方案似乎对我来说应该有效,但由于某种原因,每次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
将其编译为单个文件(。
注:
我已经检查了文件,它以0开始和结束,所以剪辑不是由音频的形状引起的。
如果我从文件最后一个缓冲区的末尾修剪大约100个字节,我就不会得到剪辑。
如果我读取头
subChunkSize
字段,不管文件是什么,它都会报告数据字段比我能够读取的大312字节。
问题不在于双缓冲方案;没关系。
问题是,您假设音频文件的其余部分是有效的音频数据,但在该文件末尾的音频数据后面有垃圾数据。当你播放垃圾数据时,听起来像是点击。
为了避免点击,只读取Subchuk2Size中指定的字节数,如wav格式中指定的。