From 8d77d11ff92406290ed7ded06aae55056c6ae267 Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Fri, 31 Oct 2008 20:27:55 +0000 Subject: [PATCH] some fixes for selecting different ASIO soundcards --- linux/sound.cpp | 70 ++++---- linux/sound.h | 58 ++++--- src/client.cpp | 13 +- src/clientsettingsdlg.cpp | 3 +- src/main.cpp | 5 + windows/sound.cpp | 347 +++++++++++++++++++++----------------- windows/sound.h | 15 +- 7 files changed, 275 insertions(+), 236 deletions(-) diff --git a/linux/sound.cpp b/linux/sound.cpp index 043eae00..59456a31 100755 --- a/linux/sound.cpp +++ b/linux/sound.cpp @@ -13,13 +13,10 @@ #ifdef WITH_SOUND /* Wave in ********************************************************************/ -void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking) +void CSound::InitRecording ( const bool bNewBlocking ) { int err; - /* set internal buffer size for read */ - iBufferSizeIn = iNewBufferSize / NUM_IN_OUT_CHANNELS; /* mono size */ - /* if recording device was already open, close it first */ if ( rhandle != NULL ) { @@ -112,12 +109,12 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking) qDebug ( "alsa init record done" ); } -bool CSound::Read(CVector& psData) +bool CSound::Read ( CVector& psData ) { int ret; /* Check if device must be opened or reinitialized */ - if (bChangParamIn == true) + if ( bChangParamIn == true ) { InitRecording ( iBufferSizeIn * NUM_IN_OUT_CHANNELS ); @@ -125,7 +122,7 @@ bool CSound::Read(CVector& psData) bChangParamIn = false; } - ret = snd_pcm_readi(rhandle, &psData[0], iBufferSizeIn); + ret = snd_pcm_readi ( rhandle, &psData[0], iBufferSizeIn ); if ( ret < 0 ) { @@ -143,7 +140,7 @@ bool CSound::Read(CVector& psData) ret = snd_pcm_start ( rhandle ); - if (ret < 0) + if ( ret < 0 ) { qDebug ( "Can't recover from underrun, start failed: %s", snd_strerror ( ret ) ); } @@ -204,13 +201,10 @@ void CSound::SetInNumBuf ( int iNewNum ) /* Wave out *******************************************************************/ -void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking ) +void CSound::InitPlayback ( const bool bNewBlocking ) { int err; - // save buffer size - iBufferSizeOut = iNewBufferSize / NUM_IN_OUT_CHANNELS; // mono size - // if playback device was already open, close it first if ( phandle != NULL ) { @@ -219,7 +213,7 @@ void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking ) // playback device (either "hw:0,0" or "plughw:0,0") if ( err = snd_pcm_open ( &phandle, "hw:0,0", - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) != 0) + SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) != 0 ) { qDebug ( "open error: %s", snd_strerror ( err ) ); } @@ -241,16 +235,16 @@ void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking ) bool CSound::Write ( CVector& psData ) { - int size = iBufferSizeOut; + int size = iBufferSizeOut; int start = 0; int ret; - /* Check if device must be opened or reinitialized */ + // check if device must be opened or reinitialized if ( bChangParamOut == true ) { InitPlayback ( iBufferSizeOut * NUM_IN_OUT_CHANNELS ); - /* Reset flag */ + // reset flag bChangParamOut = false; } @@ -262,7 +256,7 @@ bool CSound::Write ( CVector& psData ) { if ( ret == -EPIPE ) { - /* under-run */ + // under-run qDebug ( "wunderrun" ); ret = snd_pcm_prepare ( phandle ); @@ -286,7 +280,7 @@ bool CSound::Write ( CVector& psData ) { qDebug("wstrpipe"); - /* wait until the suspend flag is released */ + // wait until the suspend flag is released while ( (ret = snd_pcm_resume ( phandle ) ) == -EAGAIN ) { sleep(1); @@ -317,29 +311,29 @@ bool CSound::Write ( CVector& psData ) return false; } -void CSound::SetOutNumBuf(int iNewNum) +void CSound::SetOutNumBuf ( int iNewNum ) { - /* check new parameter */ + // check new parameter if ( ( iNewNum >= MAX_SND_BUF_OUT ) || ( iNewNum < 1 ) ) { iNewNum = NUM_PERIOD_BLOCKS_OUT; } - /* Change only if parameter is different */ + // change only if parameter is different if ( iNewNum != iCurPeriodSizeOut ) { iCurPeriodSizeOut = iNewNum; - bChangParamOut = true; + bChangParamOut = true; } } /* common **********************************************************************/ -bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn, - const int iNumPeriodBlocks) +bool CSound::SetHWParams ( snd_pcm_t* handle, const int iBufferSizeIn, + const int iNumPeriodBlocks ) { - int err; - snd_pcm_hw_params_t* hwparams; + int err; + snd_pcm_hw_params_t* hwparams; // allocate an invalid snd_pcm_hw_params_t using standard malloc if ( err = snd_pcm_hw_params_malloc ( &hwparams ) < 0 ) @@ -417,31 +411,31 @@ bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn, } -/* check period and buffer size */ +// check period and buffer size snd_pcm_uframes_t buffer_size; -if (err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0) { - qDebug("Unable to get buffer size for playback: %s\n", snd_strerror(err)); +if ( err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size ) < 0 ) { + qDebug ( "Unable to get buffer size for playback: %s\n", snd_strerror ( err ) ); } -qDebug("buffer size: %d (desired: %d)", buffer_size, iBufferSizeIn * iNumPeriodBlocks); +qDebug ( "buffer size: %d (desired: %d)", buffer_size, iBufferSizeIn * iNumPeriodBlocks ); snd_pcm_uframes_t period_size; -err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0); -if (err < 0) +err = snd_pcm_hw_params_get_period_size ( hwparams, &period_size, 0 ); +if ( err < 0 ) { - qDebug("Unable to get period size for playback: %s\n", snd_strerror(err)); + qDebug ( "Unable to get period size for playback: %s\n", snd_strerror ( err ) ); } -qDebug("frame size: %d (desired: %d)", period_size, iBufferSizeIn); +qDebug ( "frame size: %d (desired: %d)", period_size, iBufferSizeIn ); - /* clean-up */ + // clean-up snd_pcm_hw_params_free ( hwparams ); return false; } -void CSound::Close () +void CSound::Close() { - /* read */ + // read if ( rhandle != NULL ) { snd_pcm_close ( rhandle ); @@ -449,7 +443,7 @@ void CSound::Close () rhandle = NULL; - /* playback */ + // playback if ( phandle != NULL ) { snd_pcm_close ( phandle ); diff --git a/linux/sound.h b/linux/sound.h index afc91971..5225e5ca 100755 --- a/linux/sound.h +++ b/linux/sound.h @@ -31,9 +31,9 @@ /* Definitions ****************************************************************/ -#define NUM_IN_OUT_CHANNELS 2 /* always stereo */ +#define NUM_IN_OUT_CHANNELS 2 // always stereo -/* the number of periods is critical for latency */ +// the number of periods is critical for latency #define NUM_PERIOD_BLOCKS_IN 2 #define NUM_PERIOD_BLOCKS_OUT 2 @@ -44,14 +44,18 @@ class CSound { public: - CSound() + CSound ( const int iNewBufferSizeStereo ) #if WITH_SOUND - : rhandle(NULL), phandle(NULL), iCurPeriodSizeIn(NUM_PERIOD_BLOCKS_IN), - iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT), bChangParamIn(true), - bChangParamOut(true) + : rhandle ( NULL ), phandle ( NULL ), iCurPeriodSizeIn ( NUM_PERIOD_BLOCKS_IN ), + iCurPeriodSizeOut ( NUM_PERIOD_BLOCKS_OUT ), bChangParamIn ( true ), + bChangParamOut ( true ) #endif - {} - virtual ~CSound() {Close();} + { + // set internal buffer size for read and write + iBufferSizeIn = iNewBufferSizeStereo / NUM_IN_OUT_CHANNELS; // mono size + iBufferSizeOut = iNewBufferSizeStereo / NUM_IN_OUT_CHANNELS; // mono size + } + virtual ~CSound() { Close(); } // not implemented yet, always return one device and default string int GetNumDev() { return 1; } @@ -60,14 +64,14 @@ public: int GetDev() { return 0; } #if WITH_SOUND - void SetInNumBuf(int iNewNum); - int GetInNumBuf() {return iCurPeriodSizeIn;} - void SetOutNumBuf(int iNewNum); - int GetOutNumBuf() {return iCurPeriodSizeOut;} - void InitRecording(int iNewBufferSize, bool bNewBlocking = true); - void InitPlayback(int iNewBufferSize, bool bNewBlocking = false); - bool Read(CVector& psData); - bool Write(CVector& psData); + void SetInNumBuf ( int iNewNum ); + int GetInNumBuf() { return iCurPeriodSizeIn; } + void SetOutNumBuf ( int iNewNum ); + int GetOutNumBuf() { return iCurPeriodSizeOut; } + void InitRecording ( const bool bNewBlocking = true ); + void InitPlayback ( const bool bNewBlocking = false ); + bool Read ( CVector& psData ); + bool Write ( CVector& psData ); void Close(); @@ -75,8 +79,8 @@ protected: snd_pcm_t* rhandle; snd_pcm_t* phandle; - bool SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn, - const int iNumPeriodBlocks); + bool SetHWParams ( snd_pcm_t* handle, const int iBufferSizeIn, + const int iNumPeriodBlocks ); int iBufferSizeOut; int iBufferSizeIn; @@ -85,15 +89,15 @@ protected: bool bChangParamOut; int iCurPeriodSizeOut; #else - /* Dummy definitions */ - void SetInNumBuf(int iNewNum) {} - int GetInNumBuf() {return 1;} - void SetOutNumBuf(int iNewNum) {} - int GetOutNumBuf() {return 1;} - void InitRecording(int iNewBufferSize, bool bNewBlocking = true) {printf("no sound!");} - void InitPlayback(int iNewBufferSize, bool bNewBlocking = false) {printf("no sound!");} - bool Read(CVector& psData) {printf("no sound!"); return false;} - bool Write(CVector& psData) {printf("no sound!"); return false;} + // dummy definitions + void SetInNumBuf ( int iNewNum ) {} + int GetInNumBuf() { return 1; } + void SetOutNumBuf ( int iNewNum ) {} + int GetOutNumBuf() { return 1; } + void InitRecording ( const bool bNewBlocking = true ) { printf ( "no sound!" ); } + void InitPlayback ( const bool bNewBlocking = false ) { printf ( "no sound!" ); } + bool Read ( CVector& psData ) { printf ( "no sound!" ); return false; } + bool Write ( CVector& psData ) { printf ( "no sound!" ); return false; } void Close() {} #endif }; diff --git a/src/client.cpp b/src/client.cpp index ba300814..cb5a4a49 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -27,6 +27,8 @@ /* Implementation *************************************************************/ CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ), + iSndCrdBlockSizeSam ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES ), + Sound ( MIN_SND_CRD_BLOCK_SIZE_SAMPLES * 2 /* stereo */ ), Socket ( &Channel, iPortNumber ), iAudioInFader ( AUD_FADER_IN_MAX / 2 ), iReverbLevel ( AUD_REVERB_MAX / 6 ), @@ -168,9 +170,8 @@ void CClient::OnProtocolStatus ( bool bOk ) void CClient::Init() { - // set block sizes (in samples) - iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES; - iSndCrdBlockSizeSam = MIN_SND_CRD_BLOCK_SIZE_SAMPLES; + // set block size (in samples) + iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES; vecsAudioSndCrd.Init ( iSndCrdBlockSizeSam * 2 ); // stereo vecdAudioSndCrdL.Init ( iSndCrdBlockSizeSam ); @@ -179,8 +180,8 @@ void CClient::Init() vecdAudioL.Init ( iBlockSizeSam ); vecdAudioR.Init ( iBlockSizeSam ); - Sound.InitRecording ( iSndCrdBlockSizeSam * 2 ); // stereo - Sound.InitPlayback ( iSndCrdBlockSizeSam * 2 ); // stereo + Sound.InitRecording(); + Sound.InitPlayback(); // resample objects are always initialized with the input block size // record @@ -325,7 +326,7 @@ void CClient::run() // send it through the network Socket.SendPacket ( Channel.PrepSendPacket ( vecsNetwork ), - Channel.GetAddress () ); + Channel.GetAddress() ); // receive a new block if ( Channel.GetData ( vecdNetwData ) == GS_BUFFER_OK ) diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index e945fa8f..89c6249b 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -250,7 +250,8 @@ void CClientSettingsDlg::OnSoundCrdSelection ( int iSndDevIdx ) { QMessageBox::critical ( 0, APP_NAME, QString ( "The selected audio device could not be used because " - "of the following error: " ) + generr.GetErrorText(), "Ok", 0 ); + "of the following error: " ) + generr.GetErrorText() + + QString ( " The previous driver will be selected." ), "Ok", 0 ); // recover old selection cbSoundcard->setCurrentIndex ( pClient->GetSndInterface()->GetDev() ); diff --git a/src/main.cpp b/src/main.cpp index e0648d6a..3eb91a2d 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -138,6 +138,11 @@ int main ( int argc, char** argv ) exit ( 1 ); } +#ifdef _WIN32 + // Set application priority class -> high priority + SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS ); +#endif + // Application object QApplication app ( argc, argv, bUseGUI ); diff --git a/windows/sound.cpp b/windows/sound.cpp index 90ded758..ac5b5ec5 100755 --- a/windows/sound.cpp +++ b/windows/sound.cpp @@ -87,8 +87,8 @@ bool CSound::Read ( CVector& psData ) // check if device must be opened or reinitialized if ( bChangParamIn ) { - // reinit sound interface (init recording requires stereo buffer size) - InitRecordingAndPlayback ( iBufferSizeStereo ); + // reinit sound interface + InitRecordingAndPlayback(); // reset flag bChangParamIn = false; @@ -188,8 +188,8 @@ bool CSound::Write ( CVector& psData ) // check if device must be opened or reinitialized if ( bChangParamOut ) { - // reinit sound interface (init recording requires stereo buffer size) - InitRecordingAndPlayback ( iBufferSizeStereo ); + // reinit sound interface + InitRecordingAndPlayback(); // reset flag bChangParamOut = false; @@ -256,6 +256,9 @@ void CSound::SetDev ( const int iNewDev ) { // a device was already been initialized and is used, kill working // thread and clean up + // stop driver + ASIOStop(); + // set event to ensure that thread leaves the waiting function if ( m_ASIOEvent != NULL ) { @@ -265,8 +268,7 @@ void CSound::SetDev ( const int iNewDev ) // wait for the thread to terminate Sleep ( 500 ); - // stop audio and dispose ASIO buffers - ASIOStop(); + // dispose ASIO buffers ASIODisposeBuffers(); // remove old driver @@ -280,9 +282,11 @@ void CSound::SetDev ( const int iNewDev ) // loading and initializing the new driver failed, go back to original // driver and display error message LoadAndInitializeDriver ( lCurDev ); + InitRecordingAndPlayback(); throw CGenErr ( strErrorMessage.c_str() ); } + InitRecordingAndPlayback(); } else { @@ -305,8 +309,15 @@ void CSound::SetDev ( const int iNewDev ) } } -std::string CSound::LoadAndInitializeDriver ( const int iDriverIdx ) +std::string CSound::LoadAndInitializeDriver ( int iDriverIdx ) { + // first check and correct input parameter + if ( iDriverIdx >= lNumDevs ) + { + // we assume here that at least one driver is in the system + iDriverIdx = 0; + } + // load driver loadAsioDriver ( cDriverNames[iDriverIdx] ); if ( ASIOInit ( &driverInfo ) != ASE_OK ) @@ -316,6 +327,62 @@ std::string CSound::LoadAndInitializeDriver ( const int iDriverIdx ) return "The audio driver could not be initialized."; } + const std::string strStat = GetAndCheckSoundCardProperties(); + + // store ID of selected driver if initialization was successful + if ( strStat.empty() ) + { + lCurDev = iDriverIdx; + } + + return strStat; +} + +bool CSound::LoadAndInitializeFirstValidDriver() +{ + // load and initialize first valid ASIO driver + bool bValidDriverDetected = false; + int iCurDriverIdx = 0; + + // try all available drivers in the system ("lNumDevs" devices) + while ( !bValidDriverDetected && iCurDriverIdx < lNumDevs ) + { + if ( loadAsioDriver ( cDriverNames[iCurDriverIdx] ) ) + { + if ( ASIOInit ( &driverInfo ) == ASE_OK ) + { + if ( GetAndCheckSoundCardProperties().empty() ) + { + // initialization was successful + bValidDriverDetected = true; + + // store ID of selected driver + lCurDev = iCurDriverIdx; + } + else + { + // driver could not be loaded, free memory + asioDrivers->removeCurrentDriver(); + } + } + else + { + // driver could not be loaded, free memory + asioDrivers->removeCurrentDriver(); + } + } + + // try next driver + iCurDriverIdx++; + } + + return bValidDriverDetected; +} + +std::string CSound::GetAndCheckSoundCardProperties() +{ + int i; + // check the number of available channels long lNumInChan; long lNumOutChan; @@ -350,165 +417,125 @@ std::string CSound::LoadAndInitializeDriver ( const int iDriverIdx ) &HWBufferInfo.lPreferredSize, &HWBufferInfo.lGranularity ); + // calculate "nearest" buffer size and set internal parameter accordingly + // first check minimum and maximum values + if ( iBufferSizeMono < HWBufferInfo.lMinSize ) + { + iASIOBufferSizeMono = HWBufferInfo.lMinSize; + } + else + { + if ( iBufferSizeMono > HWBufferInfo.lMaxSize ) + { + iASIOBufferSizeMono = HWBufferInfo.lMaxSize; + } + else + { + // initialization + int iTrialBufSize = HWBufferInfo.lMinSize; + int iLastTrialBufSize = HWBufferInfo.lMinSize; + bool bSizeFound = false; + + // test loop + while ( ( iTrialBufSize <= HWBufferInfo.lMaxSize ) && ( !bSizeFound ) ) + { + if ( iTrialBufSize >= iBufferSizeMono ) + { + // test which buffer size fits better: the old one or the + // current one + if ( ( iTrialBufSize - iBufferSizeMono ) < + ( iBufferSizeMono - iLastTrialBufSize ) ) + { + iBufferSizeMono = iTrialBufSize; + } + else + { + iBufferSizeMono = iLastTrialBufSize; + } + + // exit while loop + bSizeFound = true; + } + + if ( !bSizeFound ) + { + // store old trial buffer size + iLastTrialBufSize = iTrialBufSize; + + // increment trial buffer size (check for special case first) + if ( HWBufferInfo.lGranularity == -1 ) + { + // special case: buffer sizes are a power of 2 + iTrialBufSize *= 2; + } + else + { + iTrialBufSize += HWBufferInfo.lGranularity; + } + } + } + + // set ASIO buffer size + iASIOBufferSizeMono = iTrialBufSize; + } + } + + // prepare input channels + for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ ) + { + bufferInfos[i].isInput = ASIOTrue; + bufferInfos[i].channelNum = i; + bufferInfos[i].buffers[0] = 0; + bufferInfos[i].buffers[1] = 0; + } + + // prepare output channels + for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ ) + { + bufferInfos[NUM_IN_OUT_CHANNELS + i].isInput = ASIOFalse; + bufferInfos[NUM_IN_OUT_CHANNELS + i].channelNum = i; + bufferInfos[NUM_IN_OUT_CHANNELS + i].buffers[0] = 0; + bufferInfos[NUM_IN_OUT_CHANNELS + i].buffers[1] = 0; + } + + // create and activate ASIO buffers (buffer size in samples) + ASIOCreateBuffers ( bufferInfos, 2 /* in/out */ * NUM_IN_OUT_CHANNELS /* stereo */, + iASIOBufferSizeMono, &asioCallbacks ); + + // now get some buffer details + for ( i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) + { + channelInfos[i].channel = bufferInfos[i].channelNum; + channelInfos[i].isInput = bufferInfos[i].isInput; + ASIOGetChannelInfo ( &channelInfos[i] ); + + // only 16/24/32 LSB is supported + if ( ( channelInfos[i].type != ASIOSTInt16LSB ) && + ( channelInfos[i].type != ASIOSTInt24LSB ) && + ( channelInfos[i].type != ASIOSTInt32LSB ) ) + { + // clean up and return error string + ASIODisposeBuffers(); + ASIOExit(); + asioDrivers->removeCurrentDriver(); + return "Required audio sample format not available (16/24/32 bit LSB)."; + } + } + // check wether the driver requires the ASIOOutputReady() optimization // (can be used by the driver to reduce output latency by one block) bASIOPostOutput = ( ASIOOutputReady() == ASE_OK ); - // store ID of selected driver - lCurDev = iDriverIdx; - return ""; } -bool CSound::LoadAndInitializeFirstValidDriver() +void CSound::InitRecordingAndPlayback() { - // load and initialize first valid ASIO driver - bool bValidDriverDetected = false; - int iCurDriverIdx = 0; - - // try all available drivers in the system ("lNumDevs" devices) - while ( !bValidDriverDetected && iCurDriverIdx < lNumDevs ) - { - if ( loadAsioDriver ( cDriverNames[iCurDriverIdx] ) ) - { - if ( ASIOInit ( &driverInfo ) == ASE_OK ) - { - // initialization was successful - bValidDriverDetected = true; - - // store ID of selected driver - lCurDev = iCurDriverIdx; - } - else - { - // driver could not be loaded, free memory - asioDrivers->removeCurrentDriver(); - } - } - - // try next driver - iCurDriverIdx++; - } - - return bValidDriverDetected; -} - -void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) -{ - int i; - // first, stop audio and dispose ASIO buffers ASIOStop(); - ASIODisposeBuffers(); ASIOMutex.lock(); // get mutex lock { - // set internal buffer size value and calculate mono buffer size - iBufferSizeStereo = iNewBufferSize; - iBufferSizeMono = iBufferSizeStereo / 2; - - // calculate "nearest" buffer size and set internal parameter accordingly - // first check minimum and maximum values - if ( iBufferSizeMono < HWBufferInfo.lMinSize ) - { - iASIOBufferSizeMono = HWBufferInfo.lMinSize; - } - else - { - if ( iBufferSizeMono > HWBufferInfo.lMaxSize ) - { - iASIOBufferSizeMono = HWBufferInfo.lMaxSize; - } - else - { - // initialization - int iTrialBufSize = HWBufferInfo.lMinSize; - int iLastTrialBufSize = HWBufferInfo.lMinSize; - bool bSizeFound = false; - - // test loop - while ( ( iTrialBufSize <= HWBufferInfo.lMaxSize ) && ( !bSizeFound ) ) - { - if ( iTrialBufSize >= iBufferSizeMono ) - { - // test which buffer size fits better: the old one or the - // current one - if ( ( iTrialBufSize - iBufferSizeMono ) < - ( iBufferSizeMono - iLastTrialBufSize ) ) - { - iBufferSizeMono = iTrialBufSize; - } - else - { - iBufferSizeMono = iLastTrialBufSize; - } - - // exit while loop - bSizeFound = true; - } - - if ( !bSizeFound ) - { - // store old trial buffer size - iLastTrialBufSize = iTrialBufSize; - - // increment trial buffer size (check for special case first) - if ( HWBufferInfo.lGranularity == -1 ) - { - // special case: buffer sizes are a power of 2 - iTrialBufSize *= 2; - } - else - { - iTrialBufSize += HWBufferInfo.lGranularity; - } - } - } - - // set ASIO buffer size - iASIOBufferSizeMono = iTrialBufSize; - } - } - - // prepare input channels - for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ ) - { - bufferInfos[i].isInput = ASIOTrue; - bufferInfos[i].channelNum = i; - bufferInfos[i].buffers[0] = 0; - bufferInfos[i].buffers[1] = 0; - } - - // prepare output channels - for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ ) - { - bufferInfos[NUM_IN_OUT_CHANNELS + i].isInput = ASIOFalse; - bufferInfos[NUM_IN_OUT_CHANNELS + i].channelNum = i; - bufferInfos[NUM_IN_OUT_CHANNELS + i].buffers[0] = 0; - bufferInfos[NUM_IN_OUT_CHANNELS + i].buffers[1] = 0; - } - - // create and activate ASIO buffers (buffer size in samples) - ASIOCreateBuffers ( bufferInfos, 2 /* in/out */ * NUM_IN_OUT_CHANNELS /* stereo */, - iASIOBufferSizeMono, &asioCallbacks ); - - // now get some buffer details - for ( i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) - { - channelInfos[i].channel = bufferInfos[i].channelNum; - channelInfos[i].isInput = bufferInfos[i].isInput; - ASIOGetChannelInfo ( &channelInfos[i] ); - - // only 16 bit is supported - if ( ( channelInfos[i].type != ASIOSTInt16LSB ) && - ( channelInfos[i].type != ASIOSTInt24LSB ) && - ( channelInfos[i].type != ASIOSTInt32LSB ) ) - { - throw CGenErr ( "Required audio sample format not available (16/24/32 bit LSB)." ); - } - } - - // Our buffer management ----------------------------------------------- // store new buffer number values iCurNumSndBufIn = iNewNumSndBufIn; @@ -537,7 +564,7 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) psPlayBuffer = new short[iCurNumSndBufOut * iBufferSizeStereo]; // clear new buffer - for ( i = 0; i < iCurNumSndBufOut * iBufferSizeStereo; i++ ) + for ( int i = 0; i < iCurNumSndBufOut * iBufferSizeStereo; i++ ) { psPlayBuffer[i] = 0; } @@ -553,6 +580,9 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) void CSound::Close() { + // stop driver + ASIOStop(); + // set event to ensure that thread leaves the waiting function if ( m_ASIOEvent != NULL ) { @@ -562,8 +592,7 @@ void CSound::Close() // wait for the thread to terminate Sleep ( 500 ); - // stop audio and dispose ASIO buffers - ASIOStop(); + // dispose ASIO buffers ASIODisposeBuffers(); // set flag to open devices the next time it is initialized @@ -571,8 +600,12 @@ void CSound::Close() bChangParamOut = true; } -CSound::CSound() +CSound::CSound ( const int iNewBufferSizeStereo ) { + // set internal buffer size value and calculate mono buffer size + iBufferSizeStereo = iNewBufferSizeStereo; + iBufferSizeMono = iBufferSizeStereo / 2; + // init number of sound buffers iNewNumSndBufIn = NUM_SOUND_BUFFERS_IN; iCurNumSndBufIn = NUM_SOUND_BUFFERS_IN; diff --git a/windows/sound.h b/windows/sound.h index 094e9f44..99d6a86b 100755 --- a/windows/sound.h +++ b/windows/sound.h @@ -65,18 +65,18 @@ class CSound { public: - CSound(); + CSound ( const int iNewBufferSizeStereo ); virtual ~CSound(); - void InitRecording ( const int iNewBufferSize, const bool bNewBlocking = true ) + void InitRecording ( const bool bNewBlocking = true ) { bBlockingRec = bNewBlocking; - InitRecordingAndPlayback ( iNewBufferSize ); + InitRecordingAndPlayback(); } - void InitPlayback ( const int iNewBufferSize, const bool bNewBlocking = false ) + void InitPlayback ( const bool bNewBlocking = false ) { bBlockingPlay = bNewBlocking; - InitRecordingAndPlayback ( iNewBufferSize ); + InitRecordingAndPlayback(); } bool Read ( CVector& psData ); bool Write ( CVector& psData ); @@ -96,8 +96,9 @@ public: protected: bool LoadAndInitializeFirstValidDriver(); - std::string LoadAndInitializeDriver ( const int iIdx ); - void InitRecordingAndPlayback ( const int iNewBufferSize ); + std::string LoadAndInitializeDriver ( int iIdx ); + std::string GetAndCheckSoundCardProperties(); + void InitRecordingAndPlayback(); // audio hardware buffer info struct sHWBufferInfo