Jump to content
  • Advertisement
Sign in to follow this  
Jack Thomas

Buffer size and other Parameters!

This topic is 4617 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi , I don't know whether I should post this query in this forum or general programming so I apologize for duplicating it. 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 input and output buffer 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.
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.dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
        aPosNotify.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 someone helping me out. Thanks. EDIT: Please use 'source' tags around longer listings of code - makes it much easier for people to read... [Edited by - jollyjeffers on March 31, 2006 1:44:39 PM]

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!