optimized PA processor for case when host and user buffer match by type and size, now host buffer pointer will be passed to user space directly, additional copying of audio input/output data is thus avoided.
asio: apply paNonInterleaved flag on host formats for callback mode (required for processor compatibility).
This commit is contained in:
parent
231eb48512
commit
1c289f924e
3 changed files with 137 additions and 58 deletions
|
|
@ -263,7 +263,10 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
|
|||
bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );
|
||||
|
||||
bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved));
|
||||
|
||||
tempInputBufferSize =
|
||||
bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
|
||||
|
|
@ -331,6 +334,10 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
|
|||
|
||||
bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved));
|
||||
|
||||
tempOutputBufferSize =
|
||||
bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
|
||||
|
||||
|
|
@ -495,6 +502,7 @@ void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->inputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->inputChannelCount );
|
||||
assert( bp->hostInputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
|
@ -509,6 +517,7 @@ void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->inputChannelCount );
|
||||
assert( !bp->hostInputIsInterleaved );
|
||||
|
||||
bp->hostInputChannels[0][channel].data = data;
|
||||
bp->hostInputChannels[0][channel].stride = 1;
|
||||
|
|
@ -544,6 +553,7 @@ void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->inputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->inputChannelCount );
|
||||
assert( bp->hostInputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
|
@ -558,6 +568,7 @@ void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->inputChannelCount );
|
||||
assert( !bp->hostInputIsInterleaved );
|
||||
|
||||
bp->hostInputChannels[1][channel].data = data;
|
||||
bp->hostInputChannels[1][channel].stride = 1;
|
||||
|
|
@ -605,6 +616,7 @@ void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->outputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->outputChannelCount );
|
||||
assert( bp->hostOutputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
|
@ -618,6 +630,7 @@ void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->outputChannelCount );
|
||||
assert( !bp->hostOutputIsInterleaved );
|
||||
|
||||
PaUtil_SetOutputChannel( bp, channel, data, 1 );
|
||||
}
|
||||
|
|
@ -653,6 +666,7 @@ void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->outputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->outputChannelCount );
|
||||
assert( bp->hostOutputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
|
@ -666,6 +680,7 @@ void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->outputChannelCount );
|
||||
assert( !bp->hostOutputIsInterleaved );
|
||||
|
||||
PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
|
||||
}
|
||||
|
|
@ -722,6 +737,8 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
unsigned long frameCount;
|
||||
unsigned long framesToGo = framesToProcess;
|
||||
unsigned long framesProcessed = 0;
|
||||
int skipOutputConvert = 0;
|
||||
int skipInputConvert = 0;
|
||||
|
||||
|
||||
if( *streamCallbackResult == paContinue )
|
||||
|
|
@ -738,18 +755,25 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
}
|
||||
else /* there are input channels */
|
||||
{
|
||||
/*
|
||||
could use more elaborate logic here and sometimes process
|
||||
buffers in-place.
|
||||
*/
|
||||
|
||||
|
||||
destBytePtr = (unsigned char *)bp->tempInputBuffer;
|
||||
|
||||
if( bp->userInputIsInterleaved )
|
||||
{
|
||||
destSampleStrideSamples = bp->inputChannelCount;
|
||||
destChannelStrideBytes = bp->bytesPerUserInputSample;
|
||||
userInput = bp->tempInputBuffer;
|
||||
|
||||
/* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */
|
||||
if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved )
|
||||
{
|
||||
userInput = hostInputChannels[0].data;
|
||||
destBytePtr = (unsigned char *)hostInputChannels[0].data;
|
||||
skipInputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
userInput = bp->tempInputBuffer;
|
||||
}
|
||||
}
|
||||
else /* user input is not interleaved */
|
||||
{
|
||||
|
|
@ -757,10 +781,21 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
|
||||
|
||||
/* setup non-interleaved ptrs */
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved )
|
||||
{
|
||||
bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
|
||||
i * bp->bytesPerUserInputSample * frameCount;
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
bp->tempInputBufferPtrs[i] = hostInputChannels[i].data;
|
||||
}
|
||||
skipInputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
|
||||
i * bp->bytesPerUserInputSample * frameCount;
|
||||
}
|
||||
}
|
||||
|
||||
userInput = bp->tempInputBufferPtrs;
|
||||
|
|
@ -778,19 +813,31 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
if( skipInputConvert )
|
||||
{
|
||||
bp->inputConverter( destBytePtr, destSampleStrideSamples,
|
||||
hostInputChannels[i].data,
|
||||
hostInputChannels[i].stride,
|
||||
frameCount, &bp->ditherGenerator );
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
/* advance src ptr for next iteration */
|
||||
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
|
||||
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
bp->inputConverter( destBytePtr, destSampleStrideSamples,
|
||||
hostInputChannels[i].data,
|
||||
hostInputChannels[i].stride,
|
||||
frameCount, &bp->ditherGenerator );
|
||||
|
||||
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
|
||||
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
|
||||
|
||||
/* advance src ptr for next iteration */
|
||||
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
|
||||
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
|
||||
/* advance src ptr for next iteration */
|
||||
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
|
||||
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -805,14 +852,34 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
{
|
||||
if( bp->userOutputIsInterleaved )
|
||||
{
|
||||
userOutput = bp->tempOutputBuffer;
|
||||
/* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */
|
||||
if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved )
|
||||
{
|
||||
userOutput = hostOutputChannels[0].data;
|
||||
skipOutputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
userOutput = bp->tempOutputBuffer;
|
||||
}
|
||||
}
|
||||
else /* user output is not interleaved */
|
||||
{
|
||||
for( i = 0; i < bp->outputChannelCount; ++i )
|
||||
if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved )
|
||||
{
|
||||
bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
|
||||
i * bp->bytesPerUserOutputSample * frameCount;
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data;
|
||||
}
|
||||
skipOutputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
|
||||
i * bp->bytesPerUserOutputSample * frameCount;
|
||||
}
|
||||
}
|
||||
|
||||
userOutput = bp->tempOutputBufferPtrs;
|
||||
|
|
@ -836,37 +903,45 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
|
||||
if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
|
||||
{
|
||||
/*
|
||||
could use more elaborate logic here and sometimes process
|
||||
buffers in-place.
|
||||
*/
|
||||
|
||||
srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
|
||||
if( skipOutputConvert )
|
||||
{
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
/* advance dest ptr for next iteration */
|
||||
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
|
||||
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if( bp->userOutputIsInterleaved )
|
||||
{
|
||||
srcSampleStrideSamples = bp->outputChannelCount;
|
||||
srcChannelStrideBytes = bp->bytesPerUserOutputSample;
|
||||
}
|
||||
else /* user output is not interleaved */
|
||||
{
|
||||
srcSampleStrideSamples = 1;
|
||||
srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
|
||||
}
|
||||
srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
|
||||
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
bp->outputConverter( hostOutputChannels[i].data,
|
||||
hostOutputChannels[i].stride,
|
||||
srcBytePtr, srcSampleStrideSamples,
|
||||
frameCount, &bp->ditherGenerator );
|
||||
if( bp->userOutputIsInterleaved )
|
||||
{
|
||||
srcSampleStrideSamples = bp->outputChannelCount;
|
||||
srcChannelStrideBytes = bp->bytesPerUserOutputSample;
|
||||
}
|
||||
else /* user output is not interleaved */
|
||||
{
|
||||
srcSampleStrideSamples = 1;
|
||||
srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
|
||||
}
|
||||
|
||||
srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
bp->outputConverter( hostOutputChannels[i].data,
|
||||
hostOutputChannels[i].stride,
|
||||
srcBytePtr, srcSampleStrideSamples,
|
||||
frameCount, &bp->ditherGenerator );
|
||||
|
||||
/* advance dest ptr for next iteration */
|
||||
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
|
||||
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
|
||||
}
|
||||
srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
|
||||
|
||||
/* advance dest ptr for next iteration */
|
||||
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
|
||||
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
framesProcessed += frameCount;
|
||||
|
|
|
|||
|
|
@ -256,6 +256,8 @@ typedef struct {
|
|||
|
||||
PaUtilHostBufferSizeMode hostBufferSizeMode;
|
||||
int useNonAdaptingProcess;
|
||||
int userOutputSampleFormatIsEqualToHost;
|
||||
int userInputSampleFormatIsEqualToHost;
|
||||
unsigned long framesPerTempBuffer;
|
||||
|
||||
unsigned int inputChannelCount;
|
||||
|
|
@ -287,12 +289,14 @@ typedef struct {
|
|||
|
||||
PaStreamCallbackFlags callbackStatusFlags;
|
||||
|
||||
int hostInputIsInterleaved;
|
||||
unsigned long hostInputFrameCount[2];
|
||||
PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors.
|
||||
pointers are NULL for half-duplex output processing.
|
||||
hostInputChannels[i].data is NULL when the caller
|
||||
calls PaUtil_SetNoInput()
|
||||
*/
|
||||
int hostOutputIsInterleaved;
|
||||
unsigned long hostOutputFrameCount[2];
|
||||
PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors.
|
||||
pointers are NULL for half-duplex input processing.
|
||||
|
|
|
|||
Loading…
Reference in a new issue