some more ASIO stuff
This commit is contained in:
parent
4889a1d378
commit
74cb27d2bc
2 changed files with 356 additions and 361 deletions
|
@ -47,10 +47,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 == TRUE )
|
if ( bChangParamIn == TRUE )
|
||||||
{
|
{
|
||||||
OpenInDevice();
|
|
||||||
|
|
||||||
// Reinit sound interface
|
// Reinit sound interface
|
||||||
InitRecording ( iBufferSizeIn, bBlockingRec );
|
InitRecordingAndPlayback ( iBufferSize );
|
||||||
|
|
||||||
// Reset flag
|
// Reset flag
|
||||||
bChangParamIn = FALSE;
|
bChangParamIn = FALSE;
|
||||||
|
@ -98,7 +96,7 @@ bool CSound::Read ( CVector<short>& psData )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// copy data from sound card in output buffer
|
// copy data from sound card in output buffer
|
||||||
for ( i = 0; i < iBufferSizeIn; i++ )
|
for ( i = 0; i < iBufferSize; i++ )
|
||||||
{
|
{
|
||||||
psData[i] = psSoundcardBuffer[iWhichBufferIn][i];
|
psData[i] = psSoundcardBuffer[iWhichBufferIn][i];
|
||||||
}
|
}
|
||||||
|
@ -147,106 +145,6 @@ void CSound::PrepareInBuffer ( int iBufNum )
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSound::InitRecording ( int iNewBufferSize, bool bNewBlocking )
|
|
||||||
{
|
|
||||||
// check if device must be opened or reinitialized
|
|
||||||
if ( bChangParamIn == TRUE )
|
|
||||||
{
|
|
||||||
OpenInDevice();
|
|
||||||
|
|
||||||
// reset flag
|
|
||||||
bChangParamIn = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set internal parameter
|
|
||||||
iBufferSizeIn = iNewBufferSize;
|
|
||||||
bBlockingRec = bNewBlocking;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// reset interface so that all buffers are returned from the interface
|
|
||||||
waveInReset ( m_WaveIn );
|
|
||||||
waveInStop ( m_WaveIn );
|
|
||||||
*/
|
|
||||||
|
|
||||||
// reset current buffer ID (it is important to do this BEFORE calling
|
|
||||||
// "AddInBuffer()"
|
|
||||||
iWhichBufferIn = 0;
|
|
||||||
|
|
||||||
// create memory for sound card buffer
|
|
||||||
for ( int i = 0; i < iCurNumSndBufIn; i++ )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
// Unprepare old wave-header in case that we "re-initialized" this
|
|
||||||
// module. Calling "waveInUnprepareHeader()" with an unprepared
|
|
||||||
// buffer (when the module is initialized for the first time) has
|
|
||||||
// simply no effect
|
|
||||||
waveInUnprepareHeader ( m_WaveIn, &m_WaveInHeader[i], sizeof ( WAVEHDR ) );
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( psSoundcardBuffer[i] != NULL )
|
|
||||||
{
|
|
||||||
delete[] psSoundcardBuffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
psSoundcardBuffer[i] = new short[iBufferSizeIn];
|
|
||||||
|
|
||||||
|
|
||||||
/* Send all buffers to driver for filling the queue ----------------- */
|
|
||||||
// prepare buffers before sending them to the sound interface
|
|
||||||
PrepareInBuffer ( i );
|
|
||||||
|
|
||||||
AddInBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// notify that sound capturing can start now
|
|
||||||
waveInStart ( m_WaveIn );
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This reset event is very important for initialization, otherwise we will
|
|
||||||
// get errors!
|
|
||||||
ResetEvent ( m_WaveInEvent );
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::OpenInDevice()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
// open wave-input and set call-back mechanism to event handle
|
|
||||||
if ( m_WaveIn != NULL )
|
|
||||||
{
|
|
||||||
waveInReset ( m_WaveIn );
|
|
||||||
waveInClose ( m_WaveIn );
|
|
||||||
}
|
|
||||||
|
|
||||||
MMRESULT result = waveInOpen ( &m_WaveIn, iCurInDev, &sWaveFormatEx,
|
|
||||||
(DWORD) m_WaveInEvent, NULL, CALLBACK_EVENT );
|
|
||||||
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface Start, waveInOpen() failed. This error "
|
|
||||||
"usually occurs if another application blocks the sound in." );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::SetInDev ( int iNewDev )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
// set device to wave mapper if iNewDev is invalid
|
|
||||||
if ( ( iNewDev >= iNumDevs ) || ( iNewDev < 0 ) )
|
|
||||||
{
|
|
||||||
iNewDev = WAVE_MAPPER;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// change only in case new device id is not already active
|
|
||||||
if ( iNewDev != iCurInDev )
|
|
||||||
{
|
|
||||||
iCurInDev = iNewDev;
|
|
||||||
bChangParamIn = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::SetInNumBuf ( int iNewNum )
|
void CSound::SetInNumBuf ( int iNewNum )
|
||||||
{
|
{
|
||||||
// check new parameter
|
// check new parameter
|
||||||
|
@ -277,10 +175,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 == TRUE )
|
if ( bChangParamOut == TRUE )
|
||||||
{
|
{
|
||||||
OpenOutDevice();
|
|
||||||
|
|
||||||
// reinit sound interface
|
// reinit sound interface
|
||||||
InitPlayback ( iBufferSizeOut, bBlockingPlay );
|
InitRecordingAndPlayback ( iBufferSize );
|
||||||
|
|
||||||
// reset flag
|
// reset flag
|
||||||
bChangParamOut = FALSE;
|
bChangParamOut = FALSE;
|
||||||
|
@ -292,24 +188,14 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
// now check special cases (Buffer is full or empty)
|
// now check special cases (Buffer is full or empty)
|
||||||
if ( iCntPrepBuf == 0 )
|
if ( iCntPrepBuf == 0 )
|
||||||
{
|
{
|
||||||
if ( bBlockingPlay == TRUE )
|
/* Blocking wave out routine. Needed for transmitter. Always
|
||||||
|
ensure that the buffer is completely filled to avoid buffer
|
||||||
|
underruns */
|
||||||
|
while ( iCntPrepBuf == 0 )
|
||||||
{
|
{
|
||||||
/* Blocking wave out routine. Needed for transmitter. Always
|
WaitForSingleObject ( m_WaveOutEvent, INFINITE );
|
||||||
ensure that the buffer is completely filled to avoid buffer
|
|
||||||
underruns */
|
|
||||||
while ( iCntPrepBuf == 0 )
|
|
||||||
{
|
|
||||||
WaitForSingleObject ( m_WaveOutEvent, INFINITE );
|
|
||||||
|
|
||||||
GetDoneBuffer ( iCntPrepBuf, iIndexDoneBuf );
|
GetDoneBuffer ( iCntPrepBuf, iIndexDoneBuf );
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* All buffers are filled, dump new block ----------------------- */
|
|
||||||
// It would be better to kill half of the buffer blocks to set the start
|
|
||||||
// back to the middle: TODO
|
|
||||||
return TRUE; // an error occurred
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -323,7 +209,7 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
for ( j = 0; j < iCurNumSndBufOut / 2; j++ )
|
for ( j = 0; j < iCurNumSndBufOut / 2; j++ )
|
||||||
{
|
{
|
||||||
// first, clear these buffers
|
// first, clear these buffers
|
||||||
for ( i = 0; i < iBufferSizeOut; i++ )
|
for ( i = 0; i < iBufferSize; i++ )
|
||||||
{
|
{
|
||||||
psPlaybackBuffer[j][i] = 0;
|
psPlaybackBuffer[j][i] = 0;
|
||||||
}
|
}
|
||||||
|
@ -344,7 +230,7 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy stereo data from input in soundcard buffer
|
// copy stereo data from input in soundcard buffer
|
||||||
for ( i = 0; i < iBufferSizeOut; i++ )
|
for ( i = 0; i < iBufferSize; i++ )
|
||||||
{
|
{
|
||||||
psPlaybackBuffer[iIndexDoneBuf][i] = psData[i];
|
psPlaybackBuffer[iIndexDoneBuf][i] = psData[i];
|
||||||
}
|
}
|
||||||
|
@ -399,95 +285,6 @@ void CSound::PrepareOutBuffer ( int iBufNum )
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSound::InitPlayback ( int iNewBufferSize, bool bNewBlocking )
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
// check if device must be opened or reinitialized
|
|
||||||
if ( bChangParamOut == TRUE )
|
|
||||||
{
|
|
||||||
OpenOutDevice();
|
|
||||||
|
|
||||||
// reset flag
|
|
||||||
bChangParamOut = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set internal parameters
|
|
||||||
iBufferSizeOut = iNewBufferSize;
|
|
||||||
bBlockingPlay = bNewBlocking;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// reset interface
|
|
||||||
waveOutReset ( m_WaveOut );
|
|
||||||
*/
|
|
||||||
|
|
||||||
for ( j = 0; j < iCurNumSndBufOut; j++ )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
// Unprepare old wave-header (in case header was not prepared before,
|
|
||||||
// simply nothing happens with this function call
|
|
||||||
waveOutUnprepareHeader ( m_WaveOut, &m_WaveOutHeader[j], sizeof ( WAVEHDR ) );
|
|
||||||
*/
|
|
||||||
|
|
||||||
// create memory for playback buffer
|
|
||||||
if ( psPlaybackBuffer[j] != NULL )
|
|
||||||
{
|
|
||||||
delete[] psPlaybackBuffer[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
psPlaybackBuffer[j] = new short[iBufferSizeOut];
|
|
||||||
|
|
||||||
// clear new buffer
|
|
||||||
for ( i = 0; i < iBufferSizeOut; i++ )
|
|
||||||
{
|
|
||||||
psPlaybackBuffer[j][i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare buffer for sending to the sound interface
|
|
||||||
PrepareOutBuffer ( j );
|
|
||||||
|
|
||||||
// initially, send all buffers to the interface
|
|
||||||
AddOutBuffer ( j );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::OpenOutDevice()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if ( m_WaveOut != NULL )
|
|
||||||
{
|
|
||||||
waveOutReset ( m_WaveOut );
|
|
||||||
waveOutClose ( m_WaveOut );
|
|
||||||
}
|
|
||||||
|
|
||||||
MMRESULT result = waveOutOpen ( &m_WaveOut, iCurOutDev, &sWaveFormatEx,
|
|
||||||
(DWORD) m_WaveOutEvent, NULL, CALLBACK_EVENT );
|
|
||||||
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface Start, waveOutOpen() failed." );
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::SetOutDev ( int iNewDev )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
// set device to wave mapper if iNewDev is invalid
|
|
||||||
if ( ( iNewDev >= iNumDevs ) || ( iNewDev < 0 ) )
|
|
||||||
{
|
|
||||||
iNewDev = WAVE_MAPPER;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// change only in case new device id is not already active
|
|
||||||
if ( iNewDev != iCurOutDev )
|
|
||||||
{
|
|
||||||
iCurOutDev = iNewDev;
|
|
||||||
bChangParamOut = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::SetOutNumBuf ( int iNewNum )
|
void CSound::SetOutNumBuf ( int iNewNum )
|
||||||
{
|
{
|
||||||
// check new parameter
|
// check new parameter
|
||||||
|
@ -508,35 +305,128 @@ void CSound::SetOutNumBuf ( int iNewNum )
|
||||||
/******************************************************************************\
|
/******************************************************************************\
|
||||||
* Common *
|
* Common *
|
||||||
\******************************************************************************/
|
\******************************************************************************/
|
||||||
void CSound::Close()
|
void CSound::InitRecordingAndPlayback ( int iNewBufferSize )
|
||||||
{
|
{
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
|
// first, stop audio
|
||||||
|
ASIOStop();
|
||||||
|
|
||||||
|
// set internal parameters
|
||||||
|
iBufferSize = iNewBufferSize;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MMRESULT result;
|
// reset interface so that all buffers are returned from the interface
|
||||||
|
waveInReset ( m_WaveIn );
|
||||||
// reset audio driver
|
waveInStop ( m_WaveIn );
|
||||||
if ( m_WaveOut != NULL )
|
|
||||||
{
|
|
||||||
result = waveOutReset ( m_WaveOut );
|
|
||||||
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface, waveOutReset() failed." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_WaveIn != NULL )
|
|
||||||
{
|
|
||||||
result = waveInReset ( m_WaveIn );
|
|
||||||
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface, waveInReset() failed." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// reset current buffer ID (it is important to do this BEFORE calling
|
||||||
|
// "AddInBuffer()"
|
||||||
|
iWhichBufferIn = 0;
|
||||||
|
|
||||||
|
// create memory for sound card buffer
|
||||||
|
for ( i = 0; i < iCurNumSndBufIn; i++ )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
// Unprepare old wave-header in case that we "re-initialized" this
|
||||||
|
// module. Calling "waveInUnprepareHeader()" with an unprepared
|
||||||
|
// buffer (when the module is initialized for the first time) has
|
||||||
|
// simply no effect
|
||||||
|
waveInUnprepareHeader ( m_WaveIn, &m_WaveInHeader[i], sizeof ( WAVEHDR ) );
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( psSoundcardBuffer[i] != NULL )
|
||||||
|
{
|
||||||
|
delete[] psSoundcardBuffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
psSoundcardBuffer[i] = new short[iBufferSize];
|
||||||
|
|
||||||
|
|
||||||
|
/* Send all buffers to driver for filling the queue ----------------- */
|
||||||
|
// prepare buffers before sending them to the sound interface
|
||||||
|
PrepareInBuffer ( i );
|
||||||
|
|
||||||
|
AddInBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// notify that sound capturing can start now
|
||||||
|
waveInStart ( m_WaveIn );
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This reset event is very important for initialization, otherwise we will
|
||||||
|
// get errors!
|
||||||
|
ResetEvent ( m_WaveInEvent );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO this should be done in the setinoutbuf functions
|
||||||
|
// create and activate buffers
|
||||||
|
// ASIOCreateBuffers(bufferInfos, 2 * NUM_IN_OUT_CHANNELS,
|
||||||
|
// iBufferSizeIn * BYTES_PER_SAMPLE, &asioCallbacks);
|
||||||
|
ASIOCreateBuffers(bufferInfos, 2 * NUM_IN_OUT_CHANNELS,
|
||||||
|
iBufferSize * BYTES_PER_SAMPLE, &asioCallbacks);
|
||||||
|
|
||||||
|
// now set all the buffer details
|
||||||
|
for ( i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ )
|
||||||
|
{
|
||||||
|
channelInfos[i].channel = NUM_IN_OUT_CHANNELS;
|
||||||
|
channelInfos[i].isInput = bufferInfos[i].isInput;
|
||||||
|
ASIOGetChannelInfo ( &channelInfos[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// reset interface
|
||||||
|
waveOutReset ( m_WaveOut );
|
||||||
|
*/
|
||||||
|
|
||||||
|
for ( j = 0; j < iCurNumSndBufOut; j++ )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
// Unprepare old wave-header (in case header was not prepared before,
|
||||||
|
// simply nothing happens with this function call
|
||||||
|
waveOutUnprepareHeader ( m_WaveOut, &m_WaveOutHeader[j], sizeof ( WAVEHDR ) );
|
||||||
|
*/
|
||||||
|
|
||||||
|
// create memory for playback buffer
|
||||||
|
if ( psPlaybackBuffer[j] != NULL )
|
||||||
|
{
|
||||||
|
delete[] psPlaybackBuffer[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
psPlaybackBuffer[j] = new short[iBufferSize];
|
||||||
|
|
||||||
|
// clear new buffer
|
||||||
|
for ( i = 0; i < iBufferSize; i++ )
|
||||||
|
{
|
||||||
|
psPlaybackBuffer[j][i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare buffer for sending to the sound interface
|
||||||
|
PrepareOutBuffer ( j );
|
||||||
|
|
||||||
|
// initially, send all buffers to the interface
|
||||||
|
AddOutBuffer ( j );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// initialization is done, (re)start audio
|
||||||
|
ASIOStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSound::Close()
|
||||||
|
{
|
||||||
// set event to ensure that thread leaves the waiting function
|
// set event to ensure that thread leaves the waiting function
|
||||||
if ( m_WaveInEvent != NULL )
|
if ( m_WaveInEvent != NULL )
|
||||||
{
|
{
|
||||||
|
@ -546,53 +436,6 @@ void CSound::Close()
|
||||||
// wait for the thread to terminate
|
// wait for the thread to terminate
|
||||||
Sleep ( 500 );
|
Sleep ( 500 );
|
||||||
|
|
||||||
/*
|
|
||||||
// unprepare wave-headers
|
|
||||||
if ( m_WaveIn != NULL )
|
|
||||||
{
|
|
||||||
for ( i = 0; i < iCurNumSndBufIn; i++ )
|
|
||||||
{
|
|
||||||
result = waveInUnprepareHeader (
|
|
||||||
m_WaveIn, &m_WaveInHeader[i], sizeof ( WAVEHDR ) );
|
|
||||||
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface, waveInUnprepareHeader()"
|
|
||||||
" failed." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// close the sound in device
|
|
||||||
result = waveInClose ( m_WaveIn );
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface, waveInClose() failed." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_WaveOut != NULL )
|
|
||||||
{
|
|
||||||
for ( i = 0; i < iCurNumSndBufOut; i++ )
|
|
||||||
{
|
|
||||||
result = waveOutUnprepareHeader (
|
|
||||||
m_WaveOut, &m_WaveOutHeader[i], sizeof ( WAVEHDR ) );
|
|
||||||
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface, waveOutUnprepareHeader()"
|
|
||||||
" failed." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// close the sound out device
|
|
||||||
result = waveOutClose ( m_WaveOut );
|
|
||||||
if ( result != MMSYSERR_NOERROR )
|
|
||||||
{
|
|
||||||
throw CGenErr ( "Sound Interface, waveOutClose() failed." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// set flag to open devices the next time it is initialized
|
// set flag to open devices the next time it is initialized
|
||||||
bChangParamIn = TRUE;
|
bChangParamIn = TRUE;
|
||||||
bChangParamOut = TRUE;
|
bChangParamOut = TRUE;
|
||||||
|
@ -606,44 +449,9 @@ CSound::CSound()
|
||||||
iCurNumSndBufIn = NUM_SOUND_BUFFERS_IN;
|
iCurNumSndBufIn = NUM_SOUND_BUFFERS_IN;
|
||||||
iCurNumSndBufOut = NUM_SOUND_BUFFERS_OUT;
|
iCurNumSndBufOut = NUM_SOUND_BUFFERS_OUT;
|
||||||
|
|
||||||
/*
|
|
||||||
// should be initialized because an error can occur during init
|
// should be initialized because an error can occur during init
|
||||||
m_WaveInEvent = NULL;
|
m_WaveInEvent = NULL;
|
||||||
m_WaveOutEvent = NULL;
|
m_WaveOutEvent = NULL;
|
||||||
m_WaveIn = NULL;
|
|
||||||
m_WaveOut = NULL;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// init buffer pointer to zero
|
|
||||||
for ( i = 0; i < MAX_SND_BUF_IN; i++ )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
memset ( &m_WaveInHeader[i], 0, sizeof ( WAVEHDR ) );
|
|
||||||
*/
|
|
||||||
psSoundcardBuffer[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i = 0; i < MAX_SND_BUF_OUT; i++ )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
memset ( &m_WaveOutHeader[i], 0, sizeof ( WAVEHDR ) );
|
|
||||||
*/
|
|
||||||
psPlaybackBuffer[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// init wave-format structure
|
|
||||||
sWaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
sWaveFormatEx.nChannels = NUM_IN_OUT_CHANNELS;
|
|
||||||
sWaveFormatEx.wBitsPerSample = BITS_PER_SAMPLE;
|
|
||||||
sWaveFormatEx.nSamplesPerSec = SND_CRD_SAMPLE_RATE;
|
|
||||||
sWaveFormatEx.nBlockAlign = sWaveFormatEx.nChannels *
|
|
||||||
sWaveFormatEx.wBitsPerSample / 8;
|
|
||||||
sWaveFormatEx.nAvgBytesPerSec = sWaveFormatEx.nBlockAlign *
|
|
||||||
sWaveFormatEx.nSamplesPerSec;
|
|
||||||
sWaveFormatEx.cbSize = 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// get available ASIO driver names in system
|
// get available ASIO driver names in system
|
||||||
char* cDriverNames[MAX_NUMBER_SOUND_CARDS];
|
char* cDriverNames[MAX_NUMBER_SOUND_CARDS];
|
||||||
|
@ -692,49 +500,94 @@ pstrDevices[0] = driverInfo.name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// check the number of available channels
|
||||||
// TEST !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
long lNumInChan;
|
||||||
ASIOExit();
|
long lNumOutChan;
|
||||||
|
ASIOGetChannels ( &lNumInChan, &lNumOutChan );
|
||||||
|
if ( ( lNumInChan != NUM_IN_OUT_CHANNELS ) || ( lNumOutChan != NUM_IN_OUT_CHANNELS ) )
|
||||||
|
|
||||||
/*
|
|
||||||
// get info about the devices and store the names
|
|
||||||
for ( i = 0; i < iNumDevs; i++ )
|
|
||||||
{
|
{
|
||||||
if ( !waveInGetDevCaps ( i, &m_WaveInDevCaps, sizeof ( WAVEINCAPS ) ) )
|
throw CGenErr ( "The audio device does not support required number of channels." );
|
||||||
{
|
}
|
||||||
pstrDevices[i] = m_WaveInDevCaps.szPname;
|
|
||||||
}
|
// check the usable buffer sizes
|
||||||
|
long lMinSize;
|
||||||
|
long lMaxSize;
|
||||||
|
long lPreferredSize;
|
||||||
|
long lGranularity;
|
||||||
|
ASIOGetBufferSize ( &lMinSize, &lMaxSize, &lPreferredSize, &lGranularity );
|
||||||
|
|
||||||
|
// TODO make use of the information...
|
||||||
|
|
||||||
|
|
||||||
|
// set the sample rate and check if sample rate is supported
|
||||||
|
ASIOSetSampleRate ( SND_CRD_SAMPLE_RATE );
|
||||||
|
|
||||||
|
ASIOSampleRate sampleRate;
|
||||||
|
ASIOGetSampleRate ( &sampleRate );
|
||||||
|
if ( sampleRate != SND_CRD_SAMPLE_RATE )
|
||||||
|
{
|
||||||
|
throw CGenErr ( "The audio device does not support required sample rate." );
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 );
|
||||||
|
|
||||||
|
// set up the asioCallback structure and create the ASIO data buffer
|
||||||
|
asioCallbacks.bufferSwitch = &bufferSwitch;
|
||||||
|
asioCallbacks.sampleRateDidChange = &sampleRateChanged;
|
||||||
|
asioCallbacks.asioMessage = &asioMessages;
|
||||||
|
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init buffer pointer to zero
|
||||||
|
for ( i = 0; i < MAX_SND_BUF_IN; i++ )
|
||||||
|
{
|
||||||
|
psSoundcardBuffer[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < MAX_SND_BUF_OUT; i++ )
|
||||||
|
{
|
||||||
|
psPlaybackBuffer[i] = NULL;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// we use an event controlled wave-in (wave-out) structure
|
// we use an event controlled wave-in (wave-out) structure
|
||||||
// create events
|
// create events
|
||||||
m_WaveInEvent = CreateEvent ( NULL, FALSE, FALSE, NULL );
|
m_WaveInEvent = CreateEvent ( NULL, FALSE, FALSE, NULL );
|
||||||
m_WaveOutEvent = CreateEvent ( NULL, FALSE, FALSE, NULL );
|
m_WaveOutEvent = CreateEvent ( NULL, FALSE, FALSE, NULL );
|
||||||
|
|
||||||
// set flag to open devices
|
// set flag to open devices
|
||||||
bChangParamIn = TRUE;
|
bChangParamIn = TRUE;
|
||||||
bChangParamOut = TRUE;
|
bChangParamOut = TRUE;
|
||||||
|
|
||||||
/*
|
|
||||||
// default device number, "wave mapper"
|
|
||||||
iCurInDev = WAVE_MAPPER;
|
|
||||||
iCurOutDev = WAVE_MAPPER;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// non-blocking wave out is default
|
|
||||||
bBlockingPlay = FALSE;
|
|
||||||
|
|
||||||
// blocking wave in is default
|
|
||||||
bBlockingRec = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSound::~CSound()
|
CSound::~CSound()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// cleanup ASIO stuff
|
||||||
|
ASIOStop();
|
||||||
|
ASIODisposeBuffers();
|
||||||
|
ASIOExit();
|
||||||
|
asioDrivers->removeCurrentDriver();
|
||||||
|
|
||||||
// delete allocated memory
|
// delete allocated memory
|
||||||
for ( i = 0; i < iCurNumSndBufIn; i++ )
|
for ( i = 0; i < iCurNumSndBufIn; i++ )
|
||||||
{
|
{
|
||||||
|
@ -766,6 +619,144 @@ CSound::~CSound()
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ASIO callbacks -------------------------------------------------------------
|
||||||
|
ASIOTime* CSound::bufferSwitchTimeInfo ( ASIOTime *timeInfo, long index, ASIOBool processNow )
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
static long processedSamples = 0;
|
||||||
|
|
||||||
|
// store the timeInfo for later use
|
||||||
|
asioDriverInfo.tInfo = *timeInfo;
|
||||||
|
|
||||||
|
// get the time stamp of the buffer, not necessary if no
|
||||||
|
// synchronization to other media is required
|
||||||
|
if (timeInfo->timeInfo.flags & kSystemTimeValid)
|
||||||
|
asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
|
||||||
|
else
|
||||||
|
asioDriverInfo.nanoSeconds = 0;
|
||||||
|
|
||||||
|
if (timeInfo->timeInfo.flags & kSamplePositionValid)
|
||||||
|
asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
|
||||||
|
else
|
||||||
|
asioDriverInfo.samples = 0;
|
||||||
|
|
||||||
|
if (timeInfo->timeCode.flags & kTcValid)
|
||||||
|
asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
|
||||||
|
else
|
||||||
|
asioDriverInfo.tcSamples = 0;
|
||||||
|
|
||||||
|
// get the system reference time
|
||||||
|
asioDriverInfo.sysRefTime = get_sys_reference_time();
|
||||||
|
|
||||||
|
#if WINDOWS && _DEBUG
|
||||||
|
// a few debug messages for the Windows device driver developer
|
||||||
|
// tells you the time when driver got its interrupt and the delay until the app receives
|
||||||
|
// the event notification.
|
||||||
|
static double last_samples = 0;
|
||||||
|
char tmp[128];
|
||||||
|
sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
|
||||||
|
OutputDebugString (tmp);
|
||||||
|
last_samples = asioDriverInfo.samples;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// buffer size in samples
|
||||||
|
long buffSize = asioDriverInfo.preferredSize;
|
||||||
|
|
||||||
|
// perform the processing
|
||||||
|
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
|
||||||
|
{
|
||||||
|
if (asioDriverInfo.bufferInfos[i].isInput == false)
|
||||||
|
{
|
||||||
|
// OK do processing for the outputs only
|
||||||
|
switch (asioDriverInfo.channelInfos[i].type)
|
||||||
|
{
|
||||||
|
case ASIOSTInt16LSB:
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
|
||||||
|
break;
|
||||||
|
case ASIOSTInt24LSB: // used for 20 bits as well
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
|
||||||
|
break;
|
||||||
|
case ASIOSTInt32LSB:
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||||
|
break;
|
||||||
|
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||||
|
break;
|
||||||
|
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||||
|
// 32 bit PCI bus systems can more easily used with these
|
||||||
|
case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment
|
||||||
|
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
|
||||||
|
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
|
||||||
|
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASIOSTInt16MSB:
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
|
||||||
|
break;
|
||||||
|
case ASIOSTInt24MSB: // used for 20 bits as well
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
|
||||||
|
break;
|
||||||
|
case ASIOSTInt32MSB:
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||||
|
break;
|
||||||
|
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||||
|
break;
|
||||||
|
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||||
|
// 32 bit PCI bus systems can more easily used with these
|
||||||
|
case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment
|
||||||
|
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
|
||||||
|
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
|
||||||
|
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
|
||||||
|
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
|
||||||
|
if (asioDriverInfo.postOutput)
|
||||||
|
ASIOOutputReady();
|
||||||
|
|
||||||
|
if (processedSamples >= asioDriverInfo.sampleRate * TEST_RUN_TIME) // roughly measured
|
||||||
|
asioDriverInfo.stopped = true;
|
||||||
|
else
|
||||||
|
processedSamples += buffSize;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSound::bufferSwitch( long index, ASIOBool processNow )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
long CSound::asioMessages ( long selector, long value, void* message, double* opt )
|
||||||
|
{
|
||||||
|
long ret = 0;
|
||||||
|
switch(selector)
|
||||||
|
{
|
||||||
|
case kAsioEngineVersion:
|
||||||
|
// return the supported ASIO version of the host application
|
||||||
|
ret = 2L;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#else // USE_ASIO_SND_INTERFACE
|
#else // USE_ASIO_SND_INTERFACE
|
||||||
|
|
||||||
/******************************************************************************\
|
/******************************************************************************\
|
||||||
|
|
|
@ -71,17 +71,17 @@ public:
|
||||||
CSound();
|
CSound();
|
||||||
virtual ~CSound();
|
virtual ~CSound();
|
||||||
|
|
||||||
void InitRecording ( int iNewBufferSize, bool bNewBlocking = TRUE );
|
void InitRecording ( int iNewBufferSize, bool bNewBlocking = TRUE ) { InitRecordingAndPlayback ( iNewBufferSize ); }
|
||||||
void InitPlayback ( int iNewBufferSize, bool bNewBlocking = FALSE );
|
void InitPlayback ( int iNewBufferSize, bool bNewBlocking = FALSE ) { InitRecordingAndPlayback ( iNewBufferSize ); }
|
||||||
bool Read ( CVector<short>& psData );
|
bool Read ( CVector<short>& psData );
|
||||||
bool Write ( CVector<short>& psData );
|
bool Write ( CVector<short>& psData );
|
||||||
|
|
||||||
int GetNumDev() { return iNumDevs; }
|
int GetNumDev() { return iNumDevs; }
|
||||||
std::string GetDeviceName ( int iDiD ) { return pstrDevices[iDiD]; }
|
std::string GetDeviceName ( int iDiD ) { return pstrDevices[iDiD]; }
|
||||||
void SetOutDev ( int iNewDev );
|
void SetOutDev ( int iNewDev ) {} // not supported
|
||||||
int GetOutDev() { return iCurOutDev; }
|
int GetOutDev() { return 0; } // not supported
|
||||||
void SetInDev ( int iNewDev );
|
void SetInDev ( int iNewDev ) {} // not supported
|
||||||
int GetInDev() { return iCurInDev; }
|
int GetInDev() { return 0; } // not supported
|
||||||
void SetOutNumBuf ( int iNewNum );
|
void SetOutNumBuf ( int iNewNum );
|
||||||
int GetOutNumBuf() { return iCurNumSndBufOut; }
|
int GetOutNumBuf() { return iCurNumSndBufOut; }
|
||||||
void SetInNumBuf ( int iNewNum );
|
void SetInNumBuf ( int iNewNum );
|
||||||
|
@ -90,8 +90,7 @@ public:
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OpenInDevice();
|
void InitRecordingAndPlayback ( int iNewBufferSize );
|
||||||
void OpenOutDevice();
|
|
||||||
void PrepareInBuffer ( int iBufNum );
|
void PrepareInBuffer ( int iBufNum );
|
||||||
void PrepareOutBuffer ( int iBufNum );
|
void PrepareOutBuffer ( int iBufNum );
|
||||||
void AddInBuffer();
|
void AddInBuffer();
|
||||||
|
@ -100,29 +99,34 @@ protected:
|
||||||
|
|
||||||
// ASIO stuff
|
// ASIO stuff
|
||||||
ASIODriverInfo driverInfo;
|
ASIODriverInfo driverInfo;
|
||||||
|
ASIOBufferInfo bufferInfos[2 * NUM_IN_OUT_CHANNELS]; // for input and output buffers -> "2 *"
|
||||||
|
ASIOChannelInfo channelInfos[2 * NUM_IN_OUT_CHANNELS];
|
||||||
|
bool bASIOPostOutput;
|
||||||
|
ASIOCallbacks asioCallbacks;
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
static void bufferSwitch ( long index, ASIOBool processNow );
|
||||||
|
static ASIOTime* bufferSwitchTimeInfo ( ASIOTime *timeInfo, long index, ASIOBool processNow );
|
||||||
|
static void sampleRateChanged ( ASIOSampleRate sRate ) {}
|
||||||
|
static long asioMessages ( long selector, long value, void* message, double* opt );
|
||||||
|
|
||||||
int iNumDevs;
|
int iNumDevs;
|
||||||
std::string pstrDevices[MAX_NUMBER_SOUND_CARDS];
|
std::string pstrDevices[MAX_NUMBER_SOUND_CARDS];
|
||||||
int iCurInDev;
|
|
||||||
int iCurOutDev;
|
|
||||||
bool bChangParamIn;
|
bool bChangParamIn;
|
||||||
bool bChangParamOut;
|
bool bChangParamOut;
|
||||||
int iCurNumSndBufIn;
|
int iCurNumSndBufIn;
|
||||||
int iCurNumSndBufOut;
|
int iCurNumSndBufOut;
|
||||||
|
|
||||||
|
int iBufferSize;
|
||||||
|
|
||||||
// wave in
|
// wave in
|
||||||
HANDLE m_WaveInEvent;
|
HANDLE m_WaveInEvent;
|
||||||
int iBufferSizeIn;
|
|
||||||
int iWhichBufferIn;
|
int iWhichBufferIn;
|
||||||
short* psSoundcardBuffer[MAX_SND_BUF_IN];
|
short* psSoundcardBuffer[MAX_SND_BUF_IN];
|
||||||
bool bBlockingRec;
|
|
||||||
|
|
||||||
// wave out
|
// wave out
|
||||||
int iBufferSizeOut;
|
|
||||||
short* psPlaybackBuffer[MAX_SND_BUF_OUT];
|
short* psPlaybackBuffer[MAX_SND_BUF_OUT];
|
||||||
HANDLE m_WaveOutEvent;
|
HANDLE m_WaveOutEvent;
|
||||||
bool bBlockingPlay;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#else // USE_ASIO_SND_INTERFACE
|
#else // USE_ASIO_SND_INTERFACE
|
||||||
|
|
Loading…
Reference in a new issue