📄 dsound_wrapper.c
字号:
return hr;
}
dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;
/* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */
return DS_OK;
}
/************************************************************************************/
HRESULT DSW_StartOutput( DSoundWrapper *dsw )
{
HRESULT hr;
QueryPerformanceCounter( &dsw->dsw_LastPlayTime );
dsw->dsw_LastPlayCursor = 0;
dsw->dsw_FramesPlayed = 0;
hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );
if( hr != DS_OK )
{
return hr;
}
// Start the buffer playback in a loop.
if( dsw->dsw_OutputBuffer != NULL )
{
hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );
if( hr != DS_OK )
{
return hr;
}
dsw->dsw_OutputRunning = TRUE;
}
return 0;
}
/************************************************************************************/
HRESULT DSW_StopOutput( DSoundWrapper *dsw )
{
// Stop the buffer playback
if( dsw->dsw_OutputBuffer != NULL )
{
dsw->dsw_OutputRunning = FALSE;
return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
}
else return 0;
}
/************************************************************************************/
HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )
{
HRESULT hr;
DWORD playCursor;
DWORD writeCursor;
long bytesFilled;
// Query to see where play position is.
// We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly
// so let's pass a pointer just to be safe.
hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
if( hr != DS_OK )
{
return hr;
}
bytesFilled = dsw->dsw_WriteOffset - playCursor;
if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset
*bytesFilledPtr = bytesFilled;
return hr;
}
/************************************************************************************
* Determine how much space can be safely written to in DS buffer.
* Detect underflows and overflows.
* Does not allow writing into safety gap maintained by DirectSound.
*/
HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )
{
HRESULT hr;
DWORD playCursor;
DWORD writeCursor;
long numBytesEmpty;
long playWriteGap;
// Query to see how much room is in buffer.
hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
if( hr != DS_OK )
{
return hr;
}
// Determine size of gap between playIndex and WriteIndex that we cannot write into.
playWriteGap = writeCursor - playCursor;
if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap
/* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */
/* Attempt to detect playCursor wrap-around and correct it. */
if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )
{
/* How much time has elapsed since last check. */
LARGE_INTEGER currentTime;
LARGE_INTEGER elapsedTime;
long bytesPlayed;
long bytesExpected;
long buffersWrapped;
QueryPerformanceCounter( ¤tTime );
elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;
dsw->dsw_LastPlayTime = currentTime;
/* How many bytes does DirectSound say have been played. */
bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;
if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap
dsw->dsw_LastPlayCursor = playCursor;
/* Calculate how many bytes we would have expected to been played by now. */
bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);
buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;
if( buffersWrapped > 0 )
{
playCursor += (buffersWrapped * dsw->dsw_OutputSize);
bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);
}
/* Maintain frame output cursor. */
dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);
}
numBytesEmpty = playCursor - dsw->dsw_WriteOffset;
if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset
/* Have we underflowed? */
if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )
{
if( dsw->dsw_OutputRunning )
{
dsw->dsw_OutputUnderflows += 1;
}
dsw->dsw_WriteOffset = writeCursor;
numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;
}
*bytesEmpty = numBytesEmpty;
return hr;
}
/************************************************************************************/
HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )
{
HRESULT hr;
LPBYTE lpbuf1 = NULL;
LPBYTE lpbuf2 = NULL;
DWORD dwsize1 = 0;
DWORD dwsize2 = 0;
long bytesEmpty;
hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed
if (hr != DS_OK) return hr;
if( bytesEmpty == 0 ) return DS_OK;
// Lock free space in the DS
hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,
(void **) &lpbuf2, &dwsize2, 0);
if (hr == DS_OK)
{
// Copy the buffer into the DS
ZeroMemory(lpbuf1, dwsize1);
if(lpbuf2 != NULL)
{
ZeroMemory(lpbuf2, dwsize2);
}
// Update our buffer offset and unlock sound buffer
dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;
}
return hr;
}
/************************************************************************************/
HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )
{
HRESULT hr;
LPBYTE lpbuf1 = NULL;
LPBYTE lpbuf2 = NULL;
DWORD dwsize1 = 0;
DWORD dwsize2 = 0;
// Lock free space in the DS
hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,
(void **) &lpbuf2, &dwsize2, 0);
if (hr == DS_OK)
{
// Copy the buffer into the DS
CopyMemory(lpbuf1, buf, dwsize1);
if(lpbuf2 != NULL)
{
CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
}
// Update our buffer offset and unlock sound buffer
dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;
}
return hr;
}
/************************************************************************************/
DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )
{
DWORD status;
if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)
return( DSERR_INVALIDPARAM );
else
return( status );
}
/* These routines are used to support audio input.
* Do NOT compile these calls when using NT4 because it does
* not support the entry points.
*/
/************************************************************************************/
HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
{
HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
if( hr != DS_OK ) return hr;
return hr;
}
/************************************************************************************/
HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
{
DSCBUFFERDESC captureDesc;
WAVEFORMATEX wfFormat;
HRESULT result;
dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);
// Define the buffer format
wfFormat.wFormatTag = WAVE_FORMAT_PCM;
wfFormat.nChannels = nChannels;
wfFormat.nSamplesPerSec = nFrameRate;
wfFormat.wBitsPerSample = 8 * sizeof(short);
wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
wfFormat.cbSize = 0; /* No extended format info. */
dsw->dsw_InputSize = bytesPerBuffer;
// ----------------------------------------------------------------------
// Setup the secondary buffer description
ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
captureDesc.dwSize = sizeof(DSCBUFFERDESC);
captureDesc.dwFlags = 0;
captureDesc.dwBufferBytes = bytesPerBuffer;
captureDesc.lpwfxFormat = &wfFormat;
// Create the capture buffer
if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,
&captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;
dsw->dsw_ReadOffset = 0; // reset last read position to start of buffer
return DS_OK;
}
/************************************************************************************/
HRESULT DSW_StartInput( DSoundWrapper *dsw )
{
// Start the buffer playback
if( dsw->dsw_InputBuffer != NULL )
{
return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );
}
else return 0;
}
/************************************************************************************/
HRESULT DSW_StopInput( DSoundWrapper *dsw )
{
// Stop the buffer playback
if( dsw->dsw_InputBuffer != NULL )
{
return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
}
else return 0;
}
/************************************************************************************/
HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
{
HRESULT hr;
DWORD capturePos;
DWORD readPos;
long filled;
// Query to see how much data is in buffer.
// We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
// so let's pass a pointer just to be safe.
hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
if( hr != DS_OK )
{
return hr;
}
filled = readPos - dsw->dsw_ReadOffset;
if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
*bytesFilled = filled;
return hr;
}
/************************************************************************************/
HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
{
HRESULT hr;
LPBYTE lpbuf1 = NULL;
LPBYTE lpbuf2 = NULL;
DWORD dwsize1 = 0;
DWORD dwsize2 = 0;
// Lock free space in the DS
hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
(void **) &lpbuf2, &dwsize2, 0);
if (hr == DS_OK)
{
// Copy from DS to the buffer
CopyMemory( buf, lpbuf1, dwsize1);
if(lpbuf2 != NULL)
{
CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
}
// Update our buffer offset and unlock sound buffer
dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
}
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -