diff options
Diffstat (limited to 'portaudio/src/common/pa_process.c')
-rw-r--r-- | portaudio/src/common/pa_process.c | 1831 |
1 files changed, 0 insertions, 1831 deletions
diff --git a/portaudio/src/common/pa_process.c b/portaudio/src/common/pa_process.c deleted file mode 100644 index 084cabb..0000000 --- a/portaudio/src/common/pa_process.c +++ /dev/null @@ -1,1831 +0,0 @@ -/* - * $Id$ - * Portable Audio I/O Library - * streamCallback <-> host buffer processing adapter - * - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2002 Ross Bencina, Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ - -/** @file - @ingroup common_src - - @brief Buffer Processor implementation. -*/ - - -#include <assert.h> -#include <string.h> /* memset() */ - -#include "pa_process.h" -#include "pa_util.h" - - -#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024 - -#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) ) - - -/* greatest common divisor - PGCD in French */ -static unsigned long GCD( unsigned long a, unsigned long b ) -{ - return (b==0) ? a : GCD( b, a%b); -} - -/* least common multiple - PPCM in French */ -static unsigned long LCM( unsigned long a, unsigned long b ) -{ - return (a*b) / GCD(a,b); -} - -#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b)) - -static unsigned long CalculateFrameShift( unsigned long M, unsigned long N ) -{ - unsigned long result = 0; - unsigned long i; - unsigned long lcm; - - assert( M > 0 ); - assert( N > 0 ); - - lcm = LCM( M, N ); - for( i = M; i < lcm; i += M ) - result = PA_MAX_( result, i % N ); - - return result; -} - - -PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, - int inputChannelCount, PaSampleFormat userInputSampleFormat, - PaSampleFormat hostInputSampleFormat, - int outputChannelCount, PaSampleFormat userOutputSampleFormat, - PaSampleFormat hostOutputSampleFormat, - double sampleRate, - PaStreamFlags streamFlags, - unsigned long framesPerUserBuffer, - unsigned long framesPerHostBuffer, - PaUtilHostBufferSizeMode hostBufferSizeMode, - PaStreamCallback *streamCallback, void *userData ) -{ - PaError result = paNoError; - PaError bytesPerSample; - unsigned long tempInputBufferSize, tempOutputBufferSize; - PaStreamFlags tempInputStreamFlags; - - if( streamFlags & paNeverDropInput ) - { - /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */ - if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) || - framesPerUserBuffer != paFramesPerBufferUnspecified ) - return paInvalidFlag; - } - - /* initialize buffer ptrs to zero so they can be freed if necessary in error */ - bp->tempInputBuffer = 0; - bp->tempInputBufferPtrs = 0; - bp->tempOutputBuffer = 0; - bp->tempOutputBufferPtrs = 0; - - bp->framesPerUserBuffer = framesPerUserBuffer; - bp->framesPerHostBuffer = framesPerHostBuffer; - - bp->inputChannelCount = inputChannelCount; - bp->outputChannelCount = outputChannelCount; - - bp->hostBufferSizeMode = hostBufferSizeMode; - - bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0; - bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0; - - if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */ - { - bp->useNonAdaptingProcess = 1; - bp->initialFramesInTempInputBuffer = 0; - bp->initialFramesInTempOutputBuffer = 0; - - if( hostBufferSizeMode == paUtilFixedHostBufferSize - || hostBufferSizeMode == paUtilBoundedHostBufferSize ) - { - bp->framesPerTempBuffer = framesPerHostBuffer; - } - else /* unknown host buffer size */ - { - bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_; - } - } - else - { - bp->framesPerTempBuffer = framesPerUserBuffer; - - if( hostBufferSizeMode == paUtilFixedHostBufferSize - && framesPerHostBuffer % framesPerUserBuffer == 0 ) - { - bp->useNonAdaptingProcess = 1; - bp->initialFramesInTempInputBuffer = 0; - bp->initialFramesInTempOutputBuffer = 0; - } - else - { - bp->useNonAdaptingProcess = 0; - - if( inputChannelCount > 0 && outputChannelCount > 0 ) - { - /* full duplex */ - if( hostBufferSizeMode == paUtilFixedHostBufferSize ) - { - unsigned long frameShift = - CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer ); - - if( framesPerUserBuffer > framesPerHostBuffer ) - { - bp->initialFramesInTempInputBuffer = frameShift; - bp->initialFramesInTempOutputBuffer = 0; - } - else - { - bp->initialFramesInTempInputBuffer = 0; - bp->initialFramesInTempOutputBuffer = frameShift; - } - } - else /* variable host buffer size, add framesPerUserBuffer latency */ - { - bp->initialFramesInTempInputBuffer = 0; - bp->initialFramesInTempOutputBuffer = framesPerUserBuffer; - } - } - else - { - /* half duplex */ - bp->initialFramesInTempInputBuffer = 0; - bp->initialFramesInTempOutputBuffer = 0; - } - } - } - - - bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; - bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; - - - if( inputChannelCount > 0 ) - { - bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat ); - if( bytesPerSample > 0 ) - { - bp->bytesPerHostInputSample = bytesPerSample; - } - else - { - result = bytesPerSample; - goto error; - } - - bytesPerSample = Pa_GetSampleSize( userInputSampleFormat ); - if( bytesPerSample > 0 ) - { - bp->bytesPerUserInputSample = bytesPerSample; - } - else - { - result = bytesPerSample; - goto error; - } - - /* Under the assumption that no ADC in existence delivers better than 24bits resolution, - we disable dithering when host input format is paInt32 and user format is paInt24, - since the host samples will just be padded with zeros anyway. */ - - tempInputStreamFlags = streamFlags; - if( !(tempInputStreamFlags & paDitherOff) /* dither is on */ - && (hostInputSampleFormat & paInt32) /* host input format is int32 */ - && (userInputSampleFormat & paInt24) /* user requested format is int24 */ ){ - - tempInputStreamFlags = tempInputStreamFlags | paDitherOff; - } - - bp->inputConverter = - PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags ); - - bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat ); - - bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; - - bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1; - - bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved)); - - tempInputBufferSize = - bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount; - - bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize ); - if( bp->tempInputBuffer == 0 ) - { - result = paInsufficientMemory; - goto error; - } - - if( bp->framesInTempInputBuffer > 0 ) - memset( bp->tempInputBuffer, 0, tempInputBufferSize ); - - if( userInputSampleFormat & paNonInterleaved ) - { - bp->tempInputBufferPtrs = - (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount ); - if( bp->tempInputBufferPtrs == 0 ) - { - result = paInsufficientMemory; - goto error; - } - } - - bp->hostInputChannels[0] = (PaUtilChannelDescriptor*) - PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2); - if( bp->hostInputChannels[0] == 0 ) - { - result = paInsufficientMemory; - goto error; - } - - bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount]; - } - - if( outputChannelCount > 0 ) - { - bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat ); - if( bytesPerSample > 0 ) - { - bp->bytesPerHostOutputSample = bytesPerSample; - } - else - { - result = bytesPerSample; - goto error; - } - - bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat ); - if( bytesPerSample > 0 ) - { - bp->bytesPerUserOutputSample = bytesPerSample; - } - else - { - result = bytesPerSample; - goto error; - } - - bp->outputConverter = - PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags ); - - bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat ); - - bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1; - - bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1; - - bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved)); - - tempOutputBufferSize = - bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount; - - bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize ); - if( bp->tempOutputBuffer == 0 ) - { - result = paInsufficientMemory; - goto error; - } - - if( bp->framesInTempOutputBuffer > 0 ) - memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); - - if( userOutputSampleFormat & paNonInterleaved ) - { - bp->tempOutputBufferPtrs = - (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount ); - if( bp->tempOutputBufferPtrs == 0 ) - { - result = paInsufficientMemory; - goto error; - } - } - - bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*) - PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 ); - if( bp->hostOutputChannels[0] == 0 ) - { - result = paInsufficientMemory; - goto error; - } - - bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount]; - } - - PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator ); - - bp->samplePeriod = 1. / sampleRate; - - bp->streamCallback = streamCallback; - bp->userData = userData; - - return result; - -error: - if( bp->tempInputBuffer ) - PaUtil_FreeMemory( bp->tempInputBuffer ); - - if( bp->tempInputBufferPtrs ) - PaUtil_FreeMemory( bp->tempInputBufferPtrs ); - - if( bp->hostInputChannels[0] ) - PaUtil_FreeMemory( bp->hostInputChannels[0] ); - - if( bp->tempOutputBuffer ) - PaUtil_FreeMemory( bp->tempOutputBuffer ); - - if( bp->tempOutputBufferPtrs ) - PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); - - if( bp->hostOutputChannels[0] ) - PaUtil_FreeMemory( bp->hostOutputChannels[0] ); - - return result; -} - - -void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp ) -{ - if( bp->tempInputBuffer ) - PaUtil_FreeMemory( bp->tempInputBuffer ); - - if( bp->tempInputBufferPtrs ) - PaUtil_FreeMemory( bp->tempInputBufferPtrs ); - - if( bp->hostInputChannels[0] ) - PaUtil_FreeMemory( bp->hostInputChannels[0] ); - - if( bp->tempOutputBuffer ) - PaUtil_FreeMemory( bp->tempOutputBuffer ); - - if( bp->tempOutputBufferPtrs ) - PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); - - if( bp->hostOutputChannels[0] ) - PaUtil_FreeMemory( bp->hostOutputChannels[0] ); -} - - -void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp ) -{ - unsigned long tempInputBufferSize, tempOutputBufferSize; - - bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; - bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; - - if( bp->framesInTempInputBuffer > 0 ) - { - tempInputBufferSize = - bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount; - memset( bp->tempInputBuffer, 0, tempInputBufferSize ); - } - - if( bp->framesInTempOutputBuffer > 0 ) - { - tempOutputBufferSize = - bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount; - memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); - } -} - - -unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bp ) -{ - return bp->initialFramesInTempInputBuffer; -} - - -unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bp ) -{ - return bp->initialFramesInTempOutputBuffer; -} - - -void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp, - unsigned long frameCount ) -{ - if( frameCount == 0 ) - bp->hostInputFrameCount[0] = bp->framesPerHostBuffer; - else - bp->hostInputFrameCount[0] = frameCount; -} - - -void PaUtil_SetNoInput( PaUtilBufferProcessor* bp ) -{ - assert( bp->inputChannelCount > 0 ); - - bp->hostInputChannels[0][0].data = 0; -} - - -void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data, unsigned int stride ) -{ - assert( channel < bp->inputChannelCount ); - - bp->hostInputChannels[0][channel].data = data; - bp->hostInputChannels[0][channel].stride = stride; -} - - -void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp, - unsigned int firstChannel, void *data, unsigned int channelCount ) -{ - unsigned int i; - unsigned int channel = firstChannel; - unsigned char *p = (unsigned char*)data; - - if( channelCount == 0 ) - channelCount = bp->inputChannelCount; - - assert( firstChannel < bp->inputChannelCount ); - assert( firstChannel + channelCount <= bp->inputChannelCount ); - assert( bp->hostInputIsInterleaved ); - - for( i=0; i< channelCount; ++i ) - { - bp->hostInputChannels[0][channel+i].data = p; - p += bp->bytesPerHostInputSample; - bp->hostInputChannels[0][channel+i].stride = channelCount; - } -} - - -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; -} - - -void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp, - unsigned long frameCount ) -{ - bp->hostInputFrameCount[1] = frameCount; -} - - -void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data, unsigned int stride ) -{ - assert( channel < bp->inputChannelCount ); - - bp->hostInputChannels[1][channel].data = data; - bp->hostInputChannels[1][channel].stride = stride; -} - - -void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp, - unsigned int firstChannel, void *data, unsigned int channelCount ) -{ - unsigned int i; - unsigned int channel = firstChannel; - unsigned char *p = (unsigned char*)data; - - if( channelCount == 0 ) - channelCount = bp->inputChannelCount; - - assert( firstChannel < bp->inputChannelCount ); - assert( firstChannel + channelCount <= bp->inputChannelCount ); - assert( bp->hostInputIsInterleaved ); - - for( i=0; i< channelCount; ++i ) - { - bp->hostInputChannels[1][channel+i].data = p; - p += bp->bytesPerHostInputSample; - bp->hostInputChannels[1][channel+i].stride = channelCount; - } -} - - -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; -} - - -void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp, - unsigned long frameCount ) -{ - if( frameCount == 0 ) - bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer; - else - bp->hostOutputFrameCount[0] = frameCount; -} - - -void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp ) -{ - assert( bp->outputChannelCount > 0 ); - - bp->hostOutputChannels[0][0].data = 0; - - /* note that only NonAdaptingProcess is able to deal with no output at this stage. not implemented for AdaptingProcess */ -} - - -void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data, unsigned int stride ) -{ - assert( channel < bp->outputChannelCount ); - assert( data != NULL ); - - bp->hostOutputChannels[0][channel].data = data; - bp->hostOutputChannels[0][channel].stride = stride; -} - - -void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp, - unsigned int firstChannel, void *data, unsigned int channelCount ) -{ - unsigned int i; - unsigned int channel = firstChannel; - unsigned char *p = (unsigned char*)data; - - if( channelCount == 0 ) - channelCount = bp->outputChannelCount; - - assert( firstChannel < bp->outputChannelCount ); - assert( firstChannel + channelCount <= bp->outputChannelCount ); - assert( bp->hostOutputIsInterleaved ); - - for( i=0; i< channelCount; ++i ) - { - PaUtil_SetOutputChannel( bp, channel + i, p, channelCount ); - p += bp->bytesPerHostOutputSample; - } -} - - -void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data ) -{ - assert( channel < bp->outputChannelCount ); - assert( !bp->hostOutputIsInterleaved ); - - PaUtil_SetOutputChannel( bp, channel, data, 1 ); -} - - -void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp, - unsigned long frameCount ) -{ - bp->hostOutputFrameCount[1] = frameCount; -} - - -void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data, unsigned int stride ) -{ - assert( channel < bp->outputChannelCount ); - assert( data != NULL ); - - bp->hostOutputChannels[1][channel].data = data; - bp->hostOutputChannels[1][channel].stride = stride; -} - - -void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp, - unsigned int firstChannel, void *data, unsigned int channelCount ) -{ - unsigned int i; - unsigned int channel = firstChannel; - unsigned char *p = (unsigned char*)data; - - if( channelCount == 0 ) - channelCount = bp->outputChannelCount; - - assert( firstChannel < bp->outputChannelCount ); - assert( firstChannel + channelCount <= bp->outputChannelCount ); - assert( bp->hostOutputIsInterleaved ); - - for( i=0; i< channelCount; ++i ) - { - PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount ); - p += bp->bytesPerHostOutputSample; - } -} - - -void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data ) -{ - assert( channel < bp->outputChannelCount ); - assert( !bp->hostOutputIsInterleaved ); - - PaUtil_Set2ndOutputChannel( bp, channel, data, 1 ); -} - - -void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, - PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags ) -{ - bp->timeInfo = timeInfo; - - /* the first streamCallback will be called to process samples which are - currently in the input buffer before the ones starting at the timeInfo time */ - - bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod; - - /* We just pass through timeInfo->currentTime provided by the caller. This is - not strictly conformant to the word of the spec, since the buffer processor - might call the callback multiple times, and we never refresh currentTime. */ - - /* the first streamCallback will be called to generate samples which will be - outputted after the frames currently in the output buffer have been - outputted. */ - bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod; - - bp->callbackStatusFlags = callbackStatusFlags; - - bp->hostInputFrameCount[1] = 0; - bp->hostOutputFrameCount[1] = 0; -} - - -/* - NonAdaptingProcess() is a simple buffer copying adaptor that can handle - both full and half duplex copies. It processes framesToProcess frames, - broken into blocks bp->framesPerTempBuffer long. - This routine can be used when the streamCallback doesn't care what length - the buffers are, or when framesToProcess is an integer multiple of - bp->framesPerTempBuffer, in which case streamCallback will always be called - with bp->framesPerTempBuffer samples. -*/ -static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, - int *streamCallbackResult, - PaUtilChannelDescriptor *hostInputChannels, - PaUtilChannelDescriptor *hostOutputChannels, - unsigned long framesToProcess ) -{ - void *userInput, *userOutput; - unsigned char *srcBytePtr, *destBytePtr; - unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i; - unsigned long frameCount; - unsigned long framesToGo = framesToProcess; - unsigned long framesProcessed = 0; - int skipOutputConvert = 0; - int skipInputConvert = 0; - - - if( *streamCallbackResult == paContinue ) - { - do - { - frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo ); - - /* configure user input buffer and convert input data (host -> user) */ - if( bp->inputChannelCount == 0 ) - { - /* no input */ - userInput = 0; - } - else /* there are input channels */ - { - - destBytePtr = (unsigned char *)bp->tempInputBuffer; - - if( bp->userInputIsInterleaved ) - { - destSampleStrideSamples = bp->inputChannelCount; - destChannelStrideBytes = bp->bytesPerUserInputSample; - - /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, - * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ - if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved - && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride ) - { - userInput = hostInputChannels[0].data; - destBytePtr = (unsigned char *)hostInputChannels[0].data; - skipInputConvert = 1; - } - else - { - userInput = bp->tempInputBuffer; - } - } - else /* user input is not interleaved */ - { - destSampleStrideSamples = 1; - destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample; - - /* setup non-interleaved ptrs */ - if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data ) - { - 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; - } - - if( !bp->hostInputChannels[0][0].data ) - { - /* no input was supplied (see PaUtil_SetNoInput), so - zero the input buffer */ - - for( i=0; i<bp->inputChannelCount; ++i ) - { - bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount ); - destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ - } - } - else - { - if( skipInputConvert ) - { - 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 */ - - /* advance src ptr for next iteration */ - hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + - frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; - } - } - } - } - - /* configure user output buffer */ - if( bp->outputChannelCount == 0 ) - { - /* no output */ - userOutput = 0; - } - else /* there are output channels */ - { - if( bp->userOutputIsInterleaved ) - { - /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, - * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ - if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved - && bp->outputChannelCount == hostOutputChannels[0].stride ) - { - userOutput = hostOutputChannels[0].data; - skipOutputConvert = 1; - } - else - { - userOutput = bp->tempOutputBuffer; - } - } - else /* user output is not interleaved */ - { - if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved ) - { - 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; - } - } - - *streamCallbackResult = bp->streamCallback( userInput, userOutput, - frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); - - if( *streamCallbackResult == paAbort ) - { - /* callback returned paAbort, don't advance framesProcessed - and framesToGo, they will be handled below */ - } - else - { - bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; - bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod; - - /* convert output data (user -> host) */ - - if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) - { - 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 - { - - srcBytePtr = (unsigned char *)bp->tempOutputBuffer; - - if( bp->userOutputIsInterleaved ) - { - srcSampleStrideSamples = bp->outputChannelCount; - srcChannelStrideBytes = bp->bytesPerUserOutputSample; - } - else /* user output is not interleaved */ - { - srcSampleStrideSamples = 1; - srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample; - } - - for( i=0; i<bp->outputChannelCount; ++i ) - { - bp->outputConverter( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - srcBytePtr, srcSampleStrideSamples, - frameCount, &bp->ditherGenerator ); - - 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; - - framesToGo -= frameCount; - } - } - while( framesToGo > 0 && *streamCallbackResult == paContinue ); - } - - if( framesToGo > 0 ) - { - /* zero any remaining frames output. There will only be remaining frames - if the callback has returned paComplete or paAbort */ - - frameCount = framesToGo; - - if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) - { - for( i=0; i<bp->outputChannelCount; ++i ) - { - bp->outputZeroer( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - frameCount ); - - /* advance dest ptr for next iteration */ - hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + - frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; - } - } - - framesProcessed += frameCount; - } - - return framesProcessed; -} - - -/* - AdaptingInputOnlyProcess() is a half duplex input buffer processor. It - converts data from the input buffers into the temporary input buffer, - when the temporary input buffer is full, it calls the streamCallback. -*/ -static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp, - int *streamCallbackResult, - PaUtilChannelDescriptor *hostInputChannels, - unsigned long framesToProcess ) -{ - void *userInput, *userOutput; - unsigned char *destBytePtr; - unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i; - unsigned long frameCount; - unsigned long framesToGo = framesToProcess; - unsigned long framesProcessed = 0; - - userOutput = 0; - - do - { - frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer ) - ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer ) - : framesToGo; - - /* convert frameCount samples into temp buffer */ - - if( bp->userInputIsInterleaved ) - { - destBytePtr = ((unsigned char*)bp->tempInputBuffer) + - bp->bytesPerUserInputSample * bp->inputChannelCount * - bp->framesInTempInputBuffer; - - destSampleStrideSamples = bp->inputChannelCount; - destChannelStrideBytes = bp->bytesPerUserInputSample; - - userInput = bp->tempInputBuffer; - } - else /* user input is not interleaved */ - { - destBytePtr = ((unsigned char*)bp->tempInputBuffer) + - bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; - - destSampleStrideSamples = 1; - destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; - - /* setup non-interleaved ptrs */ - for( i=0; i<bp->inputChannelCount; ++i ) - { - bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + - i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer; - } - - userInput = bp->tempInputBufferPtrs; - } - - 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 */ - - /* advance src ptr for next iteration */ - hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + - frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; - } - - bp->framesInTempInputBuffer += frameCount; - - if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer ) - { - /** - @todo (non-critical optimisation) - The conditional below implements the continue/complete/abort mechanism - simply by continuing on iterating through the input buffer, but not - passing the data to the callback. With care, the outer loop could be - terminated earlier, thus some unneeded conversion cycles would be - saved. - */ - if( *streamCallbackResult == paContinue ) - { - bp->timeInfo->outputBufferDacTime = 0; - - *streamCallbackResult = bp->streamCallback( userInput, userOutput, - bp->framesPerUserBuffer, bp->timeInfo, - bp->callbackStatusFlags, bp->userData ); - - bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; - } - - bp->framesInTempInputBuffer = 0; - } - - framesProcessed += frameCount; - - framesToGo -= frameCount; - }while( framesToGo > 0 ); - - return framesProcessed; -} - - -/* - AdaptingOutputOnlyProcess() is a half duplex output buffer processor. - It converts data from the temporary output buffer, to the output buffers, - when the temporary output buffer is empty, it calls the streamCallback. -*/ -static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp, - int *streamCallbackResult, - PaUtilChannelDescriptor *hostOutputChannels, - unsigned long framesToProcess ) -{ - void *userInput, *userOutput; - unsigned char *srcBytePtr; - unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i; - unsigned long frameCount; - unsigned long framesToGo = framesToProcess; - unsigned long framesProcessed = 0; - - do - { - if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue ) - { - userInput = 0; - - /* setup userOutput */ - if( bp->userOutputIsInterleaved ) - { - userOutput = bp->tempOutputBuffer; - } - else /* user output is not interleaved */ - { - for( i = 0; i < bp->outputChannelCount; ++i ) - { - bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + - i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; - } - - userOutput = bp->tempOutputBufferPtrs; - } - - bp->timeInfo->inputBufferAdcTime = 0; - - *streamCallbackResult = bp->streamCallback( userInput, userOutput, - bp->framesPerUserBuffer, bp->timeInfo, - bp->callbackStatusFlags, bp->userData ); - - if( *streamCallbackResult == paAbort ) - { - /* if the callback returned paAbort, we disregard its output */ - } - else - { - bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; - - bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; - } - } - - if( bp->framesInTempOutputBuffer > 0 ) - { - /* convert frameCount frames from user buffer to host buffer */ - - frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo ); - - if( bp->userOutputIsInterleaved ) - { - srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + - bp->bytesPerUserOutputSample * bp->outputChannelCount * - (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); - - srcSampleStrideSamples = bp->outputChannelCount; - srcChannelStrideBytes = bp->bytesPerUserOutputSample; - } - else /* user output is not interleaved */ - { - srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + - bp->bytesPerUserOutputSample * - (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); - - srcSampleStrideSamples = 1; - srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; - } - - for( i=0; i<bp->outputChannelCount; ++i ) - { - bp->outputConverter( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - srcBytePtr, srcSampleStrideSamples, - frameCount, &bp->ditherGenerator ); - - 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; - } - - bp->framesInTempOutputBuffer -= frameCount; - } - else - { - /* no more user data is available because the callback has returned - paComplete or paAbort. Fill the remainder of the host buffer - with zeros. - */ - - frameCount = framesToGo; - - for( i=0; i<bp->outputChannelCount; ++i ) - { - bp->outputZeroer( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - frameCount ); - - /* advance dest ptr for next iteration */ - hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + - frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; - } - } - - framesProcessed += frameCount; - - framesToGo -= frameCount; - - }while( framesToGo > 0 ); - - return framesProcessed; -} - -/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from - tempOutputBuffer to hostOutputChannels. This includes data conversion - and interleaving. -*/ -static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp) -{ - unsigned long maxFramesToCopy; - PaUtilChannelDescriptor *hostOutputChannels; - unsigned int frameCount; - unsigned char *srcBytePtr; - unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i; - - /* copy frames from user to host output buffers */ - while( bp->framesInTempOutputBuffer > 0 && - ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) ) - { - maxFramesToCopy = bp->framesInTempOutputBuffer; - - /* select the output buffer set (1st or 2nd) */ - if( bp->hostOutputFrameCount[0] > 0 ) - { - hostOutputChannels = bp->hostOutputChannels[0]; - frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy ); - } - else - { - hostOutputChannels = bp->hostOutputChannels[1]; - frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy ); - } - - if( bp->userOutputIsInterleaved ) - { - srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + - bp->bytesPerUserOutputSample * bp->outputChannelCount * - (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); - - srcSampleStrideSamples = bp->outputChannelCount; - srcChannelStrideBytes = bp->bytesPerUserOutputSample; - } - else /* user output is not interleaved */ - { - srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + - bp->bytesPerUserOutputSample * - (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); - - srcSampleStrideSamples = 1; - srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; - } - - for( i=0; i<bp->outputChannelCount; ++i ) - { - assert( hostOutputChannels[i].data != NULL ); - bp->outputConverter( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - srcBytePtr, srcSampleStrideSamples, - frameCount, &bp->ditherGenerator ); - - 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; - } - - if( bp->hostOutputFrameCount[0] > 0 ) - bp->hostOutputFrameCount[0] -= frameCount; - else - bp->hostOutputFrameCount[1] -= frameCount; - - bp->framesInTempOutputBuffer -= frameCount; - } -} - -/* - AdaptingProcess is a full duplex adapting buffer processor. It converts - data from the temporary output buffer into the host output buffers, then - from the host input buffers into the temporary input buffers. Calling the - streamCallback when necessary. - When processPartialUserBuffers is 0, all available input data will be - consumed and all available output space will be filled. When - processPartialUserBuffers is non-zero, as many full user buffers - as possible will be processed, but partial buffers will not be consumed. -*/ -static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp, - int *streamCallbackResult, int processPartialUserBuffers ) -{ - void *userInput, *userOutput; - unsigned long framesProcessed = 0; - unsigned long framesAvailable; - unsigned long endProcessingMinFrameCount; - unsigned long maxFramesToCopy; - PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels; - unsigned int frameCount; - unsigned char *destBytePtr; - unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i, j; - - - framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */ - - if( processPartialUserBuffers ) - endProcessingMinFrameCount = 0; - else - endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1); - - /* Fill host output with remaining frames in user output (tempOutputBuffer) */ - CopyTempOutputBuffersToHostOutputBuffers( bp ); - - while( framesAvailable > endProcessingMinFrameCount ) - { - - if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue ) - { - /* the callback will not be called any more, so zero what remains - of the host output buffers */ - - for( i=0; i<2; ++i ) - { - frameCount = bp->hostOutputFrameCount[i]; - if( frameCount > 0 ) - { - hostOutputChannels = bp->hostOutputChannels[i]; - - for( j=0; j<bp->outputChannelCount; ++j ) - { - bp->outputZeroer( hostOutputChannels[j].data, - hostOutputChannels[j].stride, - frameCount ); - - /* advance dest ptr for next iteration */ - hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) + - frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample; - } - bp->hostOutputFrameCount[i] = 0; - } - } - } - - - /* copy frames from host to user input buffers */ - while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer && - ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) ) - { - maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer; - - /* select the input buffer set (1st or 2nd) */ - if( bp->hostInputFrameCount[0] > 0 ) - { - hostInputChannels = bp->hostInputChannels[0]; - frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy ); - } - else - { - hostInputChannels = bp->hostInputChannels[1]; - frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy ); - } - - /* configure conversion destination pointers */ - if( bp->userInputIsInterleaved ) - { - destBytePtr = ((unsigned char*)bp->tempInputBuffer) + - bp->bytesPerUserInputSample * bp->inputChannelCount * - bp->framesInTempInputBuffer; - - destSampleStrideSamples = bp->inputChannelCount; - destChannelStrideBytes = bp->bytesPerUserInputSample; - } - else /* user input is not interleaved */ - { - destBytePtr = ((unsigned char*)bp->tempInputBuffer) + - bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; - - destSampleStrideSamples = 1; - destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; - } - - 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 */ - - /* advance src ptr for next iteration */ - hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + - frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; - } - - if( bp->hostInputFrameCount[0] > 0 ) - bp->hostInputFrameCount[0] -= frameCount; - else - bp->hostInputFrameCount[1] -= frameCount; - - bp->framesInTempInputBuffer += frameCount; - - /* update framesAvailable and framesProcessed based on input consumed - unless something is very wrong this will also correspond to the - amount of output generated */ - framesAvailable -= frameCount; - framesProcessed += frameCount; - } - - /* call streamCallback */ - if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer && - bp->framesInTempOutputBuffer == 0 ) - { - if( *streamCallbackResult == paContinue ) - { - /* setup userInput */ - if( bp->userInputIsInterleaved ) - { - userInput = bp->tempInputBuffer; - } - else /* user input is not interleaved */ - { - for( i = 0; i < bp->inputChannelCount; ++i ) - { - bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + - i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample; - } - - userInput = bp->tempInputBufferPtrs; - } - - /* setup userOutput */ - if( bp->userOutputIsInterleaved ) - { - userOutput = bp->tempOutputBuffer; - } - else /* user output is not interleaved */ - { - for( i = 0; i < bp->outputChannelCount; ++i ) - { - bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + - i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; - } - - userOutput = bp->tempOutputBufferPtrs; - } - - /* call streamCallback */ - - *streamCallbackResult = bp->streamCallback( userInput, userOutput, - bp->framesPerUserBuffer, bp->timeInfo, - bp->callbackStatusFlags, bp->userData ); - - bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; - bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; - - bp->framesInTempInputBuffer = 0; - - if( *streamCallbackResult == paAbort ) - bp->framesInTempOutputBuffer = 0; - else - bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; - } - else - { - /* paComplete or paAbort has already been called. */ - - bp->framesInTempInputBuffer = 0; - } - } - - /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) - Means to process the user output provided by the callback. Has to be called after - each callback. */ - CopyTempOutputBuffersToHostOutputBuffers( bp ); - - } - - return framesProcessed; -} - - -unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult ) -{ - unsigned long framesToProcess, framesToGo; - unsigned long framesProcessed = 0; - - if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 - && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */ - && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ ) - { - assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) == - (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) ); - } - - assert( *streamCallbackResult == paContinue - || *streamCallbackResult == paComplete - || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */ - - if( bp->useNonAdaptingProcess ) - { - if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) - { - /* full duplex non-adapting process, splice buffers if they are - different lengths */ - - framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */ - - do{ - unsigned long noInputInputFrameCount; - unsigned long *hostInputFrameCount; - PaUtilChannelDescriptor *hostInputChannels; - unsigned long noOutputOutputFrameCount; - unsigned long *hostOutputFrameCount; - PaUtilChannelDescriptor *hostOutputChannels; - unsigned long framesProcessedThisIteration; - - if( !bp->hostInputChannels[0][0].data ) - { - /* no input was supplied (see PaUtil_SetNoInput) - NonAdaptingProcess knows how to deal with this - */ - noInputInputFrameCount = framesToGo; - hostInputFrameCount = &noInputInputFrameCount; - hostInputChannels = 0; - } - else if( bp->hostInputFrameCount[0] != 0 ) - { - hostInputFrameCount = &bp->hostInputFrameCount[0]; - hostInputChannels = bp->hostInputChannels[0]; - } - else - { - hostInputFrameCount = &bp->hostInputFrameCount[1]; - hostInputChannels = bp->hostInputChannels[1]; - } - - if( !bp->hostOutputChannels[0][0].data ) - { - /* no output was supplied (see PaUtil_SetNoOutput) - NonAdaptingProcess knows how to deal with this - */ - noOutputOutputFrameCount = framesToGo; - hostOutputFrameCount = &noOutputOutputFrameCount; - hostOutputChannels = 0; - } - if( bp->hostOutputFrameCount[0] != 0 ) - { - hostOutputFrameCount = &bp->hostOutputFrameCount[0]; - hostOutputChannels = bp->hostOutputChannels[0]; - } - else - { - hostOutputFrameCount = &bp->hostOutputFrameCount[1]; - hostOutputChannels = bp->hostOutputChannels[1]; - } - - framesToProcess = PA_MIN_( *hostInputFrameCount, - *hostOutputFrameCount ); - - assert( framesToProcess != 0 ); - - framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult, - hostInputChannels, hostOutputChannels, - framesToProcess ); - - *hostInputFrameCount -= framesProcessedThisIteration; - *hostOutputFrameCount -= framesProcessedThisIteration; - - framesProcessed += framesProcessedThisIteration; - framesToGo -= framesProcessedThisIteration; - - }while( framesToGo > 0 ); - } - else - { - /* half duplex non-adapting process, just process 1st and 2nd buffer */ - /* process first buffer */ - - framesToProcess = (bp->inputChannelCount != 0) - ? bp->hostInputFrameCount[0] - : bp->hostOutputFrameCount[0]; - - framesProcessed = NonAdaptingProcess( bp, streamCallbackResult, - bp->hostInputChannels[0], bp->hostOutputChannels[0], - framesToProcess ); - - /* process second buffer if provided */ - - framesToProcess = (bp->inputChannelCount != 0) - ? bp->hostInputFrameCount[1] - : bp->hostOutputFrameCount[1]; - if( framesToProcess > 0 ) - { - framesProcessed += NonAdaptingProcess( bp, streamCallbackResult, - bp->hostInputChannels[1], bp->hostOutputChannels[1], - framesToProcess ); - } - } - } - else /* block adaption necessary*/ - { - - if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) - { - /* full duplex */ - - if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed ) - { - framesProcessed = AdaptingProcess( bp, streamCallbackResult, - 0 /* dont process partial user buffers */ ); - } - else - { - framesProcessed = AdaptingProcess( bp, streamCallbackResult, - 1 /* process partial user buffers */ ); - } - } - else if( bp->inputChannelCount != 0 ) - { - /* input only */ - framesToProcess = bp->hostInputFrameCount[0]; - - framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult, - bp->hostInputChannels[0], framesToProcess ); - - framesToProcess = bp->hostInputFrameCount[1]; - if( framesToProcess > 0 ) - { - framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult, - bp->hostInputChannels[1], framesToProcess ); - } - } - else - { - /* output only */ - framesToProcess = bp->hostOutputFrameCount[0]; - - framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult, - bp->hostOutputChannels[0], framesToProcess ); - - framesToProcess = bp->hostOutputFrameCount[1]; - if( framesToProcess > 0 ) - { - framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult, - bp->hostOutputChannels[1], framesToProcess ); - } - } - } - - return framesProcessed; -} - - -int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp ) -{ - return (bp->framesInTempOutputBuffer) ? 0 : 1; -} - - -unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp, - void **buffer, unsigned long frameCount ) -{ - PaUtilChannelDescriptor *hostInputChannels; - unsigned int framesToCopy; - unsigned char *destBytePtr; - void **nonInterleavedDestPtrs; - unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i; - - hostInputChannels = bp->hostInputChannels[0]; - framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount ); - - if( bp->userInputIsInterleaved ) - { - destBytePtr = (unsigned char*)*buffer; - - destSampleStrideSamples = bp->inputChannelCount; - destChannelStrideBytes = bp->bytesPerUserInputSample; - - for( i=0; i<bp->inputChannelCount; ++i ) - { - bp->inputConverter( destBytePtr, destSampleStrideSamples, - hostInputChannels[i].data, - hostInputChannels[i].stride, - framesToCopy, &bp->ditherGenerator ); - - destBytePtr += destChannelStrideBytes; /* skip to next dest channel */ - - /* advance source ptr for next iteration */ - hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + - framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; - } - - /* advance callers dest pointer (buffer) */ - *buffer = ((unsigned char *)*buffer) + - framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample; - } - else - { - /* user input is not interleaved */ - - nonInterleavedDestPtrs = (void**)*buffer; - - destSampleStrideSamples = 1; - - for( i=0; i<bp->inputChannelCount; ++i ) - { - destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i]; - - bp->inputConverter( destBytePtr, destSampleStrideSamples, - hostInputChannels[i].data, - hostInputChannels[i].stride, - framesToCopy, &bp->ditherGenerator ); - - /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */ - destBytePtr += bp->bytesPerUserInputSample * framesToCopy; - nonInterleavedDestPtrs[i] = destBytePtr; - - /* advance source ptr for next iteration */ - hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + - framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; - } - } - - bp->hostInputFrameCount[0] -= framesToCopy; - - return framesToCopy; -} - -unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp, - const void ** buffer, unsigned long frameCount ) -{ - PaUtilChannelDescriptor *hostOutputChannels; - unsigned int framesToCopy; - unsigned char *srcBytePtr; - void **nonInterleavedSrcPtrs; - unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ - unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ - unsigned int i; - - hostOutputChannels = bp->hostOutputChannels[0]; - framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); - - if( bp->userOutputIsInterleaved ) - { - srcBytePtr = (unsigned char*)*buffer; - - srcSampleStrideSamples = bp->outputChannelCount; - srcChannelStrideBytes = bp->bytesPerUserOutputSample; - - for( i=0; i<bp->outputChannelCount; ++i ) - { - bp->outputConverter( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - srcBytePtr, srcSampleStrideSamples, - framesToCopy, &bp->ditherGenerator ); - - srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ - - /* advance dest ptr for next iteration */ - hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + - framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; - } - - /* advance callers source pointer (buffer) */ - *buffer = ((unsigned char *)*buffer) + - framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample; - - } - else - { - /* user output is not interleaved */ - - nonInterleavedSrcPtrs = (void**)*buffer; - - srcSampleStrideSamples = 1; - - for( i=0; i<bp->outputChannelCount; ++i ) - { - srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i]; - - bp->outputConverter( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - srcBytePtr, srcSampleStrideSamples, - framesToCopy, &bp->ditherGenerator ); - - - /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */ - srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy; - nonInterleavedSrcPtrs[i] = srcBytePtr; - - /* advance dest ptr for next iteration */ - hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + - framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; - } - } - - bp->hostOutputFrameCount[0] += framesToCopy; - - return framesToCopy; -} - - -unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount ) -{ - PaUtilChannelDescriptor *hostOutputChannels; - unsigned int framesToZero; - unsigned int i; - - hostOutputChannels = bp->hostOutputChannels[0]; - framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); - - for( i=0; i<bp->outputChannelCount; ++i ) - { - bp->outputZeroer( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - framesToZero ); - - - /* advance dest ptr for next iteration */ - hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + - framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; - } - - bp->hostOutputFrameCount[0] += framesToZero; - - return framesToZero; -} |