some fixes for selecting different ASIO soundcards
This commit is contained in:
parent
1c2535db16
commit
8d77d11ff9
7 changed files with 275 additions and 236 deletions
|
@ -13,13 +13,10 @@
|
||||||
|
|
||||||
#ifdef WITH_SOUND
|
#ifdef WITH_SOUND
|
||||||
/* Wave in ********************************************************************/
|
/* Wave in ********************************************************************/
|
||||||
void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
|
void CSound::InitRecording ( const bool bNewBlocking )
|
||||||
{
|
{
|
||||||
int err;
|
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 recording device was already open, close it first */
|
||||||
if ( rhandle != NULL )
|
if ( rhandle != NULL )
|
||||||
{
|
{
|
||||||
|
@ -112,12 +109,12 @@ void CSound::InitRecording(int iNewBufferSize, bool bNewBlocking)
|
||||||
qDebug ( "alsa init record done" );
|
qDebug ( "alsa init record done" );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSound::Read(CVector<short>& psData)
|
bool CSound::Read ( CVector<short>& psData )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check if device must be opened or reinitialized */
|
/* Check if device must be opened or reinitialized */
|
||||||
if (bChangParamIn == true)
|
if ( bChangParamIn == true )
|
||||||
{
|
{
|
||||||
InitRecording ( iBufferSizeIn * NUM_IN_OUT_CHANNELS );
|
InitRecording ( iBufferSizeIn * NUM_IN_OUT_CHANNELS );
|
||||||
|
|
||||||
|
@ -125,7 +122,7 @@ bool CSound::Read(CVector<short>& psData)
|
||||||
bChangParamIn = false;
|
bChangParamIn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = snd_pcm_readi(rhandle, &psData[0], iBufferSizeIn);
|
ret = snd_pcm_readi ( rhandle, &psData[0], iBufferSizeIn );
|
||||||
|
|
||||||
if ( ret < 0 )
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
|
@ -143,7 +140,7 @@ bool CSound::Read(CVector<short>& psData)
|
||||||
|
|
||||||
ret = snd_pcm_start ( rhandle );
|
ret = snd_pcm_start ( rhandle );
|
||||||
|
|
||||||
if (ret < 0)
|
if ( ret < 0 )
|
||||||
{
|
{
|
||||||
qDebug ( "Can't recover from underrun, start failed: %s", snd_strerror ( ret ) );
|
qDebug ( "Can't recover from underrun, start failed: %s", snd_strerror ( ret ) );
|
||||||
}
|
}
|
||||||
|
@ -204,13 +201,10 @@ void CSound::SetInNumBuf ( int iNewNum )
|
||||||
|
|
||||||
|
|
||||||
/* Wave out *******************************************************************/
|
/* Wave out *******************************************************************/
|
||||||
void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking )
|
void CSound::InitPlayback ( const bool bNewBlocking )
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// save buffer size
|
|
||||||
iBufferSizeOut = iNewBufferSize / NUM_IN_OUT_CHANNELS; // mono size
|
|
||||||
|
|
||||||
// if playback device was already open, close it first
|
// if playback device was already open, close it first
|
||||||
if ( phandle != NULL )
|
if ( phandle != NULL )
|
||||||
{
|
{
|
||||||
|
@ -219,7 +213,7 @@ void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking )
|
||||||
|
|
||||||
// playback device (either "hw:0,0" or "plughw:0,0")
|
// playback device (either "hw:0,0" or "plughw:0,0")
|
||||||
if ( err = snd_pcm_open ( &phandle, "hw: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 ) );
|
qDebug ( "open error: %s", snd_strerror ( err ) );
|
||||||
}
|
}
|
||||||
|
@ -241,16 +235,16 @@ void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking )
|
||||||
|
|
||||||
bool CSound::Write ( CVector<short>& psData )
|
bool CSound::Write ( CVector<short>& psData )
|
||||||
{
|
{
|
||||||
int size = iBufferSizeOut;
|
int size = iBufferSizeOut;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Check if device must be opened or reinitialized */
|
// check if device must be opened or reinitialized
|
||||||
if ( bChangParamOut == true )
|
if ( bChangParamOut == true )
|
||||||
{
|
{
|
||||||
InitPlayback ( iBufferSizeOut * NUM_IN_OUT_CHANNELS );
|
InitPlayback ( iBufferSizeOut * NUM_IN_OUT_CHANNELS );
|
||||||
|
|
||||||
/* Reset flag */
|
// reset flag
|
||||||
bChangParamOut = false;
|
bChangParamOut = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +256,7 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
{
|
{
|
||||||
if ( ret == -EPIPE )
|
if ( ret == -EPIPE )
|
||||||
{
|
{
|
||||||
/* under-run */
|
// under-run
|
||||||
qDebug ( "wunderrun" );
|
qDebug ( "wunderrun" );
|
||||||
|
|
||||||
ret = snd_pcm_prepare ( phandle );
|
ret = snd_pcm_prepare ( phandle );
|
||||||
|
@ -286,7 +280,7 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
{
|
{
|
||||||
qDebug("wstrpipe");
|
qDebug("wstrpipe");
|
||||||
|
|
||||||
/* wait until the suspend flag is released */
|
// wait until the suspend flag is released
|
||||||
while ( (ret = snd_pcm_resume ( phandle ) ) == -EAGAIN )
|
while ( (ret = snd_pcm_resume ( phandle ) ) == -EAGAIN )
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
@ -317,29 +311,29 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
return false;
|
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 ) )
|
if ( ( iNewNum >= MAX_SND_BUF_OUT ) || ( iNewNum < 1 ) )
|
||||||
{
|
{
|
||||||
iNewNum = NUM_PERIOD_BLOCKS_OUT;
|
iNewNum = NUM_PERIOD_BLOCKS_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change only if parameter is different */
|
// change only if parameter is different
|
||||||
if ( iNewNum != iCurPeriodSizeOut )
|
if ( iNewNum != iCurPeriodSizeOut )
|
||||||
{
|
{
|
||||||
iCurPeriodSizeOut = iNewNum;
|
iCurPeriodSizeOut = iNewNum;
|
||||||
bChangParamOut = true;
|
bChangParamOut = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* common **********************************************************************/
|
/* common **********************************************************************/
|
||||||
bool CSound::SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
|
bool CSound::SetHWParams ( snd_pcm_t* handle, const int iBufferSizeIn,
|
||||||
const int iNumPeriodBlocks)
|
const int iNumPeriodBlocks )
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_pcm_hw_params_t* hwparams;
|
snd_pcm_hw_params_t* hwparams;
|
||||||
|
|
||||||
// allocate an invalid snd_pcm_hw_params_t using standard malloc
|
// allocate an invalid snd_pcm_hw_params_t using standard malloc
|
||||||
if ( err = snd_pcm_hw_params_malloc ( &hwparams ) < 0 )
|
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;
|
snd_pcm_uframes_t buffer_size;
|
||||||
if (err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size) < 0) {
|
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 ( "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;
|
snd_pcm_uframes_t period_size;
|
||||||
err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0);
|
err = snd_pcm_hw_params_get_period_size ( hwparams, &period_size, 0 );
|
||||||
if (err < 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 );
|
snd_pcm_hw_params_free ( hwparams );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSound::Close ()
|
void CSound::Close()
|
||||||
{
|
{
|
||||||
/* read */
|
// read
|
||||||
if ( rhandle != NULL )
|
if ( rhandle != NULL )
|
||||||
{
|
{
|
||||||
snd_pcm_close ( rhandle );
|
snd_pcm_close ( rhandle );
|
||||||
|
@ -449,7 +443,7 @@ void CSound::Close ()
|
||||||
|
|
||||||
rhandle = NULL;
|
rhandle = NULL;
|
||||||
|
|
||||||
/* playback */
|
// playback
|
||||||
if ( phandle != NULL )
|
if ( phandle != NULL )
|
||||||
{
|
{
|
||||||
snd_pcm_close ( phandle );
|
snd_pcm_close ( phandle );
|
||||||
|
|
|
@ -31,9 +31,9 @@
|
||||||
|
|
||||||
|
|
||||||
/* Definitions ****************************************************************/
|
/* 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_IN 2
|
||||||
#define NUM_PERIOD_BLOCKS_OUT 2
|
#define NUM_PERIOD_BLOCKS_OUT 2
|
||||||
|
|
||||||
|
@ -44,14 +44,18 @@
|
||||||
class CSound
|
class CSound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CSound()
|
CSound ( const int iNewBufferSizeStereo )
|
||||||
#if WITH_SOUND
|
#if WITH_SOUND
|
||||||
: rhandle(NULL), phandle(NULL), iCurPeriodSizeIn(NUM_PERIOD_BLOCKS_IN),
|
: rhandle ( NULL ), phandle ( NULL ), iCurPeriodSizeIn ( NUM_PERIOD_BLOCKS_IN ),
|
||||||
iCurPeriodSizeOut(NUM_PERIOD_BLOCKS_OUT), bChangParamIn(true),
|
iCurPeriodSizeOut ( NUM_PERIOD_BLOCKS_OUT ), bChangParamIn ( true ),
|
||||||
bChangParamOut(true)
|
bChangParamOut ( true )
|
||||||
#endif
|
#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
|
// not implemented yet, always return one device and default string
|
||||||
int GetNumDev() { return 1; }
|
int GetNumDev() { return 1; }
|
||||||
|
@ -60,14 +64,14 @@ public:
|
||||||
int GetDev() { return 0; }
|
int GetDev() { return 0; }
|
||||||
|
|
||||||
#if WITH_SOUND
|
#if WITH_SOUND
|
||||||
void SetInNumBuf(int iNewNum);
|
void SetInNumBuf ( int iNewNum );
|
||||||
int GetInNumBuf() {return iCurPeriodSizeIn;}
|
int GetInNumBuf() { return iCurPeriodSizeIn; }
|
||||||
void SetOutNumBuf(int iNewNum);
|
void SetOutNumBuf ( int iNewNum );
|
||||||
int GetOutNumBuf() {return iCurPeriodSizeOut;}
|
int GetOutNumBuf() { return iCurPeriodSizeOut; }
|
||||||
void InitRecording(int iNewBufferSize, bool bNewBlocking = true);
|
void InitRecording ( const bool bNewBlocking = true );
|
||||||
void InitPlayback(int iNewBufferSize, bool bNewBlocking = false);
|
void InitPlayback ( const bool bNewBlocking = false );
|
||||||
bool Read(CVector<short>& psData);
|
bool Read ( CVector<short>& psData );
|
||||||
bool Write(CVector<short>& psData);
|
bool Write ( CVector<short>& psData );
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
|
@ -75,8 +79,8 @@ protected:
|
||||||
snd_pcm_t* rhandle;
|
snd_pcm_t* rhandle;
|
||||||
snd_pcm_t* phandle;
|
snd_pcm_t* phandle;
|
||||||
|
|
||||||
bool SetHWParams(snd_pcm_t* handle, const int iBufferSizeIn,
|
bool SetHWParams ( snd_pcm_t* handle, const int iBufferSizeIn,
|
||||||
const int iNumPeriodBlocks);
|
const int iNumPeriodBlocks );
|
||||||
|
|
||||||
int iBufferSizeOut;
|
int iBufferSizeOut;
|
||||||
int iBufferSizeIn;
|
int iBufferSizeIn;
|
||||||
|
@ -85,15 +89,15 @@ protected:
|
||||||
bool bChangParamOut;
|
bool bChangParamOut;
|
||||||
int iCurPeriodSizeOut;
|
int iCurPeriodSizeOut;
|
||||||
#else
|
#else
|
||||||
/* Dummy definitions */
|
// dummy definitions
|
||||||
void SetInNumBuf(int iNewNum) {}
|
void SetInNumBuf ( int iNewNum ) {}
|
||||||
int GetInNumBuf() {return 1;}
|
int GetInNumBuf() { return 1; }
|
||||||
void SetOutNumBuf(int iNewNum) {}
|
void SetOutNumBuf ( int iNewNum ) {}
|
||||||
int GetOutNumBuf() {return 1;}
|
int GetOutNumBuf() { return 1; }
|
||||||
void InitRecording(int iNewBufferSize, bool bNewBlocking = true) {printf("no sound!");}
|
void InitRecording ( const bool bNewBlocking = true ) { printf ( "no sound!" ); }
|
||||||
void InitPlayback(int iNewBufferSize, bool bNewBlocking = false) {printf("no sound!");}
|
void InitPlayback ( const bool bNewBlocking = false ) { printf ( "no sound!" ); }
|
||||||
bool Read(CVector<short>& psData) {printf("no sound!"); return false;}
|
bool Read ( CVector<short>& psData ) { printf ( "no sound!" ); return false; }
|
||||||
bool Write(CVector<short>& psData) {printf("no sound!"); return false;}
|
bool Write ( CVector<short>& psData ) { printf ( "no sound!" ); return false; }
|
||||||
void Close() {}
|
void Close() {}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
/* Implementation *************************************************************/
|
/* Implementation *************************************************************/
|
||||||
CClient::CClient ( const quint16 iPortNumber ) : bRun ( false ),
|
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 ),
|
Socket ( &Channel, iPortNumber ),
|
||||||
iAudioInFader ( AUD_FADER_IN_MAX / 2 ),
|
iAudioInFader ( AUD_FADER_IN_MAX / 2 ),
|
||||||
iReverbLevel ( AUD_REVERB_MAX / 6 ),
|
iReverbLevel ( AUD_REVERB_MAX / 6 ),
|
||||||
|
@ -168,9 +170,8 @@ void CClient::OnProtocolStatus ( bool bOk )
|
||||||
|
|
||||||
void CClient::Init()
|
void CClient::Init()
|
||||||
{
|
{
|
||||||
// set block sizes (in samples)
|
// set block size (in samples)
|
||||||
iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
|
iBlockSizeSam = MIN_BLOCK_SIZE_SAMPLES;
|
||||||
iSndCrdBlockSizeSam = MIN_SND_CRD_BLOCK_SIZE_SAMPLES;
|
|
||||||
|
|
||||||
vecsAudioSndCrd.Init ( iSndCrdBlockSizeSam * 2 ); // stereo
|
vecsAudioSndCrd.Init ( iSndCrdBlockSizeSam * 2 ); // stereo
|
||||||
vecdAudioSndCrdL.Init ( iSndCrdBlockSizeSam );
|
vecdAudioSndCrdL.Init ( iSndCrdBlockSizeSam );
|
||||||
|
@ -179,8 +180,8 @@ void CClient::Init()
|
||||||
vecdAudioL.Init ( iBlockSizeSam );
|
vecdAudioL.Init ( iBlockSizeSam );
|
||||||
vecdAudioR.Init ( iBlockSizeSam );
|
vecdAudioR.Init ( iBlockSizeSam );
|
||||||
|
|
||||||
Sound.InitRecording ( iSndCrdBlockSizeSam * 2 ); // stereo
|
Sound.InitRecording();
|
||||||
Sound.InitPlayback ( iSndCrdBlockSizeSam * 2 ); // stereo
|
Sound.InitPlayback();
|
||||||
|
|
||||||
// resample objects are always initialized with the input block size
|
// resample objects are always initialized with the input block size
|
||||||
// record
|
// record
|
||||||
|
@ -325,7 +326,7 @@ void CClient::run()
|
||||||
|
|
||||||
// send it through the network
|
// send it through the network
|
||||||
Socket.SendPacket ( Channel.PrepSendPacket ( vecsNetwork ),
|
Socket.SendPacket ( Channel.PrepSendPacket ( vecsNetwork ),
|
||||||
Channel.GetAddress () );
|
Channel.GetAddress() );
|
||||||
|
|
||||||
// receive a new block
|
// receive a new block
|
||||||
if ( Channel.GetData ( vecdNetwData ) == GS_BUFFER_OK )
|
if ( Channel.GetData ( vecdNetwData ) == GS_BUFFER_OK )
|
||||||
|
|
|
@ -250,7 +250,8 @@ void CClientSettingsDlg::OnSoundCrdSelection ( int iSndDevIdx )
|
||||||
{
|
{
|
||||||
QMessageBox::critical ( 0, APP_NAME,
|
QMessageBox::critical ( 0, APP_NAME,
|
||||||
QString ( "The selected audio device could not be used because "
|
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
|
// recover old selection
|
||||||
cbSoundcard->setCurrentIndex ( pClient->GetSndInterface()->GetDev() );
|
cbSoundcard->setCurrentIndex ( pClient->GetSndInterface()->GetDev() );
|
||||||
|
|
|
@ -138,6 +138,11 @@ int main ( int argc, char** argv )
|
||||||
exit ( 1 );
|
exit ( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Set application priority class -> high priority
|
||||||
|
SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS );
|
||||||
|
#endif
|
||||||
|
|
||||||
// Application object
|
// Application object
|
||||||
QApplication app ( argc, argv, bUseGUI );
|
QApplication app ( argc, argv, bUseGUI );
|
||||||
|
|
||||||
|
|
|
@ -87,8 +87,8 @@ bool CSound::Read ( CVector<short>& psData )
|
||||||
// check if device must be opened or reinitialized
|
// check if device must be opened or reinitialized
|
||||||
if ( bChangParamIn )
|
if ( bChangParamIn )
|
||||||
{
|
{
|
||||||
// reinit sound interface (init recording requires stereo buffer size)
|
// reinit sound interface
|
||||||
InitRecordingAndPlayback ( iBufferSizeStereo );
|
InitRecordingAndPlayback();
|
||||||
|
|
||||||
// reset flag
|
// reset flag
|
||||||
bChangParamIn = false;
|
bChangParamIn = false;
|
||||||
|
@ -188,8 +188,8 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
// check if device must be opened or reinitialized
|
// check if device must be opened or reinitialized
|
||||||
if ( bChangParamOut )
|
if ( bChangParamOut )
|
||||||
{
|
{
|
||||||
// reinit sound interface (init recording requires stereo buffer size)
|
// reinit sound interface
|
||||||
InitRecordingAndPlayback ( iBufferSizeStereo );
|
InitRecordingAndPlayback();
|
||||||
|
|
||||||
// reset flag
|
// reset flag
|
||||||
bChangParamOut = false;
|
bChangParamOut = false;
|
||||||
|
@ -256,6 +256,9 @@ void CSound::SetDev ( const int iNewDev )
|
||||||
{
|
{
|
||||||
// a device was already been initialized and is used, kill working
|
// a device was already been initialized and is used, kill working
|
||||||
// thread and clean up
|
// thread and clean up
|
||||||
|
// stop driver
|
||||||
|
ASIOStop();
|
||||||
|
|
||||||
// set event to ensure that thread leaves the waiting function
|
// set event to ensure that thread leaves the waiting function
|
||||||
if ( m_ASIOEvent != NULL )
|
if ( m_ASIOEvent != NULL )
|
||||||
{
|
{
|
||||||
|
@ -265,8 +268,7 @@ void CSound::SetDev ( const int iNewDev )
|
||||||
// wait for the thread to terminate
|
// wait for the thread to terminate
|
||||||
Sleep ( 500 );
|
Sleep ( 500 );
|
||||||
|
|
||||||
// stop audio and dispose ASIO buffers
|
// dispose ASIO buffers
|
||||||
ASIOStop();
|
|
||||||
ASIODisposeBuffers();
|
ASIODisposeBuffers();
|
||||||
|
|
||||||
// remove old driver
|
// remove old driver
|
||||||
|
@ -280,9 +282,11 @@ void CSound::SetDev ( const int iNewDev )
|
||||||
// loading and initializing the new driver failed, go back to original
|
// loading and initializing the new driver failed, go back to original
|
||||||
// driver and display error message
|
// driver and display error message
|
||||||
LoadAndInitializeDriver ( lCurDev );
|
LoadAndInitializeDriver ( lCurDev );
|
||||||
|
InitRecordingAndPlayback();
|
||||||
|
|
||||||
throw CGenErr ( strErrorMessage.c_str() );
|
throw CGenErr ( strErrorMessage.c_str() );
|
||||||
}
|
}
|
||||||
|
InitRecordingAndPlayback();
|
||||||
}
|
}
|
||||||
else
|
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
|
// load driver
|
||||||
loadAsioDriver ( cDriverNames[iDriverIdx] );
|
loadAsioDriver ( cDriverNames[iDriverIdx] );
|
||||||
if ( ASIOInit ( &driverInfo ) != ASE_OK )
|
if ( ASIOInit ( &driverInfo ) != ASE_OK )
|
||||||
|
@ -316,6 +327,62 @@ std::string CSound::LoadAndInitializeDriver ( const int iDriverIdx )
|
||||||
return "The audio driver could not be initialized.";
|
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
|
// check the number of available channels
|
||||||
long lNumInChan;
|
long lNumInChan;
|
||||||
long lNumOutChan;
|
long lNumOutChan;
|
||||||
|
@ -350,165 +417,125 @@ std::string CSound::LoadAndInitializeDriver ( const int iDriverIdx )
|
||||||
&HWBufferInfo.lPreferredSize,
|
&HWBufferInfo.lPreferredSize,
|
||||||
&HWBufferInfo.lGranularity );
|
&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
|
// check wether the driver requires the ASIOOutputReady() optimization
|
||||||
// (can be used by the driver to reduce output latency by one block)
|
// (can be used by the driver to reduce output latency by one block)
|
||||||
bASIOPostOutput = ( ASIOOutputReady() == ASE_OK );
|
bASIOPostOutput = ( ASIOOutputReady() == ASE_OK );
|
||||||
|
|
||||||
// store ID of selected driver
|
|
||||||
lCurDev = iDriverIdx;
|
|
||||||
|
|
||||||
return "";
|
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
|
// first, stop audio and dispose ASIO buffers
|
||||||
ASIOStop();
|
ASIOStop();
|
||||||
ASIODisposeBuffers();
|
|
||||||
|
|
||||||
ASIOMutex.lock(); // get mutex lock
|
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 -----------------------------------------------
|
// Our buffer management -----------------------------------------------
|
||||||
// store new buffer number values
|
// store new buffer number values
|
||||||
iCurNumSndBufIn = iNewNumSndBufIn;
|
iCurNumSndBufIn = iNewNumSndBufIn;
|
||||||
|
@ -537,7 +564,7 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize )
|
||||||
psPlayBuffer = new short[iCurNumSndBufOut * iBufferSizeStereo];
|
psPlayBuffer = new short[iCurNumSndBufOut * iBufferSizeStereo];
|
||||||
|
|
||||||
// clear new buffer
|
// clear new buffer
|
||||||
for ( i = 0; i < iCurNumSndBufOut * iBufferSizeStereo; i++ )
|
for ( int i = 0; i < iCurNumSndBufOut * iBufferSizeStereo; i++ )
|
||||||
{
|
{
|
||||||
psPlayBuffer[i] = 0;
|
psPlayBuffer[i] = 0;
|
||||||
}
|
}
|
||||||
|
@ -553,6 +580,9 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize )
|
||||||
|
|
||||||
void CSound::Close()
|
void CSound::Close()
|
||||||
{
|
{
|
||||||
|
// stop driver
|
||||||
|
ASIOStop();
|
||||||
|
|
||||||
// set event to ensure that thread leaves the waiting function
|
// set event to ensure that thread leaves the waiting function
|
||||||
if ( m_ASIOEvent != NULL )
|
if ( m_ASIOEvent != NULL )
|
||||||
{
|
{
|
||||||
|
@ -562,8 +592,7 @@ void CSound::Close()
|
||||||
// wait for the thread to terminate
|
// wait for the thread to terminate
|
||||||
Sleep ( 500 );
|
Sleep ( 500 );
|
||||||
|
|
||||||
// stop audio and dispose ASIO buffers
|
// dispose ASIO buffers
|
||||||
ASIOStop();
|
|
||||||
ASIODisposeBuffers();
|
ASIODisposeBuffers();
|
||||||
|
|
||||||
// set flag to open devices the next time it is initialized
|
// set flag to open devices the next time it is initialized
|
||||||
|
@ -571,8 +600,12 @@ void CSound::Close()
|
||||||
bChangParamOut = true;
|
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
|
// init number of sound buffers
|
||||||
iNewNumSndBufIn = NUM_SOUND_BUFFERS_IN;
|
iNewNumSndBufIn = NUM_SOUND_BUFFERS_IN;
|
||||||
iCurNumSndBufIn = NUM_SOUND_BUFFERS_IN;
|
iCurNumSndBufIn = NUM_SOUND_BUFFERS_IN;
|
||||||
|
|
|
@ -65,18 +65,18 @@
|
||||||
class CSound
|
class CSound
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CSound();
|
CSound ( const int iNewBufferSizeStereo );
|
||||||
virtual ~CSound();
|
virtual ~CSound();
|
||||||
|
|
||||||
void InitRecording ( const int iNewBufferSize, const bool bNewBlocking = true )
|
void InitRecording ( const bool bNewBlocking = true )
|
||||||
{
|
{
|
||||||
bBlockingRec = bNewBlocking;
|
bBlockingRec = bNewBlocking;
|
||||||
InitRecordingAndPlayback ( iNewBufferSize );
|
InitRecordingAndPlayback();
|
||||||
}
|
}
|
||||||
void InitPlayback ( const int iNewBufferSize, const bool bNewBlocking = false )
|
void InitPlayback ( const bool bNewBlocking = false )
|
||||||
{
|
{
|
||||||
bBlockingPlay = bNewBlocking;
|
bBlockingPlay = bNewBlocking;
|
||||||
InitRecordingAndPlayback ( iNewBufferSize );
|
InitRecordingAndPlayback();
|
||||||
}
|
}
|
||||||
bool Read ( CVector<short>& psData );
|
bool Read ( CVector<short>& psData );
|
||||||
bool Write ( CVector<short>& psData );
|
bool Write ( CVector<short>& psData );
|
||||||
|
@ -96,8 +96,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool LoadAndInitializeFirstValidDriver();
|
bool LoadAndInitializeFirstValidDriver();
|
||||||
std::string LoadAndInitializeDriver ( const int iIdx );
|
std::string LoadAndInitializeDriver ( int iIdx );
|
||||||
void InitRecordingAndPlayback ( const int iNewBufferSize );
|
std::string GetAndCheckSoundCardProperties();
|
||||||
|
void InitRecordingAndPlayback();
|
||||||
|
|
||||||
// audio hardware buffer info
|
// audio hardware buffer info
|
||||||
struct sHWBufferInfo
|
struct sHWBufferInfo
|
||||||
|
|
Loading…
Reference in a new issue