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