DirectSound API 本身不提供 WAV 檔案寫入功能,但 DXUT 提供的 CWaveFile 類封裝了 RIFF/WAV 格式操作,支援標準 PCM 音訊檔案建立。
fmt (格式資訊)、data(音訊樣本)mmio* 系列函式操作 RIFF 檔案| 方法 | 功能 |
|---|---|
Open(filename, &wfx, WAVEFILE_WRITE) | 建立檔案並寫入 fmt 區塊 |
Write(byte_count, buffer, &written) | 將緩衝區資料寫入 data 區塊 |
Close() | 更新 data 區塊大小至檔頭並關閉檔案 |
CWaveFile* g_pWaveFile = new CWaveFile();
WAVEFORMATEX wfx = {};
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = 22050;
wfx.wBitsPerSample = 8;
wfx.nChannels = 1;
wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8);
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
if (FAILED(g_pWaveFile->Open(L"capture.wav", &wfx, WAVEFILE_WRITE))) {
g_pWaveFile->Close();
delete g_pWaveFile;
return E_FAIL;
}
HRESULT RecordCapturedData() {
HRESULT hr;
BYTE* pbData1 = nullptr; DWORD dwLen1;
BYTE* pbData2 = nullptr; DWORD dwLen2;
DWORD dwReadPos;
LONG lLockSize;
// 1. 取得目前讀取位置
if (FAILED(hr = g_pDSBCapture->GetCurrentPosition(nullptr, &dwReadPos)))
return hr;
// 2. 計算可安全讀取的資料長度(避開寫入游標)
lLockSize = dwReadPos - g_dwNextCaptureOffset;
if (lLockSize < 0) lLockSize += g_dwCaptureBufferSize;
if (lLockSize == 0) return S_FALSE;
// 3. 鎖定捕捉緩衝區(可能跨越緩衝區邊界產生兩段)
if (FAILED(hr = g_pDSBCapture->Lock(g_dwNextCaptureOffset, lLockSize,
&pbData1, &dwLen1, &pbData2, &dwLen2, 0)))
return hr;
// 4. 寫入 WAV 檔案(分兩段處理環繞)
DWORD dwWritten;
if (FAILED(hr = g_pWaveFile->Write(dwLen1, pbData1, &dwWritten))) return hr;
if (pbData2 && FAILED(hr = g_pWaveFile->Write(dwLen2, pbData2, &dwWritten))) return hr;
// 5. 解鎖並更新下次讀取位移
g_pDSBCapture->Unlock(pbData1, dwLen1, pbData2, dwLen2);
g_dwNextCaptureOffset = (g_dwNextCaptureOffset + dwLen1 + dwLen2) % g_dwCaptureBufferSize;
return S_OK;
}
Lock 返回兩段指標dwReadPos) 標示安全讀取上限,避免覆蓋未讀資料g_dwNextCaptureOffset 記錄下次讀取起始位置g_pWaveFile->Close(); // 寫入 data chunk 大小、更新 RIFF header、關閉檔案
delete g_pWaveFile;