WASAPI Loopback:保存波形文件
WASAPI Loopback: Save wave file
我想使用 WASAPI 录制系统的音频输出,然后将其保存为 .wav 文件。
到目前为止,我在 WASAPI 上遵循了这些指南:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd316551%28v=vs.85%29.aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/dd370800%28v=vs.85%29.aspx
我使用
获取缓冲区数据
audioCaptureClient->GetBuffer(&data, &numFramesAvailable, &flags, NULL, NULL);
然后,我正在处理这些数据,只需将其写入 .wav 文件的末尾即可:
size_t dataSize = format.nChannels * (format.wBitsPerSample / 8) * numFramesAvailable;
fwrite(data, dataSize, 1, fp);
format
是从 audioClient->GetMixFormat(&format)
:
收到的 WAVEFORMATEX
cbSize: 22
nAvgBytesPerSec: 352800
nBlockAlign: 8
nChannels: 2
nSamplesPerSec: 44100
wBitsPerSample: 32
wFormatTag: 65534 (WAVE_FORMAT_EXTENSIBLE)
显然 WAVE_FORMAT_EXTENSIBLE
的子类型是 Float:
WAVEFORMATEXTENSIBLE *waveformatextensible = (WAVEFORMATEXTENSIBLE *)format;
if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, waveformatextensible->SubFormat)) { // true
在将所有捕获的数据写入文件之前,我填写了 headers(在 http://www.topherlee.com/software/pcm-tut-wavformat.html 之后):
UINT32 sizePlaceholder = 0;
UINT32 fmtLength = 16;
// RIFF Header
fputs("RIFF", fp); // offset 0 (0x00)
fwrite(&sizePlaceholder, 4, 1, fp); // offset 4 (0x04)
fputs("WAVE", fp); // offset 8 (0x08)
// fmt-Section
fputs("fmt ", fp); // offset 12 (0x0C)
fwrite(&fmtLength, 4, 1, fp); // offset 16 (0x10)
fwrite(&format.wFormatTag, 2, 1, fp); // offset 20 (0x14)
fwrite(&format.nChannels, 2, 1, fp); // offset 22 (0x16)
fwrite(&format.nSamplesPerSec, 4, 1, fp); // offset 24 (0x18)
fwrite(&format.nAvgBytesPerSec, 4, 1, fp); // offset 28 (0x1C)
fwrite(&format.nBlockAlign, 2, 1, fp); // offset 32 (0x20)
fwrite(&format.wBitsPerSample, 2, 1, fp); // offset 34 (0x22)
// Data-Section
fputs("data", fp); // offset 36 (0x24)
fwrite(&sizePlaceholder, 4, 1, fp); // offset 40 (0x28)
写完 3 秒的数据后,我使用 fwrite
.
填写文件大小和数据段大小的占位符
文件不可读。我怀疑它与 WAVE_FORMAT_EXTENSIBLE
有关,但我无法弄清楚。
我尝试覆盖 format
的几个元素,例如:
cbSize = 0;
wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
正在生成一个可读的 .wav 文件,但播放时会发出一些咔哒声(我尝试录制一首歌)。
wFormatTag = WAVE_FORMAT_PCM;
正在产生所有随机噪声。
所以,经过长时间的试验,我终于找到了解决方案。
代码存在多个问题。
WAVE_FORMAT_EXTENSIBLE
使用文件布局,有点不同。查看这个很棒的 link 了解更多详情。
- 我没有在
fopen
中设置二进制模式,所以音频数据损坏了,因为 fwrite
检测到数据中的换行符 (\n
) 并添加了一个回车符 return(\r
)。我不得不使用 fopen("foo.wav", "wb")
而不是 fopen("foo.wav", "w")
。
第二个问题,是决定性的原因,因为我已经尝试用 WAVE_FORMAT_IEEE_FLOAT
标签替换 WAVE_FORMAT_EXTENSIBLE
标签,这应该有效,因为不需要额外的信息要工作的 .wav 文件。
我想使用 WASAPI 录制系统的音频输出,然后将其保存为 .wav 文件。
到目前为止,我在 WASAPI 上遵循了这些指南:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd316551%28v=vs.85%29.aspx https://msdn.microsoft.com/en-us/library/windows/desktop/dd370800%28v=vs.85%29.aspx
我使用
获取缓冲区数据audioCaptureClient->GetBuffer(&data, &numFramesAvailable, &flags, NULL, NULL);
然后,我正在处理这些数据,只需将其写入 .wav 文件的末尾即可:
size_t dataSize = format.nChannels * (format.wBitsPerSample / 8) * numFramesAvailable;
fwrite(data, dataSize, 1, fp);
format
是从 audioClient->GetMixFormat(&format)
:
WAVEFORMATEX
cbSize: 22
nAvgBytesPerSec: 352800
nBlockAlign: 8
nChannels: 2
nSamplesPerSec: 44100
wBitsPerSample: 32
wFormatTag: 65534 (WAVE_FORMAT_EXTENSIBLE)
显然 WAVE_FORMAT_EXTENSIBLE
的子类型是 Float:
WAVEFORMATEXTENSIBLE *waveformatextensible = (WAVEFORMATEXTENSIBLE *)format;
if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, waveformatextensible->SubFormat)) { // true
在将所有捕获的数据写入文件之前,我填写了 headers(在 http://www.topherlee.com/software/pcm-tut-wavformat.html 之后):
UINT32 sizePlaceholder = 0;
UINT32 fmtLength = 16;
// RIFF Header
fputs("RIFF", fp); // offset 0 (0x00)
fwrite(&sizePlaceholder, 4, 1, fp); // offset 4 (0x04)
fputs("WAVE", fp); // offset 8 (0x08)
// fmt-Section
fputs("fmt ", fp); // offset 12 (0x0C)
fwrite(&fmtLength, 4, 1, fp); // offset 16 (0x10)
fwrite(&format.wFormatTag, 2, 1, fp); // offset 20 (0x14)
fwrite(&format.nChannels, 2, 1, fp); // offset 22 (0x16)
fwrite(&format.nSamplesPerSec, 4, 1, fp); // offset 24 (0x18)
fwrite(&format.nAvgBytesPerSec, 4, 1, fp); // offset 28 (0x1C)
fwrite(&format.nBlockAlign, 2, 1, fp); // offset 32 (0x20)
fwrite(&format.wBitsPerSample, 2, 1, fp); // offset 34 (0x22)
// Data-Section
fputs("data", fp); // offset 36 (0x24)
fwrite(&sizePlaceholder, 4, 1, fp); // offset 40 (0x28)
写完 3 秒的数据后,我使用 fwrite
.
文件不可读。我怀疑它与 WAVE_FORMAT_EXTENSIBLE
有关,但我无法弄清楚。
我尝试覆盖 format
的几个元素,例如:
cbSize = 0;
wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
正在生成一个可读的 .wav 文件,但播放时会发出一些咔哒声(我尝试录制一首歌)。
wFormatTag = WAVE_FORMAT_PCM;
正在产生所有随机噪声。
所以,经过长时间的试验,我终于找到了解决方案。
代码存在多个问题。
WAVE_FORMAT_EXTENSIBLE
使用文件布局,有点不同。查看这个很棒的 link 了解更多详情。- 我没有在
fopen
中设置二进制模式,所以音频数据损坏了,因为fwrite
检测到数据中的换行符 (\n
) 并添加了一个回车符 return(\r
)。我不得不使用fopen("foo.wav", "wb")
而不是fopen("foo.wav", "w")
。
第二个问题,是决定性的原因,因为我已经尝试用 WAVE_FORMAT_IEEE_FLOAT
标签替换 WAVE_FORMAT_EXTENSIBLE
标签,这应该有效,因为不需要额外的信息要工作的 .wav 文件。