put ASIO member variables in class, prepared for ASIO input/output channel selection

This commit is contained in:
Volker Fischer 2010-03-19 20:23:31 +00:00
parent 29eb59d464
commit 9828ceec81
2 changed files with 557 additions and 511 deletions

View file

@ -33,24 +33,7 @@
extern AsioDrivers* asioDrivers;
bool loadAsioDriver ( char *name );
// TODO the following variables should be in the class definition but we cannot
// do it here since we have static callback functions which cannot access the
// class members :-(((
// ASIO stuff
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;
int iASIOBufferSizeMono;
int iASIOBufferSizeStereo;
CVector<int16_t> vecsTmpAudioSndCrdStereo;
QMutex ASIOMutex;
// TEST
// pointer to our sound object
CSound* pSound;
@ -115,7 +98,7 @@ QString CSound::SetDev ( const int iNewDev )
// the first available driver in the system. If this fails, too, we
// throw an error that no driver is available -> it does not make
// sense to start the llcon software if no audio hardware is
// available
// available.
if ( !LoadAndInitializeDriver ( iNewDev ).isEmpty() )
{
// loading and initializing the new driver failed, try to find
@ -257,43 +240,58 @@ QString CSound::CheckDeviceCapabilities()
// return error string
return tr ( "The audio device does not support the "
"required number of channels. The required number of channels "
"is: " ) + QString().setNum ( NUM_IN_OUT_CHANNELS );
"for input and output is: " ) +
QString().setNum ( NUM_IN_OUT_CHANNELS );
}
// check sample format
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ )
// clip number of input/output channels to our maximum
if ( lNumInChan > MAX_NUM_IN_OUT_CHANNELS )
{
// check all used input and output channels
channelInfos[i].channel = i % NUM_IN_OUT_CHANNELS;
if ( i < NUM_IN_OUT_CHANNELS )
{
channelInfos[i].isInput = ASIOTrue;
lNumInChan = MAX_NUM_IN_OUT_CHANNELS;
}
else
if ( lNumOutChan > MAX_NUM_IN_OUT_CHANNELS )
{
channelInfos[i].isInput = ASIOFalse;
lNumOutChan = MAX_NUM_IN_OUT_CHANNELS;
}
ASIOGetChannelInfo ( &channelInfos[i] );
// check supported sample formats
if ( ( channelInfos[i].type != ASIOSTInt16LSB ) &&
( channelInfos[i].type != ASIOSTInt24LSB ) &&
( channelInfos[i].type != ASIOSTInt32LSB ) &&
( channelInfos[i].type != ASIOSTFloat32LSB ) &&
( channelInfos[i].type != ASIOSTFloat64LSB ) &&
( channelInfos[i].type != ASIOSTInt32LSB16 ) &&
( channelInfos[i].type != ASIOSTInt32LSB18 ) &&
( channelInfos[i].type != ASIOSTInt32LSB20 ) &&
( channelInfos[i].type != ASIOSTInt32LSB24 ) &&
( channelInfos[i].type != ASIOSTInt16MSB ) &&
( channelInfos[i].type != ASIOSTInt24MSB ) &&
( channelInfos[i].type != ASIOSTInt32MSB ) &&
( channelInfos[i].type != ASIOSTFloat32MSB ) &&
( channelInfos[i].type != ASIOSTFloat64MSB ) &&
( channelInfos[i].type != ASIOSTInt32MSB16 ) &&
( channelInfos[i].type != ASIOSTInt32MSB18 ) &&
( channelInfos[i].type != ASIOSTInt32MSB20 ) &&
( channelInfos[i].type != ASIOSTInt32MSB24 ) )
// query channel infos for all available input channels
for ( int i = 0; i < lNumInChan; i++ )
{
// setup for input channels
channelInfosInput[i].isInput = ASIOTrue;
channelInfosInput[i].channel = i;
ASIOGetChannelInfo ( &channelInfosInput[i] );
// Check supported sample formats.
// Actually, it would be enough to have at least two channels which
// support the required sample format. But since we have support for
// all known sample types, the following check should always pass and
// therefore we throw the error message on any channel which does not
// fullfill the sample format requirement (quick hack solution).
if ( !CheckSampleTypeSupported ( channelInfosInput[i].type ) )
{
// return error string
return tr ( "Required audio sample format not available." );
}
}
// query channel infos for all available output channels
for ( int i = 0; i < lNumOutChan; i++ )
{
// setup for output channels
channelInfosOutput[i].isInput = ASIOFalse;
channelInfosOutput[i].channel = i;
ASIOGetChannelInfo ( &channelInfosOutput[i] );
// Check supported sample formats.
// Actually, it would be enough to have at least two channels which
// support the required sample format. But since we have support for
// all known sample types, the following check should always pass and
// therefore we throw the error message on any channel which does not
// fullfill the sample format requirement (quick hack solution).
if ( !CheckSampleTypeSupported ( channelInfosOutput[i].type ) )
{
// return error string
return tr ( "Required audio sample format not available." );
@ -435,6 +433,24 @@ int CSound::Init ( const int iNewPrefMonoBufferSize )
// create and activate ASIO buffers (buffer size in samples),
// dispose old buffers (if any)
ASIODisposeBuffers();
// init buffer infos, we always want to have two input and
// two output channels
for ( int i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
{
// prepare input channels
bufferInfos[i].isInput = ASIOTrue;
bufferInfos[i].channelNum = vSelectedInputChannels[i];
bufferInfos[i].buffers[0] = 0;
bufferInfos[i].buffers[1] = 0;
// prepare output channels
bufferInfos[NUM_IN_OUT_CHANNELS + i].isInput = ASIOFalse;
bufferInfos[NUM_IN_OUT_CHANNELS + i].channelNum = vSelectedOutputChannels[i];
bufferInfos[NUM_IN_OUT_CHANNELS + i].buffers[0] = 0;
bufferInfos[NUM_IN_OUT_CHANNELS + i].buffers[1] = 0;
}
ASIOCreateBuffers ( bufferInfos,
2 /* in/out */ * NUM_IN_OUT_CHANNELS /* stereo */,
iASIOBufferSizeMono, &asioCallbacks );
@ -467,14 +483,15 @@ void CSound::Stop()
}
CSound::CSound ( void (*fpNewCallback) ( CVector<int16_t>& psData, void* arg ), void* arg ) :
CSoundBase ( true, fpNewCallback, arg )
CSoundBase ( true, fpNewCallback, arg ),
vSelectedInputChannels ( NUM_IN_OUT_CHANNELS ),
vSelectedOutputChannels ( NUM_IN_OUT_CHANNELS )
{
int i;
// TEST
// init pointer to our sound object
pSound = this;
// get available ASIO driver names in system
for ( i = 0; i < MAX_NUMBER_SOUND_CARDS; i++ )
{
@ -500,22 +517,12 @@ pSound = this;
// init device index with illegal value to show that driver is not initialized
lCurDev = -1;
// init buffer infos, we always want to have two input and
// two output channels
for ( i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
{
// prepare input channels
bufferInfos[i].isInput = ASIOTrue;
bufferInfos[i].channelNum = i;
bufferInfos[i].buffers[0] = 0;
bufferInfos[i].buffers[1] = 0;
// prepare output channels
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 selected channel numbers with defaults: use first available
// channels for input and output
vSelectedInputChannels[0] = 0;
vSelectedInputChannels[1] = 1;
vSelectedOutputChannels[0] = 0;
vSelectedOutputChannels[1] = 1;
// set up the asioCallback structure
asioCallbacks.bufferSwitch = &bufferSwitch;
@ -542,336 +549,357 @@ ASIOTime* CSound::bufferSwitchTimeInfo ( ASIOTime* timeInfo,
return 0L;
}
bool CSound::CheckSampleTypeSupported ( const ASIOSampleType SamType )
{
// check for supported sample types
return ( ( SamType == ASIOSTInt16LSB ) ||
( SamType == ASIOSTInt24LSB ) ||
( SamType == ASIOSTInt32LSB ) ||
( SamType == ASIOSTFloat32LSB ) ||
( SamType == ASIOSTFloat64LSB ) ||
( SamType == ASIOSTInt32LSB16 ) ||
( SamType == ASIOSTInt32LSB18 ) ||
( SamType == ASIOSTInt32LSB20 ) ||
( SamType == ASIOSTInt32LSB24 ) ||
( SamType == ASIOSTInt16MSB ) ||
( SamType == ASIOSTInt24MSB ) ||
( SamType == ASIOSTInt32MSB ) ||
( SamType == ASIOSTFloat32MSB ) ||
( SamType == ASIOSTFloat64MSB ) ||
( SamType == ASIOSTInt32MSB16 ) ||
( SamType == ASIOSTInt32MSB18 ) ||
( SamType == ASIOSTInt32MSB20 ) ||
( SamType == ASIOSTInt32MSB24 ) );
}
void CSound::bufferSwitch ( long index, ASIOBool processNow )
{
int iCurSample;
ASIOMutex.lock(); // get mutex lock
{
// perform the processing for input and output
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo
pSound->ASIOMutex.lock(); // get mutex lock
{
if ( bufferInfos[i].isInput == ASIOTrue )
// CAPTURE -------------------------------------------------------------
for ( int i = 0; i < NUM_IN_OUT_CHANNELS; i++ )
{
// CAPTURE -----------------------------------------------------
const int iInChNum = i;
// copy new captured block in thread transfer buffer (copy
// mono data interleaved in stereo buffer)
switch ( channelInfos[i].type )
switch ( pSound->channelInfosInput[pSound->vSelectedInputChannels[i]].type )
{
case ASIOSTInt16LSB:
// no type conversion required, just copy operation
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
static_cast<int16_t*> ( bufferInfos[i].buffers[index] )[iCurSample];
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample];
}
break;
case ASIOSTInt24LSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
int iCurSam = 0;
memcpy ( &iCurSam, ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, 3 );
memcpy ( &iCurSam, ( (char*) pSound->bufferInfos[i].buffers[index] ) + iCurSample * 3, 3 );
iCurSam >>= 8;
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( iCurSam );
}
break;
case ASIOSTInt32LSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] >> 16 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] >> 16 );
}
break;
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( static_cast<float*> (
bufferInfos[i].buffers[index] )[iCurSample] * _MAXSHORT );
pSound->bufferInfos[i].buffers[index] )[iCurSample] * _MAXSHORT );
}
break;
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( static_cast<double*> (
bufferInfos[i].buffers[index] )[iCurSample] * _MAXSHORT );
pSound->bufferInfos[i].buffers[index] )[iCurSample] * _MAXSHORT );
}
break;
case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] & 0xFFFF );
pSound->bufferInfos[i].buffers[index] )[iCurSample] & 0xFFFF );
}
break;
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] & 0x3FFFF ) >> 2 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] & 0x3FFFF ) >> 2 );
}
break;
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] & 0xFFFFF ) >> 4 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] & 0xFFFFF ) >> 4 );
}
break;
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] & 0xFFFFFF ) >> 8 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] & 0xFFFFFF ) >> 8 );
}
break;
case ASIOSTInt16MSB:
// NOT YET TESTED
// flip bits
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
Flip16Bits ( ( static_cast<int16_t*> (
bufferInfos[i].buffers[index] ) )[iCurSample] );
pSound->bufferInfos[i].buffers[index] ) )[iCurSample] );
}
break;
case ASIOSTInt24MSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// because the bits are flipped, we do not have to perform the
// shift by 8 bits
int iCurSam = 0;
memcpy ( &iCurSam, ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, 3 );
memcpy ( &iCurSam, ( (char*) pSound->bufferInfos[i].buffers[index] ) + iCurSample * 3, 3 );
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
Flip16Bits ( static_cast<int16_t> ( iCurSam ) );
}
break;
case ASIOSTInt32MSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// flip bits and convert to 16 bit
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( Flip32Bits ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) >> 16 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) >> 16 );
}
break;
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( static_cast<float> (
Flip32Bits ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) ) * _MAXSHORT );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) ) * _MAXSHORT );
}
break;
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( static_cast<double> (
Flip64Bits ( static_cast<int64_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) ) * _MAXSHORT );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) ) * _MAXSHORT );
}
break;
case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( Flip32Bits ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) & 0xFFFF );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) & 0xFFFF );
}
break;
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( ( Flip32Bits ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) & 0x3FFFF ) >> 2 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) & 0x3FFFF ) >> 2 );
}
break;
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( ( Flip32Bits ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) & 0xFFFFF ) >> 4 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) & 0xFFFFF ) >> 4 );
}
break;
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iInChNum] =
static_cast<int16_t> ( ( Flip32Bits ( static_cast<int32_t*> (
bufferInfos[i].buffers[index] )[iCurSample] ) & 0xFFFFFF ) >> 8 );
pSound->bufferInfos[i].buffers[index] )[iCurSample] ) & 0xFFFFFF ) >> 8 );
}
break;
}
}
}
// call processing callback function
pSound->ProcessCallback ( vecsTmpAudioSndCrdStereo );
pSound->ProcessCallback ( pSound->vecsTmpAudioSndCrdStereo );
// perform the processing for input and output
for ( int i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) // stereo
// PLAYBACK ------------------------------------------------------------
for ( int i = NUM_IN_OUT_CHANNELS; i < 2 * NUM_IN_OUT_CHANNELS; i++ )
{
if ( bufferInfos[i].isInput != ASIOTrue )
{
// PLAYBACK ----------------------------------------------------
const int iOutChNum = i - NUM_IN_OUT_CHANNELS;
// copy data from sound card in output buffer (copy
// interleaved stereo data in mono sound card buffer)
switch ( channelInfos[i].type )
switch ( pSound->channelInfosOutput[pSound->vSelectedOutputChannels[iOutChNum]].type )
{
case ASIOSTInt16LSB:
// no type conversion required, just copy operation
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
static_cast<int16_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum];
static_cast<int16_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum];
}
break;
case ASIOSTInt24LSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert current sample in 24 bit format
int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
iCurSam <<= 8;
memcpy ( ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, &iCurSam, 3 );
memcpy ( ( (char*) pSound->bufferInfos[i].buffers[index] ) + iCurSample * 3, &iCurSam, 3 );
}
break;
case ASIOSTInt32LSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
( iCurSam << 16 );
}
break;
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
const float fCurSam = static_cast<float> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<float*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<float*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
fCurSam / _MAXSHORT;
}
break;
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
const double fCurSam = static_cast<double> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<double*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<double*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
fCurSam / _MAXSHORT;
}
break;
case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
iCurSam;
}
break;
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
( iCurSam << 2 );
}
break;
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
( iCurSam << 4 );
}
break;
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
( iCurSam << 8 );
}
break;
@ -879,47 +907,47 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow )
case ASIOSTInt16MSB:
// NOT YET TESTED
// flip bits
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
( (int16_t*) bufferInfos[i].buffers[index] )[iCurSample] =
Flip16Bits ( vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
( (int16_t*) pSound->bufferInfos[i].buffers[index] )[iCurSample] =
Flip16Bits ( pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
}
break;
case ASIOSTInt24MSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// because the bits are flipped, we do not have to perform the
// shift by 8 bits
int32_t iCurSam = static_cast<int32_t> ( Flip16Bits (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] ) );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] ) );
memcpy ( ( (char*) bufferInfos[i].buffers[index] ) + iCurSample * 3, &iCurSam, 3 );
memcpy ( ( (char*) pSound->bufferInfos[i].buffers[index] ) + iCurSample * 3, &iCurSam, 3 );
}
break;
case ASIOSTInt32MSB:
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit and flip bits
int iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
Flip32Bits ( iCurSam << 16 );
}
break;
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
const float fCurSam = static_cast<float> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<float*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<float*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<float> ( Flip32Bits ( static_cast<int32_t> (
fCurSam / _MAXSHORT ) ) );
}
@ -927,12 +955,12 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow )
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
const double fCurSam = static_cast<double> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<float*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<float*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<double> ( Flip64Bits ( static_cast<int64_t> (
fCurSam / _MAXSHORT ) ) );
}
@ -940,67 +968,66 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow )
case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
Flip32Bits ( iCurSam );
}
break;
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
Flip32Bits ( iCurSam << 2 );
}
break;
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
Flip32Bits ( iCurSam << 4 );
}
break;
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
// NOT YET TESTED
for ( iCurSample = 0; iCurSample < iASIOBufferSizeMono; iCurSample++ )
for ( iCurSample = 0; iCurSample < pSound->iASIOBufferSizeMono; iCurSample++ )
{
// convert to 32 bit
const int32_t iCurSam = static_cast<int32_t> (
vecsTmpAudioSndCrdStereo[2 * iCurSample + bufferInfos[i].channelNum] );
pSound->vecsTmpAudioSndCrdStereo[2 * iCurSample + iOutChNum] );
static_cast<int32_t*> ( bufferInfos[i].buffers[index] )[iCurSample] =
static_cast<int32_t*> ( pSound->bufferInfos[i].buffers[index] )[iCurSample] =
Flip32Bits ( iCurSam << 8 );
}
break;
}
}
}
// finally if the driver supports the ASIOOutputReady() optimization,
// do it here, all data are in place -----------------------------------
if ( bASIOPostOutput )
if ( pSound->bASIOPostOutput )
{
ASIOOutputReady();
}
}
ASIOMutex.unlock();
pSound->ASIOMutex.unlock();
}
long CSound::asioMessages ( long selector,

View file

@ -40,14 +40,14 @@
/* Definitions ****************************************************************/
#define NUM_IN_OUT_CHANNELS 2 /* Stereo recording (but we only
use one channel for recording) */
// stereo for input and output
#define NUM_IN_OUT_CHANNELS 2
#define MAX_SND_BUF_IN 100
#define MAX_SND_BUF_OUT 100
#define NUM_SOUND_BUFFERS_IN 4
#define NUM_SOUND_BUFFERS_OUT 4
// define the maximum number of audio channel for input/output we can store
// channel infos for (and therefore this is the maximum number of entries in
// the channel selection combo box regardless of the actual available number
// of channels by the audio device)
#define MAX_NUM_IN_OUT_CHANNELS 32
/* Classes ********************************************************************/
@ -74,6 +74,17 @@ protected:
QString LoadAndInitializeDriver ( int iIdx );
int GetActualBufferSize ( const int iDesiredBufferSizeMono );
QString CheckDeviceCapabilities();
bool CheckSampleTypeSupported ( const ASIOSampleType SamType );
int iASIOBufferSizeMono;
int iASIOBufferSizeStereo;
CVector<int> vSelectedInputChannels;
CVector<int> vSelectedOutputChannels;
CVector<int16_t> vecsTmpAudioSndCrdStereo;
QMutex ASIOMutex;
// utility functions
static int16_t Flip16Bits ( const int16_t iIn );
@ -89,6 +100,14 @@ protected:
long lGranularity;
} HWBufferInfo;
// ASIO stuff
ASIODriverInfo driverInfo;
ASIOBufferInfo bufferInfos[2 * NUM_IN_OUT_CHANNELS]; // for input and output buffers -> "2 *"
ASIOChannelInfo channelInfosInput[MAX_NUM_IN_OUT_CHANNELS];
ASIOChannelInfo channelInfosOutput[MAX_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 );