PDA

View Full Version : Buffer size,duration and other parameters!!


Jack_thomas
03-31-2006, 02:55 PM
Hi I've got this code and I am trying to implement a thread with it.
Could someone tell me what are the sizes of the capture and playback buffers and their durations ? Are these parameters fixed or can be manipulated ?
What other parameters are being used in this code which can be manipulated ?
What is the rate at which samples are being played from output.

code:

HRESULT __fastcall TDSFilter::InitDirectSound()
{
HRESULT hr;
DSBUFFERDESC dsbdesc;

// ZeroMemory( &aPosNotify, sizeof(DSBPOSITIONNOTIFY) * FNumBuffers);
dwOutputBufferSize = 0;
dwCaptureBufferSize = 0;
dwNotifySize = 0;
dwNextOutputOffset = 0;

// Initialize COM
if( FAILED( hr = CoInitialize(NULL) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CoInitialize"), hr );

// Create IDirectSound using the preferred sound device
if( FAILED( hr = DirectSoundCreate8( NULL, &pDS, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCreate"), hr );

// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetCooperativeLevel"), hr );

// Obtain primary buffer
ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );

// Create IDirectSoundCapture using the preferred capture device
if( FAILED( hr = DirectSoundCaptureCreate8( NULL, &pDSCapture, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCaptureCreate"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::FreeDirectSound()
{
// Release DirectSound interfaces
SAFE_RELEASE( pDSNotify );

SAFE_RELEASE( pDSBPrimary );
SAFE_RELEASE( pDSBOutput );
SAFE_RELEASE( pDSBCapture );

SAFE_RELEASE( pDSCapture );
SAFE_RELEASE( pDS );

// Release COM
CoUninitialize();

return S_OK;
}
HRESULT __fastcall TDSFilter::ScanAvailableOutputFormats()
{
WAVEFORMATEX wfx;
WAVEFORMATEX wfxSet;
HRESULT hr;

ZeroMemory( &wfxSet, sizeof(wfxSet) );
wfxSet.wFormatTag = WAVE_FORMAT_PCM;

ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;

// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );

// To test if a playback format is supported, try to set the format
// using a specific format. If it works then the format is
// supported, otherwise not.
if( FAILED( hr = pDSBPrimary->SetFormat( &wfx ) ) )
{
abOutputFormatSupported[ iIndex ] = FALSE;
}
else
{
// Get the format that was just set, and see if it
// is actually supported since SetFormat() sometimes returns DS_OK
// even if the format was not supported
if( FAILED( hr = pDSBPrimary->GetFormat( &wfxSet, sizeof(wfxSet),
NULL ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("GetFormat"), hr );

if( memcmp( &wfx, &wfxSet, sizeof(wfx) ) == 0 )
abOutputFormatSupported[ iIndex ] = TRUE;
else
abOutputFormatSupported[ iIndex ] = FALSE;
}
}

return S_OK;
}
void __fastcall TDSFilter::GetWaveFormatFromIndex( INT nIndex, WAVEFORMATEX* pwfx )
{
INT iSampleRate = nIndex % 5;
INT iType = nIndex / 5;

switch( iSampleRate )
{
case 0: pwfx->nSamplesPerSec = 48000; break;
case 1: pwfx->nSamplesPerSec = 44100; break;
case 2: pwfx->nSamplesPerSec = 22050; break;
case 3: pwfx->nSamplesPerSec = 11025; break;
case 4: pwfx->nSamplesPerSec = 8000; break;
}

switch( iType )
{
case 0: pwfx->wBitsPerSample = 16; pwfx->nChannels = 2; break;
case 1: pwfx->wBitsPerSample = 16; pwfx->nChannels = 1; break;
case 2: pwfx->wBitsPerSample = 8; pwfx->nChannels = 2; break;
case 3: pwfx->wBitsPerSample = 8; pwfx->nChannels = 1; break;
}

pwfx->nBlockAlign = pwfx->nChannels * ( pwfx->wBitsPerSample / 8 );
pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
}
void __fastcall TDSFilter::ConvertWaveFormatToString( WAVEFORMATEX* pwfx, TCHAR* strFormatName)
{
wsprintf( strFormatName,
TEXT("%u Hz, %u-bit %s"),
pwfx->nSamplesPerSec,
pwfx->wBitsPerSample,
( pwfx->nChannels == 1 ) ? TEXT("Mono") : TEXT("Stereo") );
}
HRESULT __fastcall TDSFilter::ScanAvailableInputFormats()
{
WAVEFORMATEX wfx;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER pDSCaptureBuffer = NULL;

ZeroMemory( &wfx, sizeof(wfx) );
wfx.wFormatTag = WAVE_FORMAT_PCM;

ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);

// Try 20 different standard format to see if they are supported
for( INT iIndex = 0; iIndex < 20; iIndex++ )
{
GetWaveFormatFromIndex( iIndex, &wfx );

// To test if a capture format is supported, try to create a
// new capture buffer using a specific format. If it works
// then the format is supported, otherwise not.
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec;
dscbd.lpwfxFormat = &wfx;

if( FAILED( pDSCapture->CreateCaptureBuffer( &dscbd, &pDSCaptureBuffer, NULL ) ) ) abInputFormatSupported[ iIndex ] = FALSE;
else abInputFormatSupported[ iIndex ] = TRUE;
SAFE_RELEASE( pDSCaptureBuffer );
}
return S_OK;
}
HRESULT __fastcall TDSFilter::SetBufferFormats( WAVEFORMATEX* pwfxInput, WAVEFORMATEX* pwfxOutput )
{
HRESULT hr ;
// Set the format of the primary buffer
// to the format of the output buffer
if( FAILED( hr = pDSBPrimary->SetFormat( pwfxOutput ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("SetFormat"), hr );

// Set the notification size
dwNotifySize = FBufferSize ;
dwNotifySize -= dwNotifySize % pwfxInput->nBlockAlign;

// Set the buffer sizes
dwOutputBufferSize = FNumBuffers * dwNotifySize / 2;
dwCaptureBufferSize = dwNotifySize * FNumBuffers ;

SAFE_RELEASE( pDSBCapture );

// Create the capture buffer
DSCBUFFERDESC dscbd;
ZeroMemory( &dscbd, sizeof(dscbd) );
dscbd.dwSize = sizeof(dscbd);
dscbd.dwBufferBytes = dwCaptureBufferSize;
dscbd.lpwfxFormat = pwfxInput; // Set the format during creatation

if( FAILED( hr = pDSCapture->CreateCaptureBuffer( &dscbd, &pDSBCapture, NULL))) return DXTRACE_ERR_MSGBOX( TEXT("CreateCaptureBuffer"), hr );
return S_OK;
}
HRESULT __fastcall TDSFilter::CreateOutputBuffer()
{
HRESULT hr;
WAVEFORMATEX wfxInput;

// This sample works by creating notification events which
// are signaled when the capture buffer reachs specific offsets
// WinMain() waits for the associated event to be signaled, and
// when it is, it calls HandleNotifications() which copy the
// data from the capture buffer into the output buffer

ZeroMemory( &wfxInput, sizeof(wfxInput) );
pDSBCapture->GetFormat( &wfxInput, sizeof(wfxInput), NULL );

// Create the direct sound buffer using the same format as the
// capture buffer.
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_GLOBALFOCUS;
dsbd.dwBufferBytes = dwOutputBufferSize;
dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfxInput;

// Create the DirectSound buffer
if( FAILED( hr = pDS->CreateSoundBuffer( &dsbd, &pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("CreateSoundBuffer"), hr );

// Create a notification event, for when the sound stops playing
if( FAILED( hr = pDSBCapture->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("QueryInterface"), hr );

// Setup the notification positions
for( unsigned int i = 0; i < FNumBuffers ; i++ ) {
aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
aPosNotify[i].hEventNotify = hNotificationEvent;
}

// Tell DirectSound when to notify us. the notification will come in the from
// of signaled events that are handled in WinMain()
if( FAILED( hr = pDSNotify->SetNotificationPositions( FNumBuffers, aPosNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("SetNotificationPositions"), hr );

return S_OK;
}
HRESULT __fastcall TDSFilter::StartBuffers()
{
WAVEFORMATEX wfxOutput;
VOID* pDSLockedBuffer = NULL;
DWORD dwDSLockedBufferSize;
HRESULT hr;

// Restore lost buffers
if( FAILED( hr = RestoreBuffer( pDSBOutput, NULL ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("RestoreBuffer"), hr );

// Reset the buffers
dwNextOutputOffset = 0;
pDSBOutput->SetCurrentPosition( 0 );

// Find out where the capture buffer is right now, then write data
// some extra amount forward to make sure we're ahead of the write cursor
pDSBCapture->GetCurrentPosition( &dwNextCaptureOffset, NULL );
dwNextCaptureOffset -= dwNextCaptureOffset % dwNotifySize;

dwNextOutputOffset = dwNextCaptureOffset + ( dwNotifySize << 1);
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer

// Tell the capture buffer to start recording
pDSBCapture->Start( DSCBSTART_LOOPING );

// Rewind the output buffer, fill it with silence, and play it
pDSBOutput->SetCurrentPosition( dwNextOutputOffset );

// Save the format of the capture buffer in g_pCaptureWaveFormat
ZeroMemory( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX) );
pDSBCapture->GetFormat( &wfxCaptureWaveFormat, sizeof(WAVEFORMATEX), NULL );

// Get the format of the output buffer
ZeroMemory( &wfxOutput, sizeof(wfxOutput) );
pDSBOutput->GetFormat( &wfxOutput, sizeof(wfxOutput), NULL );

// Fill the output buffer with silence at first
// As capture data arrives, HandleNotifications() will fill
// the output buffer with wave data.
if( FAILED( hr = pDSBOutput->Lock( 0, dwOutputBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );

FillMemory( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize,
(BYTE)( wfxOutput.wBitsPerSample == 8 ? 128 : 0 ) );
pDSBOutput->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL );

// Play the output buffer
pDSBOutput->Play( 0, 0, DSBPLAY_LOOPING );

return S_OK;
}
HRESULT __fastcall TDSFilter::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSBuffer, BOOL* pbRestored )
{
HRESULT hr;

if( pbRestored) *pbRestored = FALSE;
if( !pDSBuffer ) return S_FALSE;

DWORD dwStatus;
if( FAILED( hr = pDSBuffer->GetStatus( &dwStatus ) ) ) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );

if( dwStatus & DSBSTATUS_BUFFERLOST ) {
// Since the app could have just been activated, then
// DirectSound may not be giving us control yet, so
// the restoring the buffer may fail.
// If it does, sleep until DirectSound gives us control.
do {
hr = pDSBuffer->Restore();
if( hr == DSERR_BUFFERLOST )
Sleep( 10 );
} while( ( hr = pDSBuffer->Restore() ) == DSERR_BUFFERLOST );

if( pbRestored) *pbRestored = TRUE;
return S_OK;
} else return S_FALSE;
}
HRESULT __fastcall TDSFilter::HandleNotification()
{
HRESULT hr;
VOID* pDSCaptureLockedBuffer = NULL;
VOID* pDSOutputLockedBuffer = NULL;
DWORD dwDSCaptureLockedBufferSize;
DWORD dwDSOutputLockedBufferSize;

DWORD dwStatus;

// Make sure buffers were not lost, if the were we need
// to start the capture again
if( FAILED( hr = pDSBOutput->GetStatus( &dwStatus))) return DXTRACE_ERR_MSGBOX( TEXT("GetStatus"), hr );

if( dwStatus & DSBSTATUS_BUFFERLOST ) {
if( FAILED( hr = StartBuffers())) return DXTRACE_ERR_MSGBOX( TEXT("StartBuffers"), hr );
return S_OK;
}

// Lock the capture buffer down
if( FAILED( hr = pDSBCapture->Lock( dwNextCaptureOffset, dwNotifySize, &pDSCaptureLockedBuffer,
&dwDSCaptureLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );

// Lock the output buffer down
if( FAILED( hr = pDSBOutput->Lock( dwNextOutputOffset, dwNotifySize, &pDSOutputLockedBuffer,
&dwDSOutputLockedBufferSize, NULL, NULL, 0L)))
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );

// These should be equal
if( dwDSOutputLockedBufferSize != dwDSCaptureLockedBufferSize ) return E_FAIL; // Sanity check unhandled case

// Just copy the memory from the
// capture buffer to the playback buffer
Process( (short*) pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize) ;
CopyMemory( pDSOutputLockedBuffer, pDSCaptureLockedBuffer, dwDSOutputLockedBufferSize );

// Unlock the play buffer
pDSBOutput->Unlock( pDSOutputLockedBuffer, dwDSOutputLockedBufferSize, NULL, 0 );

// Unlock the capture buffer
pDSBCapture->Unlock( pDSCaptureLockedBuffer, dwDSCaptureLockedBufferSize, NULL, 0 );

// Move the capture offset along
dwNextCaptureOffset += dwDSCaptureLockedBufferSize;
dwNextCaptureOffset %= dwCaptureBufferSize; // Circular buffer

// Move the playback offset along
dwNextOutputOffset += dwDSOutputLockedBufferSize;
dwNextOutputOffset %= dwOutputBufferSize; // Circular buffer

return S_OK;
}



I would really appreciate your help.

Thanks.

Reedbeta
03-31-2006, 06:01 PM
First, please use the [ code ] [ /code ] tags when you post source code in the forum, so it will be nicely formatted. I have added them for you this time. Second, you should read the comments in the code and if necessary look up some of the function calls in the MSDN to find the information you are looking for.