diff --git a/src/common/pa_process.c b/src/common/pa_process.c index 568c774..01a9ee2 100644 --- a/src/common/pa_process.c +++ b/src/common/pa_process.c @@ -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; iinputChannelCount; ++i ) + if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved ) { - bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + - i * bp->bytesPerUserInputSample * frameCount; + for( i=0; iinputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = hostInputChannels[i].data; + } + skipInputConvert = 1; + } + else + { + for( i=0; iinputChannelCount; ++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; iinputChannelCount; ++i ) + { + if( skipInputConvert ) { - bp->inputConverter( destBytePtr, destSampleStrideSamples, - hostInputChannels[i].data, - hostInputChannels[i].stride, - frameCount, &bp->ditherGenerator ); + for( i=0; iinputChannelCount; ++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; iinputChannelCount; ++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; ioutputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data; + } + skipOutputConvert = 1; + } + else + { + for( i=0; ioutputChannelCount; ++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; ioutputChannelCount; ++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; ioutputChannelCount; ++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; ioutputChannelCount; ++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; diff --git a/src/common/pa_process.h b/src/common/pa_process.h index 9aef25e..eb44749 100644 --- a/src/common/pa_process.h +++ b/src/common/pa_process.h @@ -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. diff --git a/src/hostapi/asio/pa_asio.cpp b/src/hostapi/asio/pa_asio.cpp index 01096cf..009fbfa 100644 --- a/src/hostapi/asio/pa_asio.cpp +++ b/src/hostapi/asio/pa_asio.cpp @@ -2528,8 +2528,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, else /* Using callback interface... */ { result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, - inputChannelCount, inputSampleFormat, hostInputSampleFormat, - outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + inputChannelCount, inputSampleFormat, (hostInputSampleFormat | paNonInterleaved), + outputChannelCount, outputSampleFormat, (hostOutputSampleFormat | paNonInterleaved), sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, streamCallback, userData );