complete redesign of ASIO conversion buffers to have greater flexibility with different ASIO buffer sizes, not yet working correctly
This commit is contained in:
parent
33be3c0812
commit
2516cf62f9
2 changed files with 122 additions and 187 deletions
|
@ -78,13 +78,13 @@ void CSettings::ReadIniFile ( const QString& sFileName )
|
||||||
}
|
}
|
||||||
|
|
||||||
// sound card in number of buffers
|
// sound card in number of buffers
|
||||||
if ( GetNumericIniSet ( IniXMLDocument, "client", "audinbuf", 0, AUD_SLIDER_LENGTH, iValue ) )
|
if ( GetNumericIniSet ( IniXMLDocument, "client", "audinbuf", 1, AUD_SLIDER_LENGTH, iValue ) )
|
||||||
{
|
{
|
||||||
pClient->GetSndInterface()->SetInNumBuf( iValue );
|
pClient->GetSndInterface()->SetInNumBuf( iValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
// sound card out number of buffers
|
// sound card out number of buffers
|
||||||
if ( GetNumericIniSet ( IniXMLDocument, "client", "audoutbuf", 0, AUD_SLIDER_LENGTH, iValue ) )
|
if ( GetNumericIniSet ( IniXMLDocument, "client", "audoutbuf", 1, AUD_SLIDER_LENGTH, iValue ) )
|
||||||
{
|
{
|
||||||
pClient->GetSndInterface()->SetOutNumBuf ( iValue );
|
pClient->GetSndInterface()->SetOutNumBuf ( iValue );
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,21 +57,14 @@ int iASIOBufferSizeMono;
|
||||||
HANDLE m_ASIOEvent;
|
HANDLE m_ASIOEvent;
|
||||||
|
|
||||||
// wave in
|
// wave in
|
||||||
int iInCurBlockToWrite;
|
short* psCaptureBuffer;
|
||||||
short* psSoundcardBuffer[MAX_SND_BUF_IN];
|
int iBufferPosCapture;
|
||||||
bool bBufferOverrun;
|
bool bCaptureBufferOverrun;
|
||||||
|
|
||||||
// wave out
|
// wave out
|
||||||
int iOutCurBlockToWrite;
|
short* psPlayBuffer;
|
||||||
short* psPlaybackBuffer[MAX_SND_BUF_OUT];
|
int iBufferPosPlay;
|
||||||
bool bBufferUnderrun;
|
bool bPlayBufferUnderrun;
|
||||||
|
|
||||||
// ASIO buffer size conversion buffer
|
|
||||||
short* psCaptureConvBuf;
|
|
||||||
int iCurPosCaptConvBuf;
|
|
||||||
short* psPlayConvBuf;
|
|
||||||
int iCurPosPlayConvBuf;
|
|
||||||
int iASIOConfBufSize;
|
|
||||||
|
|
||||||
int iCurNumSndBufIn;
|
int iCurNumSndBufIn;
|
||||||
int iCurNumSndBufOut;
|
int iCurNumSndBufOut;
|
||||||
|
@ -79,8 +72,8 @@ int iNewNumSndBufIn;
|
||||||
int iNewNumSndBufOut;
|
int iNewNumSndBufOut;
|
||||||
|
|
||||||
// we must implement these functions here to get access to global variables
|
// we must implement these functions here to get access to global variables
|
||||||
int CSound::GetOutNumBuf() { return iCurNumSndBufOut; }
|
int CSound::GetOutNumBuf() { return iNewNumSndBufOut; }
|
||||||
int CSound::GetInNumBuf() { return iCurNumSndBufIn; }
|
int CSound::GetInNumBuf() { return iNewNumSndBufIn; }
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************\
|
/******************************************************************************\
|
||||||
|
@ -88,7 +81,7 @@ int CSound::GetInNumBuf() { return iCurNumSndBufIn; }
|
||||||
\******************************************************************************/
|
\******************************************************************************/
|
||||||
bool CSound::Read ( CVector<short>& psData )
|
bool CSound::Read ( CVector<short>& psData )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i;
|
||||||
bool bError;
|
bool bError;
|
||||||
|
|
||||||
// check if device must be opened or reinitialized
|
// check if device must be opened or reinitialized
|
||||||
|
@ -101,46 +94,44 @@ bool CSound::Read ( CVector<short>& psData )
|
||||||
bChangParamIn = false;
|
bChangParamIn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait until data is available
|
// wait until enough data is available
|
||||||
if ( iInCurBlockToWrite == 0 )
|
while ( iBufferPosCapture < iBufferSizeStereo )
|
||||||
{
|
{
|
||||||
if ( bBlockingRec )
|
if ( bBlockingRec && !bCaptureBufferOverrun )
|
||||||
{
|
{
|
||||||
WaitForSingleObject ( m_ASIOEvent, INFINITE );
|
WaitForSingleObject ( m_ASIOEvent, INFINITE );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASIOMutex.lock(); // get mutex lock
|
ASIOMutex.lock(); // get mutex lock
|
||||||
{
|
{
|
||||||
// check for buffer overrun in ASIO thread
|
// check for buffer overrun in ASIO thread
|
||||||
bError = bBufferOverrun;
|
bError = bCaptureBufferOverrun;
|
||||||
if ( bBufferOverrun )
|
if ( bCaptureBufferOverrun )
|
||||||
{
|
{
|
||||||
// reset flag
|
// reset flag
|
||||||
bBufferOverrun = false;
|
bCaptureBufferOverrun = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy data from sound card in output buffer
|
// copy data from sound card capture buffer in function output buffer
|
||||||
for ( i = 0; i < iBufferSizeStereo; i++ )
|
for ( i = 0; i < iBufferSizeStereo; i++ )
|
||||||
{
|
{
|
||||||
psData[i] = psSoundcardBuffer[0][i];
|
psData[i] = psCaptureBuffer[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// move all other data in buffer
|
// move all other data in buffer
|
||||||
for ( j = 0; j < iInCurBlockToWrite - 1; j++ )
|
const int iLenCopyRegion = iBufferPosCapture - iBufferSizeStereo;
|
||||||
|
for ( i = 0; i < iBufferSizeStereo; i++ )
|
||||||
{
|
{
|
||||||
for ( i = 0; i < iBufferSizeStereo; i++ )
|
psCaptureBuffer[i] = psCaptureBuffer[iBufferSizeStereo + i];
|
||||||
{
|
|
||||||
psSoundcardBuffer[j][i] = psSoundcardBuffer[j + 1][i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust "current block to write" pointer
|
// adjust "current block to write" pointer
|
||||||
iInCurBlockToWrite--;
|
iBufferPosCapture -= iBufferSizeStereo;
|
||||||
|
|
||||||
// in case more than one buffer was ready, reset event
|
// in case more than one buffer was ready, reset event
|
||||||
ResetEvent ( m_ASIOEvent );
|
ResetEvent ( m_ASIOEvent );
|
||||||
|
@ -187,29 +178,31 @@ bool CSound::Write ( CVector<short>& psData )
|
||||||
ASIOMutex.lock(); // get mutex lock
|
ASIOMutex.lock(); // get mutex lock
|
||||||
{
|
{
|
||||||
// check for buffer underrun in ASIO thread
|
// check for buffer underrun in ASIO thread
|
||||||
bError = bBufferUnderrun;
|
bError = bPlayBufferUnderrun;
|
||||||
if ( bBufferUnderrun )
|
if ( bPlayBufferUnderrun )
|
||||||
{
|
{
|
||||||
// reset flag
|
// reset flag
|
||||||
bBufferUnderrun = false;
|
bPlayBufferUnderrun = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first check if buffer is available
|
// first check if enough data in buffer is available
|
||||||
if ( iOutCurBlockToWrite < iCurNumSndBufOut )
|
const int iPlayBufferLen = iCurNumSndBufOut * iBufferSizeStereo;
|
||||||
{
|
|
||||||
// copy stereo data from input in soundcard buffer
|
|
||||||
for ( int i = 0; i < iBufferSizeStereo; i++ )
|
|
||||||
{
|
|
||||||
psPlaybackBuffer[iOutCurBlockToWrite][i] = psData[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
iOutCurBlockToWrite++;
|
if ( iBufferPosPlay + iBufferSizeStereo > iPlayBufferLen )
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// buffer overrun, return error
|
// buffer overrun, return error
|
||||||
bError = true;
|
bError = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// copy stereo data from function input in soundcard play buffer
|
||||||
|
for ( int i = 0; i < iBufferSizeStereo; i++ )
|
||||||
|
{
|
||||||
|
psPlayBuffer[iBufferPosPlay + i] = psData[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
iBufferPosPlay += iBufferSizeStereo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ASIOMutex.unlock();
|
ASIOMutex.unlock();
|
||||||
|
|
||||||
|
@ -238,7 +231,7 @@ void CSound::SetOutNumBuf ( int iNewNum )
|
||||||
\******************************************************************************/
|
\******************************************************************************/
|
||||||
void CSound::InitRecordingAndPlayback ( int iNewBufferSize )
|
void CSound::InitRecordingAndPlayback ( int iNewBufferSize )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i;
|
||||||
|
|
||||||
// first, stop audio and dispose ASIO buffers
|
// first, stop audio and dispose ASIO buffers
|
||||||
ASIOStop();
|
ASIOStop();
|
||||||
|
@ -313,13 +306,18 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST test if requested buffer size is supported by the audio hardware, if not, fire error
|
|
||||||
|
// TEST test if requested buffer size is supported by the audio hardware, if not, fire error
|
||||||
if ( iASIOBufferSizeMono != iBufferSizeMono )
|
if ( iASIOBufferSizeMono != iBufferSizeMono )
|
||||||
{
|
{
|
||||||
throw CGenErr ( QString ( "Required sound card buffer size of %1 samples "
|
throw CGenErr ( QString ( "Required sound card buffer size of %1 samples "
|
||||||
"not supported by the audio hardware." ).arg(iBufferSizeMono) );
|
"not supported by the audio hardware." ).arg(iBufferSizeMono) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
//iASIOBufferSizeMono = 256;
|
||||||
|
|
||||||
|
|
||||||
// prepare input channels
|
// prepare input channels
|
||||||
for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
|
for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
|
||||||
{
|
{
|
||||||
|
@ -363,63 +361,32 @@ if ( iASIOBufferSizeMono != iBufferSizeMono )
|
||||||
iCurNumSndBufOut = iNewNumSndBufOut;
|
iCurNumSndBufOut = iNewNumSndBufOut;
|
||||||
|
|
||||||
// initialize write block pointer in and overrun flag
|
// initialize write block pointer in and overrun flag
|
||||||
iInCurBlockToWrite = 0;
|
iBufferPosCapture = 0;
|
||||||
bBufferOverrun = false;
|
bCaptureBufferOverrun = false;
|
||||||
|
|
||||||
// create memory for sound card buffer
|
// create memory for capture buffer
|
||||||
for ( i = 0; i < iCurNumSndBufIn; i++ )
|
if ( psCaptureBuffer != NULL )
|
||||||
{
|
{
|
||||||
if ( psSoundcardBuffer[i] != NULL )
|
delete[] psCaptureBuffer;
|
||||||
{
|
}
|
||||||
delete[] psSoundcardBuffer[i];
|
psCaptureBuffer = new short[iCurNumSndBufIn * iBufferSizeStereo];
|
||||||
}
|
|
||||||
|
|
||||||
psSoundcardBuffer[i] = new short[iBufferSizeStereo];
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize write block pointer out and underrun flag
|
// initialize write block pointer out and underrun flag
|
||||||
iOutCurBlockToWrite = 0;
|
iBufferPosPlay = 0;
|
||||||
bBufferUnderrun = false;
|
bPlayBufferUnderrun = false;
|
||||||
|
|
||||||
// create memory for playback buffer
|
// create memory for play buffer
|
||||||
for ( j = 0; j < iCurNumSndBufOut; j++ )
|
if ( psPlayBuffer != NULL )
|
||||||
{
|
{
|
||||||
if ( psPlaybackBuffer[j] != NULL )
|
delete[] psPlayBuffer;
|
||||||
{
|
}
|
||||||
delete[] psPlaybackBuffer[j];
|
psPlayBuffer = new short[iCurNumSndBufOut * iBufferSizeStereo];
|
||||||
}
|
|
||||||
|
|
||||||
psPlaybackBuffer[j] = new short[iBufferSizeStereo];
|
// clear new buffer
|
||||||
|
for ( i = 0; i < iCurNumSndBufOut * iBufferSizeStereo; i++ )
|
||||||
// clear new buffer
|
{
|
||||||
for ( i = 0; i < iBufferSizeStereo; i++ )
|
psPlayBuffer[i] = 0;
|
||||||
{
|
}
|
||||||
psPlaybackBuffer[j][i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create memory for ASIO buffer conversion if required
|
|
||||||
if ( iASIOBufferSizeMono != iBufferSizeMono )
|
|
||||||
{
|
|
||||||
// required size: two times of one stereo buffer of the larger buffer
|
|
||||||
iASIOConfBufSize = max(4 * iASIOBufferSizeMono, 2 * iBufferSizeStereo);
|
|
||||||
|
|
||||||
if ( psCaptureConvBuf != NULL )
|
|
||||||
{
|
|
||||||
delete[] psCaptureConvBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
psCaptureConvBuf = new short[iASIOConfBufSize];
|
|
||||||
iCurPosCaptConvBuf = 0;
|
|
||||||
|
|
||||||
if ( psPlayConvBuf != NULL )
|
|
||||||
{
|
|
||||||
delete[] psPlayConvBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
psPlayConvBuf = new short[iASIOConfBufSize];
|
|
||||||
iCurPosPlayConvBuf = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset event
|
// reset event
|
||||||
ResetEvent ( m_ASIOEvent );
|
ResetEvent ( m_ASIOEvent );
|
||||||
|
@ -510,7 +477,6 @@ iNumDevs = 1;
|
||||||
pstrDevices[0] = driverInfo.name;
|
pstrDevices[0] = driverInfo.name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// check the number of available channels
|
// check the number of available channels
|
||||||
long lNumInChan;
|
long lNumInChan;
|
||||||
long lNumOutChan;
|
long lNumOutChan;
|
||||||
|
@ -518,7 +484,8 @@ pstrDevices[0] = driverInfo.name;
|
||||||
if ( ( lNumInChan < NUM_IN_OUT_CHANNELS ) ||
|
if ( ( lNumInChan < NUM_IN_OUT_CHANNELS ) ||
|
||||||
( lNumOutChan < NUM_IN_OUT_CHANNELS ) )
|
( lNumOutChan < NUM_IN_OUT_CHANNELS ) )
|
||||||
{
|
{
|
||||||
throw CGenErr ( "The audio device does not support required number of channels." );
|
throw CGenErr ( "The audio device does not support the "
|
||||||
|
"required number of channels." );
|
||||||
}
|
}
|
||||||
|
|
||||||
// query the usable buffer sizes
|
// query the usable buffer sizes
|
||||||
|
@ -534,7 +501,8 @@ pstrDevices[0] = driverInfo.name;
|
||||||
ASIOGetSampleRate ( &sampleRate );
|
ASIOGetSampleRate ( &sampleRate );
|
||||||
if ( sampleRate != SND_CRD_SAMPLE_RATE )
|
if ( sampleRate != SND_CRD_SAMPLE_RATE )
|
||||||
{
|
{
|
||||||
throw CGenErr ( "The audio device does not support required sample rate." );
|
throw CGenErr ( "The audio device does not support the "
|
||||||
|
"required sample rate." );
|
||||||
}
|
}
|
||||||
|
|
||||||
// check wether the driver requires the ASIOOutputReady() optimization
|
// check wether the driver requires the ASIOOutputReady() optimization
|
||||||
|
@ -548,19 +516,8 @@ pstrDevices[0] = driverInfo.name;
|
||||||
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
|
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
|
||||||
|
|
||||||
// init buffer pointer to zero
|
// init buffer pointer to zero
|
||||||
for ( i = 0; i < MAX_SND_BUF_IN; i++ )
|
psCaptureBuffer = NULL;
|
||||||
{
|
psPlayBuffer = NULL;
|
||||||
psSoundcardBuffer[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i = 0; i < MAX_SND_BUF_OUT; i++ )
|
|
||||||
{
|
|
||||||
psPlaybackBuffer[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// init ASIO convertion buffers
|
|
||||||
psCaptureConvBuf = NULL;
|
|
||||||
psPlayConvBuf = NULL;
|
|
||||||
|
|
||||||
// we use an event controlled structure
|
// we use an event controlled structure
|
||||||
// create event
|
// create event
|
||||||
|
@ -573,8 +530,6 @@ pstrDevices[0] = driverInfo.name;
|
||||||
|
|
||||||
CSound::~CSound()
|
CSound::~CSound()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
// cleanup ASIO stuff
|
// cleanup ASIO stuff
|
||||||
ASIOStop();
|
ASIOStop();
|
||||||
ASIODisposeBuffers();
|
ASIODisposeBuffers();
|
||||||
|
@ -582,21 +537,14 @@ CSound::~CSound()
|
||||||
asioDrivers->removeCurrentDriver();
|
asioDrivers->removeCurrentDriver();
|
||||||
|
|
||||||
// delete allocated memory
|
// delete allocated memory
|
||||||
for ( i = 0; i < iCurNumSndBufIn; i++ )
|
if ( psCaptureBuffer != NULL )
|
||||||
{
|
{
|
||||||
if ( psSoundcardBuffer[i] != NULL )
|
delete[] psCaptureBuffer;
|
||||||
{
|
}
|
||||||
delete[] psSoundcardBuffer[i];
|
if ( psPlayBuffer != NULL )
|
||||||
}
|
{
|
||||||
}
|
delete[] psPlayBuffer;
|
||||||
|
}
|
||||||
for ( i = 0; i < iCurNumSndBufOut; i++ )
|
|
||||||
{
|
|
||||||
if ( psPlaybackBuffer[i] != NULL )
|
|
||||||
{
|
|
||||||
delete[] psPlaybackBuffer[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// close the handle for the event
|
// close the handle for the event
|
||||||
if ( m_ASIOEvent != NULL )
|
if ( m_ASIOEvent != NULL )
|
||||||
|
@ -620,88 +568,75 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow )
|
||||||
|
|
||||||
ASIOMutex.lock(); // get mutex lock
|
ASIOMutex.lock(); // get mutex lock
|
||||||
{
|
{
|
||||||
// check if special treatment is required with buffer conversion
|
// first check buffer state of capture and play buffers
|
||||||
const bool bConvBufNeeded = ( iASIOBufferSizeMono != iBufferSizeMono );
|
const int iCaptureBufferLen = iCurNumSndBufIn * iBufferSizeStereo;
|
||||||
|
|
||||||
|
bCaptureBufferOverrun =
|
||||||
|
( iBufferPosCapture + 2 * iASIOBufferSizeMono > iCaptureBufferLen );
|
||||||
|
|
||||||
// TODO implementation of ASIO conversion buffer
|
bPlayBufferUnderrun = ( 2 * iASIOBufferSizeMono > iBufferPosPlay );
|
||||||
// psCaptureConvBuf
|
|
||||||
// iCurPosCaptConvBuf
|
|
||||||
// psPlayConvBuf
|
|
||||||
// iCurPosPlayConvBuf
|
|
||||||
|
|
||||||
|
// perform the processing for input and output
|
||||||
// perform the processing for input and output
|
|
||||||
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo
|
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo
|
||||||
{
|
{
|
||||||
if ( bufferInfos[i].isInput == ASIOFalse )
|
if ( bufferInfos[i].isInput == ASIOTrue )
|
||||||
{
|
{
|
||||||
|
// CAPTURE -----------------------------------------------------
|
||||||
|
// first check if space in buffer is available
|
||||||
|
if ( !bCaptureBufferOverrun )
|
||||||
|
{
|
||||||
|
// copy new captured block in thread transfer buffer
|
||||||
|
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
|
||||||
|
{
|
||||||
|
// copy mono data interleaved in stereo buffer
|
||||||
|
psCaptureBuffer[iBufferPosCapture +
|
||||||
|
2 * iCurSample + bufferInfos[i].channelNum] =
|
||||||
|
((short*) bufferInfos[i].buffers[index])[iCurSample];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// PLAYBACK ----------------------------------------------------
|
// PLAYBACK ----------------------------------------------------
|
||||||
if ( iOutCurBlockToWrite > 0 )
|
if ( !bPlayBufferUnderrun )
|
||||||
{
|
{
|
||||||
// copy data from sound card in output buffer
|
// copy data from sound card in output buffer
|
||||||
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
|
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
|
||||||
{
|
{
|
||||||
// copy interleaved stereo data in mono sound card buffer
|
// copy interleaved stereo data in mono sound card buffer
|
||||||
((short*) bufferInfos[i].buffers[index])[iCurSample] =
|
((short*) bufferInfos[i].buffers[index])[iCurSample] =
|
||||||
psPlaybackBuffer[0][2 * iCurSample + bufferInfos[i].channelNum];
|
psPlayBuffer[2 * iCurSample + bufferInfos[i].channelNum];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// CAPTURE -----------------------------------------------------
|
|
||||||
// first check if space in buffer is available
|
|
||||||
if ( iInCurBlockToWrite < iCurNumSndBufIn )
|
|
||||||
{
|
|
||||||
// copy new captured block in thread transfer buffer
|
|
||||||
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
|
|
||||||
{
|
|
||||||
// copy mono data interleaved in stereo buffer
|
|
||||||
psSoundcardBuffer[iInCurBlockToWrite][2 * iCurSample + bufferInfos[i].channelNum] =
|
|
||||||
((short*) bufferInfos[i].buffers[index])[iCurSample];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Manage thread interface buffers for input and output ----------------
|
// Manage thread interface buffers for input and output ----------------
|
||||||
// playback
|
// capture
|
||||||
if ( iOutCurBlockToWrite > 0 )
|
if ( !bCaptureBufferOverrun )
|
||||||
{
|
{
|
||||||
// move all other data in playback buffer
|
iBufferPosCapture += 2 * iASIOBufferSizeMono;
|
||||||
for ( int j = 0; j < iOutCurBlockToWrite - 1; j++ )
|
}
|
||||||
|
|
||||||
|
// play
|
||||||
|
if ( !bPlayBufferUnderrun )
|
||||||
|
{
|
||||||
|
// move all other data in play buffer
|
||||||
|
const int iLenCopyRegion = iBufferPosPlay - 2 * iASIOBufferSizeMono;
|
||||||
|
for ( iCurSample = 0; iCurSample < iLenCopyRegion; iCurSample++ )
|
||||||
{
|
{
|
||||||
for ( iCurSample = 0; iCurSample < iBufferSizeStereo; iCurSample++ )
|
psPlayBuffer[iCurSample] =
|
||||||
{
|
psPlayBuffer[2 * iASIOBufferSizeMono + iCurSample];
|
||||||
psPlaybackBuffer[j][iCurSample] =
|
|
||||||
psPlaybackBuffer[j + 1][iCurSample];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust "current block to write" pointer
|
// adjust "current block to write" pointer
|
||||||
iOutCurBlockToWrite--;
|
iBufferPosPlay -= 2 * iASIOBufferSizeMono;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// set buffer underrun flag
|
|
||||||
bBufferUnderrun = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// capture
|
|
||||||
if ( iInCurBlockToWrite < iCurNumSndBufIn )
|
|
||||||
{
|
|
||||||
iInCurBlockToWrite++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// set buffer overrun flag
|
|
||||||
bBufferOverrun = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally if the driver supports the ASIOOutputReady() optimization,
|
// finally if the driver supports the ASIOOutputReady() optimization,
|
||||||
// do it here, all data are in place
|
// do it here, all data are in place -----------------------------------
|
||||||
if ( bASIOPostOutput )
|
if ( bASIOPostOutput )
|
||||||
{
|
{
|
||||||
ASIOOutputReady();
|
ASIOOutputReady();
|
||||||
|
|
Loading…
Reference in a new issue