Microsoft DirectX 8.0 (C++) |
The DirectSound API does not include methods for writing to wave files. However, the Dsutil.cpp file used by many of the SDK sample applications implements a CWaveFile class that has the following public methods:
The first step in writing a wave file is to call the CWaveFile::Open method. This creates the file and writes the wave format chunk. The parameters are the filename, a pointer to an initialized WAVEFORMATEX structure, and the WAVEFILE_WRITE flag. The method returns an HRESULT.
The following code opens a wave file for writing:
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(); }
The application can now begin copying data from the capture buffer to the file. The following function is called each time the read cursor reaches a notification position. The following global variables are used:
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 our 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 along. 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 wave file.
g_pWaveFile->Close();
The CWaveFile::Close method writes the chunk sizes to the file before closing it.