Step 7: Stream Data to the Wave File
In the first tutorial you saw how to identify the segment of the buffer that was safe to write to by checking the offset of the notification position. This technique would work equally well with the capture buffer in the present tutorial, but this time you'll do things a bit differently.
In the previous step you saw how the StreamToFile function was called in response to a notification event. Unlike the StreamToBuffer function in the previous tutorial, this function does not take the event index as a parameter.
BOOL StreamToFile(void)
{
DWORD dwReadPos;
DWORD dwNumBytes;
LPBYTE pbInput1, pbInput2;
DWORD cbInput1, cbInput2;
static DWORD dwMyReadCursor = 0;
UINT dwBytesWritten;
Note the static declaration of dwMyReadCursor. This is the offset of the next byte of data you want to read; in other words, the byte just beyond the last one read on the previous pass through this function.
The first thing the function does is find the current read position. Remember, this position marks the leading edge of the data that is safe to read. It is not necessarily the same as the notification position, because it has likely advanced since the event was signaled.
IDirectSoundCaptureBuffer_GetCurrentPosition(lpdscb,
NULL, &dwReadPos);
The function then subtracts your internal read cursor from the current read position (after allowing for wraparound) in order to determine how many bytes of new data are available:
if (dwReadPos < dwMyReadCursor)
dwReadPos += dscbDesc.dwBufferBytes;
dwNumBytes = dwReadPos - dwMyReadCursor;
You then lock the buffer and do the copy. Because the segment of data you've identified as available is not exactly demarcated by the notification positions at the beginning and midpoint of the buffer, the locked portion of the buffer might wrap around, in which case two separate copy operations are required:
if FAILED(IDirectSoundCaptureBuffer_Lock(lpdscb,
dwMyReadCursor, dwNumBytes,
(LPVOID *)&pbInput1, &cbInput1,
(LPVOID *)&pbInput2, &cbInput2, 0))
OutputDebugString("Capture lock failure");
else
{
if (WaveWriteFile(hmmio, cbInput1, pbInput1, &mmckinfoData,
&dwBytesWritten, &mmioinfo))
OutputDebugString("Failure writing data to file\n");
dwTotalBytesWritten += dwBytesWritten;
// Wraparound
if (pbInput2 != NULL)
{
if (WaveWriteFile(hmmio, cbInput2, pbInput2,
&mmckinfoData, &dwBytesWritten, &mmioinfo))
OutputDebugString("Failure writing data to file\n");
dwTotalBytesWritten += dwBytesWritten;
}
IDirectSoundCaptureBuffer_Unlock(lpdscb,
pbInput1, cbInput1,
pbInput2, cbInput2);
}
The WaveWriteFile function returns 0 if successful and also fills dwBytesWritten with the number of bytes actually copied to the file. This value is added to the cumulative total, which will be needed when the file is closed.
Finally, update the internal read cursor, compensating for wraparound, and return to the message loop:
dwMyReadCursor += dwNumBytes;
if (dwMyReadCursor >= dscbDesc.dwBufferBytes)
dwMyReadCursor -= dscbDesc.dwBufferBytes;
return TRUE;
} // end StreamToFile()