Microsoft DirectX 8.0 (C++)

Writing to a Wave File

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.