gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pa_process.c (68282B)


      1 /*
      2  * $Id$
      3  * Portable Audio I/O Library
      4  * streamCallback <-> host buffer processing adapter
      5  *
      6  * Based on the Open Source API proposed by Ross Bencina
      7  * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining
     10  * a copy of this software and associated documentation files
     11  * (the "Software"), to deal in the Software without restriction,
     12  * including without limitation the rights to use, copy, modify, merge,
     13  * publish, distribute, sublicense, and/or sell copies of the Software,
     14  * and to permit persons to whom the Software is furnished to do so,
     15  * subject to the following conditions:
     16  *
     17  * The above copyright notice and this permission notice shall be
     18  * included in all copies or substantial portions of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     24  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     25  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     27  */
     28 
     29 /*
     30  * The text above constitutes the entire PortAudio license; however, 
     31  * the PortAudio community also makes the following non-binding requests:
     32  *
     33  * Any person wishing to distribute modifications to the Software is
     34  * requested to send the modifications to the original developer so that
     35  * they can be incorporated into the canonical version. It is also 
     36  * requested that these non-binding requests be included along with the 
     37  * license above.
     38  */
     39 
     40 /** @file
     41  @ingroup common_src
     42 
     43  @brief Buffer Processor implementation.
     44 */
     45 
     46 
     47 #include <assert.h>
     48 #include <string.h> /* memset() */
     49 
     50 #include "pa_process.h"
     51 #include "pa_util.h"
     52 
     53 
     54 #define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_    1024
     55 
     56 #define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
     57 
     58 
     59 /* greatest common divisor - PGCD in French */
     60 static unsigned long GCD( unsigned long a, unsigned long b )
     61 {
     62     return (b==0) ? a : GCD( b, a%b);
     63 }
     64 
     65 /* least common multiple - PPCM in French */
     66 static unsigned long LCM( unsigned long a, unsigned long b )
     67 {
     68     return (a*b) / GCD(a,b);
     69 }
     70 
     71 #define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
     72 
     73 static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
     74 {
     75     unsigned long result = 0;
     76     unsigned long i;
     77     unsigned long lcm;
     78 
     79     assert( M > 0 );
     80     assert( N > 0 );
     81 
     82     lcm = LCM( M, N );
     83     for( i = M; i < lcm; i += M )
     84         result = PA_MAX_( result, i % N );
     85 
     86     return result;
     87 }
     88 
     89 
     90 PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
     91         int inputChannelCount, PaSampleFormat userInputSampleFormat,
     92         PaSampleFormat hostInputSampleFormat,
     93         int outputChannelCount, PaSampleFormat userOutputSampleFormat,
     94         PaSampleFormat hostOutputSampleFormat,
     95         double sampleRate,
     96         PaStreamFlags streamFlags,
     97         unsigned long framesPerUserBuffer,
     98         unsigned long framesPerHostBuffer,
     99         PaUtilHostBufferSizeMode hostBufferSizeMode,
    100         PaStreamCallback *streamCallback, void *userData )
    101 {
    102     PaError result = paNoError;
    103     PaError bytesPerSample;
    104     unsigned long tempInputBufferSize, tempOutputBufferSize;
    105     PaStreamFlags tempInputStreamFlags;
    106 
    107     if( streamFlags & paNeverDropInput )
    108     {
    109         /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */
    110         if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) ||
    111                 framesPerUserBuffer != paFramesPerBufferUnspecified )
    112             return paInvalidFlag;
    113     }
    114 
    115     /* initialize buffer ptrs to zero so they can be freed if necessary in error */
    116     bp->tempInputBuffer = 0;
    117     bp->tempInputBufferPtrs = 0;
    118     bp->tempOutputBuffer = 0;
    119     bp->tempOutputBufferPtrs = 0;
    120 
    121     bp->framesPerUserBuffer = framesPerUserBuffer;
    122     bp->framesPerHostBuffer = framesPerHostBuffer;
    123 
    124     bp->inputChannelCount = inputChannelCount;
    125     bp->outputChannelCount = outputChannelCount;
    126 
    127     bp->hostBufferSizeMode = hostBufferSizeMode;
    128 
    129     bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;
    130     bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;
    131 
    132     if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
    133     {
    134         bp->useNonAdaptingProcess = 1;
    135         bp->initialFramesInTempInputBuffer = 0;
    136         bp->initialFramesInTempOutputBuffer = 0;
    137 
    138         if( hostBufferSizeMode == paUtilFixedHostBufferSize
    139                 || hostBufferSizeMode == paUtilBoundedHostBufferSize )
    140         {
    141             bp->framesPerTempBuffer = framesPerHostBuffer;
    142         }
    143         else /* unknown host buffer size */
    144         {
    145              bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
    146         }
    147     }
    148     else
    149     {
    150         bp->framesPerTempBuffer = framesPerUserBuffer;
    151 
    152         if( hostBufferSizeMode == paUtilFixedHostBufferSize
    153                 && framesPerHostBuffer % framesPerUserBuffer == 0 )
    154         {
    155             bp->useNonAdaptingProcess = 1;
    156             bp->initialFramesInTempInputBuffer = 0;
    157             bp->initialFramesInTempOutputBuffer = 0;
    158         }
    159         else
    160         {
    161             bp->useNonAdaptingProcess = 0;
    162 
    163             if( inputChannelCount > 0 && outputChannelCount > 0 )
    164             {
    165                 /* full duplex */
    166                 if( hostBufferSizeMode == paUtilFixedHostBufferSize )
    167                 {
    168                     unsigned long frameShift =
    169                         CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
    170 
    171                     if( framesPerUserBuffer > framesPerHostBuffer )
    172                     {
    173                         bp->initialFramesInTempInputBuffer = frameShift;
    174                         bp->initialFramesInTempOutputBuffer = 0;
    175                     }
    176                     else
    177                     {
    178                         bp->initialFramesInTempInputBuffer = 0;
    179                         bp->initialFramesInTempOutputBuffer = frameShift;
    180                     }
    181                 }
    182                 else /* variable host buffer size, add framesPerUserBuffer latency */
    183                 {
    184                     bp->initialFramesInTempInputBuffer = 0;
    185                     bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;
    186                 }
    187             }
    188             else
    189             {
    190                 /* half duplex */
    191                 bp->initialFramesInTempInputBuffer = 0;
    192                 bp->initialFramesInTempOutputBuffer = 0;
    193             }
    194         }
    195     }
    196 
    197 
    198     bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
    199     bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
    200 
    201     
    202     if( inputChannelCount > 0 )
    203     {
    204         bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
    205         if( bytesPerSample > 0 )
    206         {
    207             bp->bytesPerHostInputSample = bytesPerSample;
    208         }
    209         else
    210         {
    211             result = bytesPerSample;
    212             goto error;
    213         }
    214 
    215         bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
    216         if( bytesPerSample > 0 )
    217         {
    218             bp->bytesPerUserInputSample = bytesPerSample;
    219         }
    220         else
    221         {
    222             result = bytesPerSample;
    223             goto error;
    224         }
    225 
    226         /* Under the assumption that no ADC in existence delivers better than 24bits resolution,
    227             we disable dithering when host input format is paInt32 and user format is paInt24, 
    228             since the host samples will just be padded with zeros anyway. */
    229 
    230         tempInputStreamFlags = streamFlags;
    231         if( !(tempInputStreamFlags & paDitherOff) /* dither is on */
    232                 && (hostInputSampleFormat & paInt32) /* host input format is int32 */
    233                 && (userInputSampleFormat & paInt24) /* user requested format is int24 */ ){
    234 
    235             tempInputStreamFlags = tempInputStreamFlags | paDitherOff;
    236         }
    237 
    238         bp->inputConverter =
    239             PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags );
    240 
    241         bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat );
    242             
    243         bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
    244 		
    245         bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1;
    246 
    247         bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved));
    248 
    249         tempInputBufferSize =
    250             bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
    251          
    252         bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
    253         if( bp->tempInputBuffer == 0 )
    254         {
    255             result = paInsufficientMemory;
    256             goto error;
    257         }
    258         
    259         if( bp->framesInTempInputBuffer > 0 )
    260             memset( bp->tempInputBuffer, 0, tempInputBufferSize );
    261 
    262         if( userInputSampleFormat & paNonInterleaved )
    263         {
    264             bp->tempInputBufferPtrs =
    265                 (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
    266             if( bp->tempInputBufferPtrs == 0 )
    267             {
    268                 result = paInsufficientMemory;
    269                 goto error;
    270             }
    271         }
    272 
    273         bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
    274                 PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
    275         if( bp->hostInputChannels[0] == 0 )
    276         {
    277             result = paInsufficientMemory;
    278             goto error;
    279         }
    280 
    281         bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
    282     }
    283 
    284     if( outputChannelCount > 0 )
    285     {
    286         bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
    287         if( bytesPerSample > 0 )
    288         {
    289             bp->bytesPerHostOutputSample = bytesPerSample;
    290         }
    291         else
    292         {
    293             result = bytesPerSample;
    294             goto error;
    295         }
    296 
    297         bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
    298         if( bytesPerSample > 0 )
    299         {
    300             bp->bytesPerUserOutputSample = bytesPerSample;
    301         }
    302         else
    303         {
    304             result = bytesPerSample;
    305             goto error;
    306         }
    307 
    308         bp->outputConverter =
    309             PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
    310 
    311         bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
    312 
    313         bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
    314 
    315         bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1;
    316 
    317         bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved));
    318 
    319         tempOutputBufferSize =
    320                 bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
    321 
    322         bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
    323         if( bp->tempOutputBuffer == 0 )
    324         {
    325             result = paInsufficientMemory;
    326             goto error;
    327         }
    328 
    329         if( bp->framesInTempOutputBuffer > 0 )
    330             memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
    331         
    332         if( userOutputSampleFormat & paNonInterleaved )
    333         {
    334             bp->tempOutputBufferPtrs =
    335                 (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
    336             if( bp->tempOutputBufferPtrs == 0 )
    337             {
    338                 result = paInsufficientMemory;
    339                 goto error;
    340             }
    341         }
    342 
    343         bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
    344                 PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
    345         if( bp->hostOutputChannels[0] == 0 )
    346         {                                                                     
    347             result = paInsufficientMemory;
    348             goto error;
    349         }
    350 
    351         bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
    352     }
    353 
    354     PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
    355 
    356     bp->samplePeriod = 1. / sampleRate;
    357 
    358     bp->streamCallback = streamCallback;
    359     bp->userData = userData;
    360 
    361     return result;
    362 
    363 error:
    364     if( bp->tempInputBuffer )
    365         PaUtil_FreeMemory( bp->tempInputBuffer );
    366 
    367     if( bp->tempInputBufferPtrs )
    368         PaUtil_FreeMemory( bp->tempInputBufferPtrs );
    369 
    370     if( bp->hostInputChannels[0] )
    371         PaUtil_FreeMemory( bp->hostInputChannels[0] );
    372 
    373     if( bp->tempOutputBuffer )
    374         PaUtil_FreeMemory( bp->tempOutputBuffer );
    375 
    376     if( bp->tempOutputBufferPtrs )
    377         PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
    378 
    379     if( bp->hostOutputChannels[0] )
    380         PaUtil_FreeMemory( bp->hostOutputChannels[0] );
    381 
    382     return result;
    383 }
    384 
    385 
    386 void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
    387 {
    388     if( bp->tempInputBuffer )
    389         PaUtil_FreeMemory( bp->tempInputBuffer );
    390 
    391     if( bp->tempInputBufferPtrs )
    392         PaUtil_FreeMemory( bp->tempInputBufferPtrs );
    393 
    394     if( bp->hostInputChannels[0] )
    395         PaUtil_FreeMemory( bp->hostInputChannels[0] );
    396         
    397     if( bp->tempOutputBuffer )
    398         PaUtil_FreeMemory( bp->tempOutputBuffer );
    399 
    400     if( bp->tempOutputBufferPtrs )
    401         PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
    402 
    403     if( bp->hostOutputChannels[0] )
    404         PaUtil_FreeMemory( bp->hostOutputChannels[0] );
    405 }
    406 
    407 
    408 void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
    409 {
    410     unsigned long tempInputBufferSize, tempOutputBufferSize;
    411 
    412     bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
    413     bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
    414 
    415     if( bp->framesInTempInputBuffer > 0 )
    416     {
    417         tempInputBufferSize =
    418             bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
    419         memset( bp->tempInputBuffer, 0, tempInputBufferSize );
    420     }
    421 
    422     if( bp->framesInTempOutputBuffer > 0 )
    423     {      
    424         tempOutputBufferSize =
    425             bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
    426         memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
    427     }
    428 }
    429 
    430 
    431 unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bp )
    432 {
    433     return bp->initialFramesInTempInputBuffer;
    434 }
    435 
    436 
    437 unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bp )
    438 {
    439     return bp->initialFramesInTempOutputBuffer;
    440 }
    441 
    442 
    443 void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
    444         unsigned long frameCount )
    445 {
    446     if( frameCount == 0 )
    447         bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
    448     else
    449         bp->hostInputFrameCount[0] = frameCount;
    450 }
    451         
    452 
    453 void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
    454 {
    455     assert( bp->inputChannelCount > 0 );
    456 
    457     bp->hostInputChannels[0][0].data = 0;
    458 }
    459 
    460 
    461 void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
    462         unsigned int channel, void *data, unsigned int stride )
    463 {
    464     assert( channel < bp->inputChannelCount );
    465     
    466     bp->hostInputChannels[0][channel].data = data;
    467     bp->hostInputChannels[0][channel].stride = stride;
    468 }
    469 
    470 
    471 void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
    472         unsigned int firstChannel, void *data, unsigned int channelCount )
    473 {
    474     unsigned int i;
    475     unsigned int channel = firstChannel;
    476     unsigned char *p = (unsigned char*)data;
    477 
    478     if( channelCount == 0 )
    479         channelCount = bp->inputChannelCount;
    480 
    481     assert( firstChannel < bp->inputChannelCount );
    482     assert( firstChannel + channelCount <= bp->inputChannelCount );
    483     assert( bp->hostInputIsInterleaved );
    484 
    485     for( i=0; i< channelCount; ++i )
    486     {
    487         bp->hostInputChannels[0][channel+i].data = p;
    488         p += bp->bytesPerHostInputSample;
    489         bp->hostInputChannels[0][channel+i].stride = channelCount;
    490     }
    491 }
    492 
    493 
    494 void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
    495         unsigned int channel, void *data )
    496 {
    497     assert( channel < bp->inputChannelCount );
    498     assert( !bp->hostInputIsInterleaved );
    499     
    500     bp->hostInputChannels[0][channel].data = data;
    501     bp->hostInputChannels[0][channel].stride = 1;
    502 }
    503 
    504 
    505 void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
    506         unsigned long frameCount )
    507 {
    508     bp->hostInputFrameCount[1] = frameCount;
    509 }
    510 
    511 
    512 void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
    513         unsigned int channel, void *data, unsigned int stride )
    514 {
    515     assert( channel < bp->inputChannelCount );
    516 
    517     bp->hostInputChannels[1][channel].data = data;
    518     bp->hostInputChannels[1][channel].stride = stride;
    519 }
    520 
    521 
    522 void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
    523         unsigned int firstChannel, void *data, unsigned int channelCount )
    524 {
    525     unsigned int i;
    526     unsigned int channel = firstChannel;
    527     unsigned char *p = (unsigned char*)data;
    528 
    529     if( channelCount == 0 )
    530         channelCount = bp->inputChannelCount;
    531 
    532     assert( firstChannel < bp->inputChannelCount );
    533     assert( firstChannel + channelCount <= bp->inputChannelCount );
    534     assert( bp->hostInputIsInterleaved );
    535     
    536     for( i=0; i< channelCount; ++i )
    537     {
    538         bp->hostInputChannels[1][channel+i].data = p;
    539         p += bp->bytesPerHostInputSample;
    540         bp->hostInputChannels[1][channel+i].stride = channelCount;
    541     }
    542 }
    543 
    544         
    545 void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
    546         unsigned int channel, void *data )
    547 {
    548     assert( channel < bp->inputChannelCount );
    549     assert( !bp->hostInputIsInterleaved );
    550     
    551     bp->hostInputChannels[1][channel].data = data;
    552     bp->hostInputChannels[1][channel].stride = 1;
    553 }
    554 
    555 
    556 void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
    557         unsigned long frameCount )
    558 {
    559     if( frameCount == 0 )
    560         bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
    561     else
    562         bp->hostOutputFrameCount[0] = frameCount;
    563 }
    564 
    565 
    566 void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
    567 {
    568     assert( bp->outputChannelCount > 0 );
    569 
    570     bp->hostOutputChannels[0][0].data = 0;
    571 
    572     /* note that only NonAdaptingProcess is able to deal with no output at this stage. not implemented for AdaptingProcess */
    573 }
    574 
    575 
    576 void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
    577         unsigned int channel, void *data, unsigned int stride )
    578 {
    579     assert( channel < bp->outputChannelCount );
    580     assert( data != NULL );
    581 
    582     bp->hostOutputChannels[0][channel].data = data;
    583     bp->hostOutputChannels[0][channel].stride = stride;
    584 }
    585 
    586 
    587 void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
    588         unsigned int firstChannel, void *data, unsigned int channelCount )
    589 {
    590     unsigned int i;
    591     unsigned int channel = firstChannel;
    592     unsigned char *p = (unsigned char*)data;
    593 
    594     if( channelCount == 0 )
    595         channelCount = bp->outputChannelCount;
    596 
    597     assert( firstChannel < bp->outputChannelCount );
    598     assert( firstChannel + channelCount <= bp->outputChannelCount );
    599     assert( bp->hostOutputIsInterleaved );
    600     
    601     for( i=0; i< channelCount; ++i )
    602     {
    603         PaUtil_SetOutputChannel( bp, channel + i, p, channelCount );
    604         p += bp->bytesPerHostOutputSample;
    605     }
    606 }
    607 
    608 
    609 void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
    610         unsigned int channel, void *data )
    611 {
    612     assert( channel < bp->outputChannelCount );
    613     assert( !bp->hostOutputIsInterleaved );
    614 
    615     PaUtil_SetOutputChannel( bp, channel, data, 1 );
    616 }
    617 
    618 
    619 void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
    620         unsigned long frameCount )
    621 {
    622     bp->hostOutputFrameCount[1] = frameCount;
    623 }
    624 
    625 
    626 void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
    627         unsigned int channel, void *data, unsigned int stride )
    628 {
    629     assert( channel < bp->outputChannelCount );
    630     assert( data != NULL );
    631 
    632     bp->hostOutputChannels[1][channel].data = data;
    633     bp->hostOutputChannels[1][channel].stride = stride;
    634 }
    635 
    636 
    637 void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
    638         unsigned int firstChannel, void *data, unsigned int channelCount )
    639 {
    640     unsigned int i;
    641     unsigned int channel = firstChannel;
    642     unsigned char *p = (unsigned char*)data;
    643 
    644     if( channelCount == 0 )
    645         channelCount = bp->outputChannelCount;
    646 
    647     assert( firstChannel < bp->outputChannelCount );
    648     assert( firstChannel + channelCount <= bp->outputChannelCount );
    649     assert( bp->hostOutputIsInterleaved );
    650     
    651     for( i=0; i< channelCount; ++i )
    652     {
    653         PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount );
    654         p += bp->bytesPerHostOutputSample;
    655     }
    656 }
    657 
    658         
    659 void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
    660         unsigned int channel, void *data )
    661 {
    662     assert( channel < bp->outputChannelCount );
    663     assert( !bp->hostOutputIsInterleaved );
    664     
    665     PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
    666 }
    667 
    668 
    669 void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
    670         PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
    671 {
    672     bp->timeInfo = timeInfo;
    673 
    674     /* the first streamCallback will be called to process samples which are
    675         currently in the input buffer before the ones starting at the timeInfo time */
    676         
    677     bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
    678     
    679     /* We just pass through timeInfo->currentTime provided by the caller. This is
    680         not strictly conformant to the word of the spec, since the buffer processor 
    681         might call the callback multiple times, and we never refresh currentTime. */
    682 
    683     /* the first streamCallback will be called to generate samples which will be
    684         outputted after the frames currently in the output buffer have been
    685         outputted. */
    686     bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
    687 
    688     bp->callbackStatusFlags = callbackStatusFlags;
    689 
    690     bp->hostInputFrameCount[1] = 0;
    691     bp->hostOutputFrameCount[1] = 0;
    692 }
    693 
    694 
    695 /*
    696     NonAdaptingProcess() is a simple buffer copying adaptor that can handle
    697     both full and half duplex copies. It processes framesToProcess frames,
    698     broken into blocks bp->framesPerTempBuffer long.
    699     This routine can be used when the streamCallback doesn't care what length
    700     the buffers are, or when framesToProcess is an integer multiple of
    701     bp->framesPerTempBuffer, in which case streamCallback will always be called
    702     with bp->framesPerTempBuffer samples.
    703 */
    704 static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
    705         int *streamCallbackResult,
    706         PaUtilChannelDescriptor *hostInputChannels,
    707         PaUtilChannelDescriptor *hostOutputChannels,
    708         unsigned long framesToProcess )
    709 {
    710     void *userInput, *userOutput;
    711     unsigned char *srcBytePtr, *destBytePtr;
    712     unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
    713     unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
    714     unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
    715     unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
    716     unsigned int i;
    717     unsigned long frameCount;
    718     unsigned long framesToGo = framesToProcess;
    719     unsigned long framesProcessed = 0;
    720     int skipOutputConvert = 0;
    721     int skipInputConvert = 0;
    722 
    723 
    724     if( *streamCallbackResult == paContinue )
    725     {
    726         do
    727         {
    728             frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
    729 
    730             /* configure user input buffer and convert input data (host -> user) */
    731             if( bp->inputChannelCount == 0 )
    732             {
    733                 /* no input */
    734                 userInput = 0;
    735             }
    736             else /* there are input channels */
    737             {
    738                 
    739                 destBytePtr = (unsigned char *)bp->tempInputBuffer;
    740 
    741                 if( bp->userInputIsInterleaved )
    742                 {
    743                     destSampleStrideSamples = bp->inputChannelCount;
    744                     destChannelStrideBytes = bp->bytesPerUserInputSample;
    745 
    746                     /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved,
    747                      * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */
    748                     if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved
    749                         && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride )
    750                     {
    751                         userInput = hostInputChannels[0].data;
    752                         destBytePtr = (unsigned char *)hostInputChannels[0].data;
    753                         skipInputConvert = 1;
    754                     }
    755                     else
    756                     {
    757                         userInput = bp->tempInputBuffer;
    758                     }
    759                 }
    760                 else /* user input is not interleaved */
    761                 {
    762                     destSampleStrideSamples = 1;
    763                     destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
    764 
    765                     /* setup non-interleaved ptrs */
    766                     if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data )
    767                     {
    768                         for( i=0; i<bp->inputChannelCount; ++i )
    769                         {
    770                             bp->tempInputBufferPtrs[i] = hostInputChannels[i].data;
    771                         }
    772                         skipInputConvert = 1;
    773                     }
    774                     else
    775                     {
    776                         for( i=0; i<bp->inputChannelCount; ++i )
    777                         {
    778                             bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
    779                                 i * bp->bytesPerUserInputSample * frameCount;
    780                         }
    781                     }
    782                 
    783                     userInput = bp->tempInputBufferPtrs;
    784                 }
    785 
    786                 if( !bp->hostInputChannels[0][0].data )
    787                 {
    788                     /* no input was supplied (see PaUtil_SetNoInput), so
    789                         zero the input buffer */
    790 
    791                     for( i=0; i<bp->inputChannelCount; ++i )
    792                     {
    793                         bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
    794                         destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
    795                     }
    796                 }
    797                 else
    798 	            {
    799                     if( skipInputConvert )
    800                     {
    801                         for( i=0; i<bp->inputChannelCount; ++i )
    802                         {
    803                             /* advance src ptr for next iteration */
    804                             hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
    805                                     frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
    806                         }
    807                     }
    808                     else
    809                     {
    810                         for( i=0; i<bp->inputChannelCount; ++i )
    811                         {
    812                             bp->inputConverter( destBytePtr, destSampleStrideSamples,
    813                                                     hostInputChannels[i].data,
    814                                                     hostInputChannels[i].stride,
    815                                                     frameCount, &bp->ditherGenerator );
    816 
    817                             destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
    818 
    819                             /* advance src ptr for next iteration */
    820                             hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
    821                                     frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
    822                         }
    823                     }
    824                 }
    825             }
    826 
    827             /* configure user output buffer */
    828             if( bp->outputChannelCount == 0 )
    829             {
    830                 /* no output */
    831                 userOutput = 0;
    832             }
    833             else /* there are output channels */
    834             {
    835                 if( bp->userOutputIsInterleaved )
    836                 {
    837                     /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved,
    838                      * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */
    839                     if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved
    840                           && bp->outputChannelCount == hostOutputChannels[0].stride )
    841                     {
    842                         userOutput = hostOutputChannels[0].data;
    843                         skipOutputConvert = 1;
    844                     }
    845                     else
    846                     {
    847                         userOutput = bp->tempOutputBuffer;
    848                     }
    849                 }
    850                 else /* user output is not interleaved */
    851                 {
    852                     if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved )
    853                     {
    854                         for( i=0; i<bp->outputChannelCount; ++i )
    855                         {
    856                             bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data;
    857                         }
    858                         skipOutputConvert = 1;
    859                     }
    860                     else
    861                     {
    862                         for( i=0; i<bp->outputChannelCount; ++i )
    863                         {
    864                             bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
    865                                 i * bp->bytesPerUserOutputSample * frameCount;
    866                         }
    867                     }
    868 
    869                     userOutput = bp->tempOutputBufferPtrs;
    870                 }
    871             }
    872         
    873             *streamCallbackResult = bp->streamCallback( userInput, userOutput,
    874                     frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
    875 
    876             if( *streamCallbackResult == paAbort )
    877             {
    878                 /* callback returned paAbort, don't advance framesProcessed
    879                         and framesToGo, they will be handled below */
    880             }
    881             else
    882             {
    883                 bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
    884                 bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
    885 
    886                 /* convert output data (user -> host) */
    887                 
    888                 if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
    889                 {
    890                     if( skipOutputConvert )
    891 					{
    892 						for( i=0; i<bp->outputChannelCount; ++i )
    893                     	{
    894                         	/* advance dest ptr for next iteration */
    895                         	hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
    896                             	    frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
    897                     	}
    898 					}
    899 					else
    900 					{
    901 
    902                     	srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
    903 
    904                     	if( bp->userOutputIsInterleaved )
    905                     	{
    906                         	srcSampleStrideSamples = bp->outputChannelCount;
    907                         	srcChannelStrideBytes = bp->bytesPerUserOutputSample;
    908                     	}
    909                     	else /* user output is not interleaved */
    910                     	{
    911                         	srcSampleStrideSamples = 1;
    912                         	srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
    913                     	}
    914 
    915                     	for( i=0; i<bp->outputChannelCount; ++i )
    916                     	{
    917                         	bp->outputConverter(    hostOutputChannels[i].data,
    918                                                 	hostOutputChannels[i].stride,
    919                                                 	srcBytePtr, srcSampleStrideSamples,
    920                                                 	frameCount, &bp->ditherGenerator );
    921 
    922                         	srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
    923 
    924                         	/* advance dest ptr for next iteration */
    925                         	hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
    926                                 		frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
    927                     	}
    928 					}
    929                 }
    930              
    931                 framesProcessed += frameCount;
    932 
    933                 framesToGo -= frameCount;
    934             }
    935         }
    936         while( framesToGo > 0  && *streamCallbackResult == paContinue );
    937     }
    938 
    939     if( framesToGo > 0 )
    940     {
    941         /* zero any remaining frames output. There will only be remaining frames
    942             if the callback has returned paComplete or paAbort */
    943 
    944         frameCount = framesToGo;
    945 
    946         if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
    947         {
    948             for( i=0; i<bp->outputChannelCount; ++i )
    949             {
    950                 bp->outputZeroer(   hostOutputChannels[i].data,
    951                                     hostOutputChannels[i].stride,
    952                                     frameCount );
    953 
    954                 /* advance dest ptr for next iteration */
    955                 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
    956                         frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
    957             }
    958         }
    959 
    960         framesProcessed += frameCount;
    961     }
    962 
    963     return framesProcessed;
    964 }
    965 
    966 
    967 /*
    968     AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
    969     converts data from the input buffers into the temporary input buffer,
    970     when the temporary input buffer is full, it calls the streamCallback.
    971 */
    972 static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
    973         int *streamCallbackResult,
    974         PaUtilChannelDescriptor *hostInputChannels,
    975         unsigned long framesToProcess )
    976 {
    977     void *userInput, *userOutput;
    978     unsigned char *destBytePtr;
    979     unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
    980     unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
    981     unsigned int i;
    982     unsigned long frameCount;
    983     unsigned long framesToGo = framesToProcess;
    984     unsigned long framesProcessed = 0;
    985     
    986     userOutput = 0;
    987 
    988     do
    989     {
    990         frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
    991                 ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
    992                 : framesToGo;
    993 
    994         /* convert frameCount samples into temp buffer */
    995 
    996         if( bp->userInputIsInterleaved )
    997         {
    998             destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
    999                     bp->bytesPerUserInputSample * bp->inputChannelCount *
   1000                     bp->framesInTempInputBuffer;
   1001                       
   1002             destSampleStrideSamples = bp->inputChannelCount;
   1003             destChannelStrideBytes = bp->bytesPerUserInputSample;
   1004 
   1005             userInput = bp->tempInputBuffer;
   1006         }
   1007         else /* user input is not interleaved */
   1008         {
   1009             destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
   1010                     bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
   1011 
   1012             destSampleStrideSamples = 1;
   1013             destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
   1014 
   1015             /* setup non-interleaved ptrs */
   1016             for( i=0; i<bp->inputChannelCount; ++i )
   1017             {
   1018                 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
   1019                     i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
   1020             }
   1021                     
   1022             userInput = bp->tempInputBufferPtrs;
   1023         }
   1024 
   1025         for( i=0; i<bp->inputChannelCount; ++i )
   1026         {
   1027             bp->inputConverter( destBytePtr, destSampleStrideSamples,
   1028                                     hostInputChannels[i].data,
   1029                                     hostInputChannels[i].stride,
   1030                                     frameCount, &bp->ditherGenerator );
   1031 
   1032             destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
   1033 
   1034             /* advance src ptr for next iteration */
   1035             hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
   1036                     frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
   1037         }
   1038 
   1039         bp->framesInTempInputBuffer += frameCount;
   1040 
   1041         if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
   1042         {
   1043             /**
   1044             @todo (non-critical optimisation)
   1045             The conditional below implements the continue/complete/abort mechanism
   1046             simply by continuing on iterating through the input buffer, but not
   1047             passing the data to the callback. With care, the outer loop could be
   1048             terminated earlier, thus some unneeded conversion cycles would be
   1049             saved.
   1050             */
   1051             if( *streamCallbackResult == paContinue )
   1052             {
   1053                 bp->timeInfo->outputBufferDacTime = 0;
   1054 
   1055                 *streamCallbackResult = bp->streamCallback( userInput, userOutput,
   1056                         bp->framesPerUserBuffer, bp->timeInfo,
   1057                         bp->callbackStatusFlags, bp->userData );
   1058 
   1059                 bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
   1060             }
   1061             
   1062             bp->framesInTempInputBuffer = 0;
   1063         }
   1064 
   1065         framesProcessed += frameCount;
   1066 
   1067         framesToGo -= frameCount;
   1068     }while( framesToGo > 0 );
   1069 
   1070     return framesProcessed;
   1071 }
   1072 
   1073 
   1074 /*
   1075     AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
   1076     It converts data from the temporary output buffer, to the output buffers,
   1077     when the temporary output buffer is empty, it calls the streamCallback.
   1078 */
   1079 static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
   1080         int *streamCallbackResult,
   1081         PaUtilChannelDescriptor *hostOutputChannels,
   1082         unsigned long framesToProcess )
   1083 {
   1084     void *userInput, *userOutput;
   1085     unsigned char *srcBytePtr;
   1086     unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
   1087     unsigned int srcChannelStrideBytes;  /* stride from one channel to the next, in bytes */
   1088     unsigned int i;
   1089     unsigned long frameCount;
   1090     unsigned long framesToGo = framesToProcess;
   1091     unsigned long framesProcessed = 0;
   1092 
   1093     do
   1094     {
   1095         if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
   1096         {
   1097             userInput = 0;
   1098 
   1099             /* setup userOutput */
   1100             if( bp->userOutputIsInterleaved )
   1101             {
   1102                 userOutput = bp->tempOutputBuffer;
   1103             }
   1104             else /* user output is not interleaved */
   1105             {
   1106                 for( i = 0; i < bp->outputChannelCount; ++i )
   1107                 {
   1108                     bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
   1109                             i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
   1110                 }
   1111 
   1112                 userOutput = bp->tempOutputBufferPtrs;
   1113             }
   1114 
   1115             bp->timeInfo->inputBufferAdcTime = 0;
   1116             
   1117             *streamCallbackResult = bp->streamCallback( userInput, userOutput,
   1118                     bp->framesPerUserBuffer, bp->timeInfo,
   1119                     bp->callbackStatusFlags, bp->userData );
   1120 
   1121             if( *streamCallbackResult == paAbort )
   1122             {
   1123                 /* if the callback returned paAbort, we disregard its output */
   1124             }
   1125             else
   1126             {
   1127                 bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
   1128 
   1129                 bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
   1130             }
   1131         }
   1132 
   1133         if( bp->framesInTempOutputBuffer > 0 )
   1134         {
   1135             /* convert frameCount frames from user buffer to host buffer */
   1136 
   1137             frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
   1138 
   1139             if( bp->userOutputIsInterleaved )
   1140             {
   1141                 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
   1142                         bp->bytesPerUserOutputSample * bp->outputChannelCount *
   1143                         (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
   1144 
   1145                 srcSampleStrideSamples = bp->outputChannelCount;
   1146                 srcChannelStrideBytes = bp->bytesPerUserOutputSample;
   1147             }
   1148             else /* user output is not interleaved */
   1149             {
   1150                 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
   1151                         bp->bytesPerUserOutputSample *
   1152                         (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
   1153                             
   1154                 srcSampleStrideSamples = 1;
   1155                 srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
   1156             }
   1157 
   1158             for( i=0; i<bp->outputChannelCount; ++i )
   1159             {
   1160                 bp->outputConverter(    hostOutputChannels[i].data,
   1161                                         hostOutputChannels[i].stride,
   1162                                         srcBytePtr, srcSampleStrideSamples,
   1163                                         frameCount, &bp->ditherGenerator );
   1164 
   1165                 srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
   1166 
   1167                 /* advance dest ptr for next iteration */
   1168                 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
   1169                         frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
   1170             }
   1171 
   1172             bp->framesInTempOutputBuffer -= frameCount;
   1173         }
   1174         else
   1175         {
   1176             /* no more user data is available because the callback has returned
   1177                 paComplete or paAbort. Fill the remainder of the host buffer
   1178                 with zeros.
   1179             */
   1180 
   1181             frameCount = framesToGo;
   1182 
   1183             for( i=0; i<bp->outputChannelCount; ++i )
   1184             {
   1185                 bp->outputZeroer(   hostOutputChannels[i].data,
   1186                                     hostOutputChannels[i].stride,
   1187                                     frameCount );
   1188 
   1189                 /* advance dest ptr for next iteration */
   1190                 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
   1191                         frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
   1192             }
   1193         }
   1194         
   1195         framesProcessed += frameCount;
   1196         
   1197         framesToGo -= frameCount;
   1198 
   1199     }while( framesToGo > 0 );
   1200 
   1201     return framesProcessed;
   1202 }
   1203 
   1204 /* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
   1205 	tempOutputBuffer to hostOutputChannels. This includes data conversion
   1206 	and interleaving. 
   1207 */
   1208 static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
   1209 {
   1210     unsigned long maxFramesToCopy;
   1211     PaUtilChannelDescriptor *hostOutputChannels;
   1212     unsigned int frameCount;
   1213     unsigned char *srcBytePtr;
   1214     unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
   1215     unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
   1216     unsigned int i;
   1217 
   1218      /* copy frames from user to host output buffers */
   1219      while( bp->framesInTempOutputBuffer > 0 &&
   1220              ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
   1221      {
   1222          maxFramesToCopy = bp->framesInTempOutputBuffer;
   1223 
   1224          /* select the output buffer set (1st or 2nd) */
   1225          if( bp->hostOutputFrameCount[0] > 0 )
   1226          {
   1227              hostOutputChannels = bp->hostOutputChannels[0];
   1228              frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
   1229          }
   1230          else
   1231          {
   1232              hostOutputChannels = bp->hostOutputChannels[1];
   1233              frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
   1234          }
   1235 
   1236          if( bp->userOutputIsInterleaved )
   1237          {
   1238              srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
   1239                      bp->bytesPerUserOutputSample * bp->outputChannelCount *
   1240                      (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
   1241                          
   1242              srcSampleStrideSamples = bp->outputChannelCount;
   1243              srcChannelStrideBytes = bp->bytesPerUserOutputSample;
   1244          }
   1245          else /* user output is not interleaved */
   1246          {
   1247              srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
   1248                      bp->bytesPerUserOutputSample *
   1249                      (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
   1250 
   1251              srcSampleStrideSamples = 1;
   1252              srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
   1253          }
   1254 
   1255          for( i=0; i<bp->outputChannelCount; ++i )
   1256          {
   1257              assert( hostOutputChannels[i].data != NULL );
   1258              bp->outputConverter(    hostOutputChannels[i].data,
   1259                                      hostOutputChannels[i].stride,
   1260                                      srcBytePtr, srcSampleStrideSamples,
   1261                                      frameCount, &bp->ditherGenerator );
   1262 
   1263              srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
   1264 
   1265              /* advance dest ptr for next iteration */
   1266              hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
   1267                      frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
   1268          }
   1269 
   1270          if( bp->hostOutputFrameCount[0] > 0 )
   1271              bp->hostOutputFrameCount[0] -= frameCount;
   1272          else
   1273              bp->hostOutputFrameCount[1] -= frameCount;
   1274 
   1275          bp->framesInTempOutputBuffer -= frameCount;
   1276      }
   1277 }
   1278 
   1279 /*
   1280     AdaptingProcess is a full duplex adapting buffer processor. It converts
   1281     data from the temporary output buffer into the host output buffers, then
   1282     from the host input buffers into the temporary input buffers. Calling the
   1283     streamCallback when necessary.
   1284     When processPartialUserBuffers is 0, all available input data will be
   1285     consumed and all available output space will be filled. When
   1286     processPartialUserBuffers is non-zero, as many full user buffers
   1287     as possible will be processed, but partial buffers will not be consumed.
   1288 */
   1289 static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
   1290         int *streamCallbackResult, int processPartialUserBuffers )
   1291 {
   1292     void *userInput, *userOutput;
   1293     unsigned long framesProcessed = 0;
   1294     unsigned long framesAvailable;
   1295     unsigned long endProcessingMinFrameCount;
   1296     unsigned long maxFramesToCopy;
   1297     PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
   1298     unsigned int frameCount;
   1299     unsigned char *destBytePtr;
   1300     unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
   1301     unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
   1302     unsigned int i, j;
   1303  
   1304 
   1305     framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
   1306 
   1307     if( processPartialUserBuffers )
   1308         endProcessingMinFrameCount = 0;
   1309     else
   1310         endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
   1311 
   1312     /* Fill host output with remaining frames in user output (tempOutputBuffer) */
   1313     CopyTempOutputBuffersToHostOutputBuffers( bp );		  	
   1314 
   1315     while( framesAvailable > endProcessingMinFrameCount ) 
   1316     {
   1317 
   1318         if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
   1319         {
   1320             /* the callback will not be called any more, so zero what remains
   1321                 of the host output buffers */
   1322 
   1323             for( i=0; i<2; ++i )
   1324             {
   1325                 frameCount = bp->hostOutputFrameCount[i];
   1326                 if( frameCount > 0 )
   1327                 {
   1328                     hostOutputChannels = bp->hostOutputChannels[i];
   1329                     
   1330                     for( j=0; j<bp->outputChannelCount; ++j )
   1331                     {
   1332                         bp->outputZeroer(   hostOutputChannels[j].data,
   1333                                             hostOutputChannels[j].stride,
   1334                                             frameCount );
   1335 
   1336                         /* advance dest ptr for next iteration  */
   1337                         hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
   1338                                 frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
   1339                     }
   1340                     bp->hostOutputFrameCount[i] = 0;
   1341                 }
   1342             }
   1343         }          
   1344 
   1345 
   1346         /* copy frames from host to user input buffers */
   1347         while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
   1348                 ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
   1349         {
   1350             maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
   1351 
   1352             /* select the input buffer set (1st or 2nd) */
   1353             if( bp->hostInputFrameCount[0] > 0 )
   1354             {
   1355                 hostInputChannels = bp->hostInputChannels[0];
   1356                 frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
   1357             }
   1358             else
   1359             {
   1360                 hostInputChannels = bp->hostInputChannels[1];
   1361                 frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
   1362             }
   1363 
   1364             /* configure conversion destination pointers */
   1365             if( bp->userInputIsInterleaved )
   1366             {
   1367                 destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
   1368                         bp->bytesPerUserInputSample * bp->inputChannelCount *
   1369                         bp->framesInTempInputBuffer;
   1370 
   1371                 destSampleStrideSamples = bp->inputChannelCount;
   1372                 destChannelStrideBytes = bp->bytesPerUserInputSample;
   1373             }
   1374             else /* user input is not interleaved */
   1375             {
   1376                 destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
   1377                         bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
   1378 
   1379                 destSampleStrideSamples = 1;
   1380                 destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
   1381             }
   1382 
   1383             for( i=0; i<bp->inputChannelCount; ++i )
   1384             {
   1385                 bp->inputConverter( destBytePtr, destSampleStrideSamples,
   1386                                         hostInputChannels[i].data,
   1387                                         hostInputChannels[i].stride,
   1388                                         frameCount, &bp->ditherGenerator );
   1389 
   1390                 destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
   1391 
   1392                 /* advance src ptr for next iteration */
   1393                 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
   1394                         frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
   1395             }
   1396 
   1397             if( bp->hostInputFrameCount[0] > 0 )
   1398                 bp->hostInputFrameCount[0] -= frameCount;
   1399             else
   1400                 bp->hostInputFrameCount[1] -= frameCount;
   1401                 
   1402             bp->framesInTempInputBuffer += frameCount;
   1403 
   1404             /* update framesAvailable and framesProcessed based on input consumed
   1405                 unless something is very wrong this will also correspond to the
   1406                 amount of output generated */
   1407             framesAvailable -= frameCount;
   1408             framesProcessed += frameCount;
   1409         }
   1410 
   1411         /* call streamCallback */
   1412         if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
   1413             bp->framesInTempOutputBuffer == 0 )
   1414         {
   1415             if( *streamCallbackResult == paContinue )
   1416             {
   1417                 /* setup userInput */
   1418                 if( bp->userInputIsInterleaved )
   1419                 {
   1420                     userInput = bp->tempInputBuffer;
   1421                 }
   1422                 else /* user input is not interleaved */
   1423                 {
   1424                     for( i = 0; i < bp->inputChannelCount; ++i )
   1425                     {
   1426                         bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
   1427                                 i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
   1428                     }
   1429 
   1430                     userInput = bp->tempInputBufferPtrs;
   1431                 }
   1432 
   1433                 /* setup userOutput */
   1434                 if( bp->userOutputIsInterleaved )
   1435                 {
   1436                     userOutput = bp->tempOutputBuffer;
   1437                 }
   1438                 else /* user output is not interleaved */
   1439                 {
   1440                     for( i = 0; i < bp->outputChannelCount; ++i )
   1441                     {
   1442                         bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
   1443                                 i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
   1444                     }
   1445 
   1446                     userOutput = bp->tempOutputBufferPtrs;
   1447                 }
   1448 
   1449                 /* call streamCallback */
   1450 
   1451                 *streamCallbackResult = bp->streamCallback( userInput, userOutput,
   1452                         bp->framesPerUserBuffer, bp->timeInfo,
   1453                         bp->callbackStatusFlags, bp->userData );
   1454 
   1455                 bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
   1456                 bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
   1457 
   1458                 bp->framesInTempInputBuffer = 0;
   1459 
   1460                 if( *streamCallbackResult == paAbort )
   1461                     bp->framesInTempOutputBuffer = 0;
   1462                 else
   1463                     bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
   1464             }
   1465             else
   1466             {
   1467                 /* paComplete or paAbort has already been called. */
   1468 
   1469                 bp->framesInTempInputBuffer = 0;
   1470             }
   1471         }
   1472 
   1473         /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) 
   1474            Means to process the user output provided by the callback. Has to be called after
   1475             each callback. */
   1476         CopyTempOutputBuffersToHostOutputBuffers( bp );		  	
   1477 
   1478     }
   1479     
   1480     return framesProcessed;
   1481 }
   1482 
   1483 
   1484 unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
   1485 {
   1486     unsigned long framesToProcess, framesToGo;
   1487     unsigned long framesProcessed = 0;
   1488     
   1489     if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
   1490             && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
   1491             && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
   1492     {
   1493         assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
   1494                 (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
   1495     }
   1496 
   1497     assert( *streamCallbackResult == paContinue
   1498             || *streamCallbackResult == paComplete
   1499             || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
   1500 
   1501     if( bp->useNonAdaptingProcess )
   1502     {
   1503         if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
   1504         {
   1505             /* full duplex non-adapting process, splice buffers if they are
   1506                 different lengths */
   1507 
   1508             framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
   1509 
   1510             do{
   1511                 unsigned long noInputInputFrameCount;
   1512                 unsigned long *hostInputFrameCount;
   1513                 PaUtilChannelDescriptor *hostInputChannels;
   1514                 unsigned long noOutputOutputFrameCount;
   1515                 unsigned long *hostOutputFrameCount;
   1516                 PaUtilChannelDescriptor *hostOutputChannels;
   1517                 unsigned long framesProcessedThisIteration;
   1518 
   1519                 if( !bp->hostInputChannels[0][0].data )
   1520                 {
   1521                     /* no input was supplied (see PaUtil_SetNoInput)
   1522                         NonAdaptingProcess knows how to deal with this
   1523                     */
   1524                     noInputInputFrameCount = framesToGo;
   1525                     hostInputFrameCount = &noInputInputFrameCount;
   1526                     hostInputChannels = 0;
   1527                 }
   1528                 else if( bp->hostInputFrameCount[0] != 0 )
   1529                 {
   1530                     hostInputFrameCount = &bp->hostInputFrameCount[0];
   1531                     hostInputChannels = bp->hostInputChannels[0];
   1532                 }
   1533                 else
   1534                 {
   1535                     hostInputFrameCount = &bp->hostInputFrameCount[1];
   1536                     hostInputChannels = bp->hostInputChannels[1];
   1537                 }
   1538 
   1539                 if( !bp->hostOutputChannels[0][0].data )
   1540                 {
   1541                     /* no output was supplied (see PaUtil_SetNoOutput)
   1542                         NonAdaptingProcess knows how to deal with this
   1543                     */
   1544                     noOutputOutputFrameCount = framesToGo;
   1545                     hostOutputFrameCount = &noOutputOutputFrameCount;
   1546                     hostOutputChannels = 0;
   1547                 }
   1548                 if( bp->hostOutputFrameCount[0] != 0 )
   1549                 {
   1550                     hostOutputFrameCount = &bp->hostOutputFrameCount[0];
   1551                     hostOutputChannels = bp->hostOutputChannels[0];
   1552                 }
   1553                 else
   1554                 {
   1555                     hostOutputFrameCount = &bp->hostOutputFrameCount[1];
   1556                     hostOutputChannels = bp->hostOutputChannels[1];
   1557                 }
   1558 
   1559                 framesToProcess = PA_MIN_( *hostInputFrameCount,
   1560                                        *hostOutputFrameCount );
   1561 
   1562                 assert( framesToProcess != 0 );
   1563                 
   1564                 framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
   1565                         hostInputChannels, hostOutputChannels,
   1566                         framesToProcess );                                       
   1567 
   1568                 *hostInputFrameCount -= framesProcessedThisIteration;
   1569                 *hostOutputFrameCount -= framesProcessedThisIteration;
   1570 
   1571                 framesProcessed += framesProcessedThisIteration;
   1572                 framesToGo -= framesProcessedThisIteration;
   1573                 
   1574             }while( framesToGo > 0 );
   1575         }
   1576         else
   1577         {
   1578             /* half duplex non-adapting process, just process 1st and 2nd buffer */
   1579             /* process first buffer */
   1580 
   1581             framesToProcess = (bp->inputChannelCount != 0)
   1582                             ? bp->hostInputFrameCount[0]
   1583                             : bp->hostOutputFrameCount[0];
   1584 
   1585             framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
   1586                         bp->hostInputChannels[0], bp->hostOutputChannels[0],
   1587                         framesToProcess );
   1588 
   1589             /* process second buffer if provided */
   1590     
   1591             framesToProcess = (bp->inputChannelCount != 0)
   1592                             ? bp->hostInputFrameCount[1]
   1593                             : bp->hostOutputFrameCount[1];
   1594             if( framesToProcess > 0 )
   1595             {
   1596                 framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
   1597                     bp->hostInputChannels[1], bp->hostOutputChannels[1],
   1598                     framesToProcess );
   1599             }
   1600         }
   1601     }
   1602     else /* block adaption necessary*/
   1603     {
   1604 
   1605         if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
   1606         {
   1607             /* full duplex */
   1608             
   1609             if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed  )
   1610             {
   1611                 framesProcessed = AdaptingProcess( bp, streamCallbackResult,
   1612                         0 /* dont process partial user buffers */ );
   1613             }
   1614             else
   1615             {
   1616                 framesProcessed = AdaptingProcess( bp, streamCallbackResult,
   1617                         1 /* process partial user buffers */ );
   1618             }
   1619         }
   1620         else if( bp->inputChannelCount != 0 )
   1621         {
   1622             /* input only */
   1623             framesToProcess = bp->hostInputFrameCount[0];
   1624 
   1625             framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
   1626                         bp->hostInputChannels[0], framesToProcess );
   1627 
   1628             framesToProcess = bp->hostInputFrameCount[1];
   1629             if( framesToProcess > 0 )
   1630             {
   1631                 framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
   1632                         bp->hostInputChannels[1], framesToProcess );
   1633             }
   1634         }
   1635         else
   1636         {
   1637             /* output only */
   1638             framesToProcess = bp->hostOutputFrameCount[0];
   1639 
   1640             framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
   1641                         bp->hostOutputChannels[0], framesToProcess );
   1642 
   1643             framesToProcess = bp->hostOutputFrameCount[1];
   1644             if( framesToProcess > 0 )
   1645             {
   1646                 framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
   1647                         bp->hostOutputChannels[1], framesToProcess );
   1648             }
   1649         }
   1650     }
   1651 
   1652     return framesProcessed;
   1653 }
   1654 
   1655 
   1656 int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
   1657 {
   1658     return (bp->framesInTempOutputBuffer) ? 0 : 1;
   1659 } 
   1660 
   1661 
   1662 unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
   1663         void **buffer, unsigned long frameCount )
   1664 {
   1665     PaUtilChannelDescriptor *hostInputChannels;
   1666     unsigned int framesToCopy;
   1667     unsigned char *destBytePtr;
   1668     void **nonInterleavedDestPtrs;
   1669     unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
   1670     unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
   1671     unsigned int i;
   1672 
   1673     hostInputChannels = bp->hostInputChannels[0];
   1674     framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
   1675 
   1676     if( bp->userInputIsInterleaved )
   1677     {
   1678         destBytePtr = (unsigned char*)*buffer;
   1679         
   1680         destSampleStrideSamples = bp->inputChannelCount;
   1681         destChannelStrideBytes = bp->bytesPerUserInputSample;
   1682 
   1683         for( i=0; i<bp->inputChannelCount; ++i )
   1684         {
   1685             bp->inputConverter( destBytePtr, destSampleStrideSamples,
   1686                                 hostInputChannels[i].data,
   1687                                 hostInputChannels[i].stride,
   1688                                 framesToCopy, &bp->ditherGenerator );
   1689 
   1690             destBytePtr += destChannelStrideBytes;  /* skip to next dest channel */
   1691 
   1692             /* advance source ptr for next iteration */
   1693             hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
   1694                     framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
   1695         }
   1696 
   1697         /* advance callers dest pointer (buffer) */
   1698         *buffer = ((unsigned char *)*buffer) +
   1699                 framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
   1700     }
   1701     else
   1702     {
   1703         /* user input is not interleaved */
   1704         
   1705         nonInterleavedDestPtrs = (void**)*buffer;
   1706 
   1707         destSampleStrideSamples = 1;
   1708         
   1709         for( i=0; i<bp->inputChannelCount; ++i )
   1710         {
   1711             destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
   1712 
   1713             bp->inputConverter( destBytePtr, destSampleStrideSamples,
   1714                                 hostInputChannels[i].data,
   1715                                 hostInputChannels[i].stride,
   1716                                 framesToCopy, &bp->ditherGenerator );
   1717 
   1718             /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
   1719             destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
   1720             nonInterleavedDestPtrs[i] = destBytePtr;
   1721             
   1722             /* advance source ptr for next iteration */
   1723             hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
   1724                     framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
   1725         }
   1726     }
   1727 
   1728     bp->hostInputFrameCount[0] -= framesToCopy;
   1729     
   1730     return framesToCopy;
   1731 }
   1732 
   1733 unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
   1734         const void ** buffer, unsigned long frameCount )
   1735 {
   1736     PaUtilChannelDescriptor *hostOutputChannels;
   1737     unsigned int framesToCopy;
   1738     unsigned char *srcBytePtr;
   1739     void **nonInterleavedSrcPtrs;
   1740     unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
   1741     unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
   1742     unsigned int i;
   1743 
   1744     hostOutputChannels = bp->hostOutputChannels[0];
   1745     framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
   1746 
   1747     if( bp->userOutputIsInterleaved )
   1748     {
   1749         srcBytePtr = (unsigned char*)*buffer;
   1750         
   1751         srcSampleStrideSamples = bp->outputChannelCount;
   1752         srcChannelStrideBytes = bp->bytesPerUserOutputSample;
   1753 
   1754         for( i=0; i<bp->outputChannelCount; ++i )
   1755         {
   1756             bp->outputConverter(    hostOutputChannels[i].data,
   1757                                     hostOutputChannels[i].stride,
   1758                                     srcBytePtr, srcSampleStrideSamples,
   1759                                     framesToCopy, &bp->ditherGenerator );
   1760 
   1761             srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
   1762 
   1763             /* advance dest ptr for next iteration */
   1764             hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
   1765                     framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
   1766         }
   1767 
   1768         /* advance callers source pointer (buffer) */
   1769         *buffer = ((unsigned char *)*buffer) +
   1770                 framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
   1771 
   1772     }
   1773     else
   1774     {
   1775         /* user output is not interleaved */
   1776         
   1777         nonInterleavedSrcPtrs = (void**)*buffer;
   1778 
   1779         srcSampleStrideSamples = 1;
   1780         
   1781         for( i=0; i<bp->outputChannelCount; ++i )
   1782         {
   1783             srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
   1784             
   1785             bp->outputConverter(    hostOutputChannels[i].data,
   1786                                     hostOutputChannels[i].stride,
   1787                                     srcBytePtr, srcSampleStrideSamples,
   1788                                     framesToCopy, &bp->ditherGenerator );
   1789 
   1790 
   1791             /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
   1792             srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
   1793             nonInterleavedSrcPtrs[i] = srcBytePtr;
   1794             
   1795             /* advance dest ptr for next iteration */
   1796             hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
   1797                     framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
   1798         }
   1799     }
   1800 
   1801     bp->hostOutputFrameCount[0] += framesToCopy;
   1802     
   1803     return framesToCopy;
   1804 }
   1805 
   1806 
   1807 unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
   1808 {
   1809     PaUtilChannelDescriptor *hostOutputChannels;
   1810     unsigned int framesToZero;
   1811     unsigned int i;
   1812 
   1813     hostOutputChannels = bp->hostOutputChannels[0];
   1814     framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
   1815 
   1816     for( i=0; i<bp->outputChannelCount; ++i )
   1817     {
   1818         bp->outputZeroer(   hostOutputChannels[i].data,
   1819                             hostOutputChannels[i].stride,
   1820                             framesToZero );
   1821 
   1822 
   1823         /* advance dest ptr for next iteration */
   1824         hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
   1825                 framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
   1826     }
   1827 
   1828     bp->hostOutputFrameCount[0] += framesToZero;
   1829     
   1830     return framesToZero;
   1831 }