WAV文件为资源交换文件格式(RIFF),包括若干数量的命名块,其中包含头信息(如声音采样格式)或数据(如样本本身)。Win 32 API提供了打开关闭FIFF文件、查找块等函数。这些函数的名字都以“mmio”开头。
写入到WAV文件
WAV文件为资源交换文件格式(RIFF),包括若干数量的命名块,其中包含头信息(如声音采样格式)或数据(如样本本身)。Win 32 API提供了打开关闭FIFF文件、查找块等函数。这些函数的名字都以“mmio”开头。
DirectSound API 不包括写入WAV文件的方法。但是 DXUTsound.cpp 文件实现了一个 CWaveFile 类,这个类具有以下管理捕捉文件的方法:
·Open 方法。打开一个文件并且写入头部块。
·Write 方法。将数据从缓冲区写入到数据块中并且提高写指针。
·Close 方法。将数据块的大小写入到头部并且关闭文件。
写入到一个WAV文件的第一步是调用 CWaveFile::Open 方法。这样会创建一个文件并且写WAV格式块。参数为文件名,一个指向初始化后的WAVEFORMATEX 结构体的指针和 WAVEFILE_WRITE 标志。这个方法返回一个 HRESULT。
下面的代码为写入打开了一个WAV文件:

Code
CWaveFile g_pWaveFile;
WAVEFORMATEX wfxInput;
ZeroMemory( &wfxInput, sizeof(wfxInput));
wfxInput.wFormatTag = WAVE_FORMAT_PCM;
wfxInput.nSamplesPerSec = 22050
wfxInput.wBitsPerSample = 8;
wfxInput.nChannels = 1;
wfxInput.nBlockAlign =
wfxInput.nChannels * (wfxInput.wBitsPerSample / 8);
wfxInput.nAvgBytesPerSec =
wfxInput.nBlockAlign * wfxInput.nSamplesPerSec;
g_pWaveFile = new CWaveFile;
if (FAILED(g_pWaveFile->Open("mywave.wav", &wfxInput,
WAVEFILE_WRITE)))
{
g_pWaveFile->Close();
}
应用程序现在可以开始从捕捉缓冲区复制数据到这个文件了。
下面的示例函数将在每次读指针到达通知位置时被调用。在这个函数内,将使用如下全局变量:
·g_pDSBCapture 是一个指向缓冲区中的 IDirectSoundCaptureBuffer8 接口的指针。
·g_dwNextCaptureOffset 跟踪缓冲区中下一个将要被复制到文件的数据块的偏移量。
·g_dwCaptureBufferSize 表示缓冲区大小,被用在计算"环绕"。

Code
HRESULT RecordCapturedData()
{
HRESULT hr;
VOID* pbCaptureData = NULL;
DWORD dwCaptureLength;
VOID* pbCaptureData2 = NULL;
DWORD dwCaptureLength2;
VOID* pbPlayData = NULL;
UINT dwDataWrote;
DWORD dwReadPos;
LONG lLockSize;
if (NULL == g_pDSBCapture)
return S_FALSE;
if (NULL == g_pWaveFile)
return S_FALSE;
if (FAILED (hr = g_pDSBCapture->GetCurrentPosition(
NULL, &dwReadPos)))
return hr;
// Lock everything between the private cursor
// and the read cursor, allowing for wraparound.
lLockSize = dwReadPos - g_dwNextCaptureOffset;
if( lLockSize < 0 ) lLockSize += g_dwCaptureBufferSize;
if( lLockSize == 0 ) return S_FALSE;
if (FAILED(hr = g_pDSBCapture->Lock(
g_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L)))
return hr;
// Write the data. This is done in two steps
// to account for wraparound.
if (FAILED( hr = g_pWaveFile->Write( dwCaptureLength,
(BYTE*)pbCaptureData, &dwDataWrote)))
return hr;
if (pbCaptureData2 != NULL)
{
if (FAILED(hr = g_pWaveFile->Write(
dwCaptureLength2, (BYTE*)pbCaptureData2,
&dwDataWrote)))
return hr;
}
// Unlock the capture buffer.
g_pDSBCapture->Unlock( pbCaptureData, dwCaptureLength,
pbCaptureData2, dwCaptureLength2 );
// Move the capture offset forward.
g_dwNextCaptureOffset += dwCaptureLength;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize;
g_dwNextCaptureOffset += dwCaptureLength2;
g_dwNextCaptureOffset %= g_dwCaptureBufferSize;
return S_OK;
}
When capturing is finished, the application closes the WAV file.
g_pWaveFile->Close();
查看其它:
导 言
1.枚举“捕捉设备”
2.创建“捕捉设备对象”
3.“捕捉设备”性能
4.创建一个“捕捉缓冲区”
5.“捕捉缓冲区”信息
6.“捕捉缓冲区”通知
7. “捕捉缓冲区”特效
8.使用“捕捉缓冲区”
9.写入到WAV文件
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述