about summary refs log tree commit diff
path: root/src/engine/external/portaudio/pa_process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/external/portaudio/pa_process.c')
-rw-r--r--src/engine/external/portaudio/pa_process.c1772
1 files changed, 1772 insertions, 0 deletions
diff --git a/src/engine/external/portaudio/pa_process.c b/src/engine/external/portaudio/pa_process.c
new file mode 100644
index 00000000..bc8848e2
--- /dev/null
+++ b/src/engine/external/portaudio/pa_process.c
@@ -0,0 +1,1772 @@
+/*

+ * $Id: pa_process.c 1097 2006-08-26 08:27:53Z rossb $

+ * 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.

+    

+ The code in this file is not optimised yet - although it's not clear that

+ it needs to be. there may appear to be redundancies

+ that could be factored into common functions, but the redundanceis are left

+ intentionally as each appearance may have different optimisation possibilities.

+

+ The optimisations which are planned involve only converting data in-place

+ where possible, rather than copying to the temp buffer(s).

+

+ Note that in the extreme case of being able to convert in-place, and there

+ being no conversion necessary there should be some code which short-circuits

+ the operation.

+

+    @todo Consider cache tilings for intereave<->deinterleave.

+

+    @todo implement timeInfo->currentTime int PaUtil_BeginBufferProcessing()

+

+    @todo specify and implement some kind of logical policy for handling the

+        underflow and overflow stream flags when the underflow/overflow overlaps

+        multiple user buffers/callbacks.

+

+	@todo provide support for priming the buffers with data from the callback.

+        The client interface is now implemented through PaUtil_SetNoInput()

+        which sets bp->hostInputChannels[0][0].data to zero. However this is

+        currently only implemented in NonAdaptingProcess(). It shouldn't be

+        needed for AdaptingInputOnlyProcess() (no priming should ever be

+        requested for AdaptingInputOnlyProcess()).

+        Not sure if additional work should be required to make it work with

+        AdaptingOutputOnlyProcess, but it definitely is required for

+        AdaptingProcess.

+

+    @todo implement PaUtil_SetNoOutput for AdaptingProcess

+

+    @todo don't allocate temp buffers for blocking streams unless they are

+        needed. At the moment they are needed, but perhaps for host APIs

+        where the implementation passes a buffer to the host they could be

+        used.

+*/

+

+

+#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;

+

+    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;

+        }

+

+        bp->inputConverter =

+            PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );

+

+        bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );

+            

+        bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;

+

+

+        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;

+

+        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_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp )

+{

+    return bp->initialFramesInTempInputBuffer;

+}

+

+

+unsigned long PaUtil_GetBufferProcessorOutputLatency( 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 );

+

+    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 );

+    

+    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 );

+    

+    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 );

+    

+    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;

+}

+

+

+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 );

+    

+    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 );

+

+    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 );

+    

+    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 );

+    

+    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;

+    

+    bp->timeInfo->currentTime = 0; /** FIXME: @todo time info currentTime not implemented */

+

+    /* 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;

+

+

+    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 */

+            {

+                /*

+                    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;

+                }

+                else /* user input is not interleaved */

+                {

+                    destSampleStrideSamples = 1;

+                    destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;

+

+                    /* setup non-interleaved ptrs */

+                    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

+                {

+                    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 )

+                {

+                    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->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 )

+                {

+                    /*

+                        could use more elaborate logic here and sometimes process

+                        buffers in-place.

+                    */

+            

+                    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 += frameCount * 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 source channel */

+

+            /* advance dest 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 dest 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;

+}