2
* $Id: pa_process.c 1408 2009-03-13 16:41:39Z rossb $
3
* Portable Audio I/O Library
4
* streamCallback <-> host buffer processing adapter
6
* Based on the Open Source API proposed by Ross Bencina
7
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk
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:
17
* The above copyright notice and this permission notice shall be
18
* included in all copies or substantial portions of the Software.
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.
30
* The text above constitutes the entire PortAudio license; however,
31
* the PortAudio community also makes the following non-binding requests:
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
43
@brief Buffer Processor implementation.
45
The code in this file is not optimised yet - although it's not clear that
46
it needs to be. there may appear to be redundancies
47
that could be factored into common functions, but the redundanceis are left
48
intentionally as each appearance may have different optimisation possibilities.
50
The optimisations which are planned involve only converting data in-place
51
where possible, rather than copying to the temp buffer(s).
53
Note that in the extreme case of being able to convert in-place, and there
54
being no conversion necessary there should be some code which short-circuits
57
@todo Consider cache tilings for intereave<->deinterleave.
59
@todo specify and implement some kind of logical policy for handling the
60
underflow and overflow stream flags when the underflow/overflow overlaps
61
multiple user buffers/callbacks.
63
@todo provide support for priming the buffers with data from the callback.
64
The client interface is now implemented through PaUtil_SetNoInput()
65
which sets bp->hostInputChannels[0][0].data to zero. However this is
66
currently only implemented in NonAdaptingProcess(). It shouldn't be
67
needed for AdaptingInputOnlyProcess() (no priming should ever be
68
requested for AdaptingInputOnlyProcess()).
69
Not sure if additional work should be required to make it work with
70
AdaptingOutputOnlyProcess, but it definitely is required for
73
@todo implement PaUtil_SetNoOutput for AdaptingProcess
75
@todo don't allocate temp buffers for blocking streams unless they are
76
needed. At the moment they are needed, but perhaps for host APIs
77
where the implementation passes a buffer to the host they could be
83
#include <string.h> /* memset() */
85
#include "pa_process.h"
89
#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024
91
#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
94
/* greatest common divisor - PGCD in French */
95
static unsigned long GCD( unsigned long a, unsigned long b )
97
return (b==0) ? a : GCD( b, a%b);
100
/* least common multiple - PPCM in French */
101
static unsigned long LCM( unsigned long a, unsigned long b )
103
return (a*b) / GCD(a,b);
106
#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
108
static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
110
unsigned long result = 0;
118
for( i = M; i < lcm; i += M )
119
result = PA_MAX_( result, i % N );
125
PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
126
int inputChannelCount, PaSampleFormat userInputSampleFormat,
127
PaSampleFormat hostInputSampleFormat,
128
int outputChannelCount, PaSampleFormat userOutputSampleFormat,
129
PaSampleFormat hostOutputSampleFormat,
131
PaStreamFlags streamFlags,
132
unsigned long framesPerUserBuffer,
133
unsigned long framesPerHostBuffer,
134
PaUtilHostBufferSizeMode hostBufferSizeMode,
135
PaStreamCallback *streamCallback, void *userData )
137
PaError result = paNoError;
138
PaError bytesPerSample;
139
unsigned long tempInputBufferSize, tempOutputBufferSize;
141
if( streamFlags & paNeverDropInput )
143
/* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */
144
if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) ||
145
framesPerUserBuffer != paFramesPerBufferUnspecified )
146
return paInvalidFlag;
149
/* initialize buffer ptrs to zero so they can be freed if necessary in error */
150
bp->tempInputBuffer = 0;
151
bp->tempInputBufferPtrs = 0;
152
bp->tempOutputBuffer = 0;
153
bp->tempOutputBufferPtrs = 0;
155
bp->framesPerUserBuffer = framesPerUserBuffer;
156
bp->framesPerHostBuffer = framesPerHostBuffer;
158
bp->inputChannelCount = inputChannelCount;
159
bp->outputChannelCount = outputChannelCount;
161
bp->hostBufferSizeMode = hostBufferSizeMode;
163
bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;
164
bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;
166
if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
168
bp->useNonAdaptingProcess = 1;
169
bp->initialFramesInTempInputBuffer = 0;
170
bp->initialFramesInTempOutputBuffer = 0;
172
if( hostBufferSizeMode == paUtilFixedHostBufferSize
173
|| hostBufferSizeMode == paUtilBoundedHostBufferSize )
175
bp->framesPerTempBuffer = framesPerHostBuffer;
177
else /* unknown host buffer size */
179
bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
184
bp->framesPerTempBuffer = framesPerUserBuffer;
186
if( hostBufferSizeMode == paUtilFixedHostBufferSize
187
&& framesPerHostBuffer % framesPerUserBuffer == 0 )
189
bp->useNonAdaptingProcess = 1;
190
bp->initialFramesInTempInputBuffer = 0;
191
bp->initialFramesInTempOutputBuffer = 0;
195
bp->useNonAdaptingProcess = 0;
197
if( inputChannelCount > 0 && outputChannelCount > 0 )
200
if( hostBufferSizeMode == paUtilFixedHostBufferSize )
202
unsigned long frameShift =
203
CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
205
if( framesPerUserBuffer > framesPerHostBuffer )
207
bp->initialFramesInTempInputBuffer = frameShift;
208
bp->initialFramesInTempOutputBuffer = 0;
212
bp->initialFramesInTempInputBuffer = 0;
213
bp->initialFramesInTempOutputBuffer = frameShift;
216
else /* variable host buffer size, add framesPerUserBuffer latency */
218
bp->initialFramesInTempInputBuffer = 0;
219
bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;
225
bp->initialFramesInTempInputBuffer = 0;
226
bp->initialFramesInTempOutputBuffer = 0;
232
bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
233
bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
236
if( inputChannelCount > 0 )
238
bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
239
if( bytesPerSample > 0 )
241
bp->bytesPerHostInputSample = bytesPerSample;
245
result = bytesPerSample;
249
bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
250
if( bytesPerSample > 0 )
252
bp->bytesPerUserInputSample = bytesPerSample;
256
result = bytesPerSample;
261
PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );
263
bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );
265
bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
268
tempInputBufferSize =
269
bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
271
bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
272
if( bp->tempInputBuffer == 0 )
274
result = paInsufficientMemory;
278
if( bp->framesInTempInputBuffer > 0 )
279
memset( bp->tempInputBuffer, 0, tempInputBufferSize );
281
if( userInputSampleFormat & paNonInterleaved )
283
bp->tempInputBufferPtrs =
284
(void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
285
if( bp->tempInputBufferPtrs == 0 )
287
result = paInsufficientMemory;
292
bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
293
PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
294
if( bp->hostInputChannels[0] == 0 )
296
result = paInsufficientMemory;
300
bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
303
if( outputChannelCount > 0 )
305
bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
306
if( bytesPerSample > 0 )
308
bp->bytesPerHostOutputSample = bytesPerSample;
312
result = bytesPerSample;
316
bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
317
if( bytesPerSample > 0 )
319
bp->bytesPerUserOutputSample = bytesPerSample;
323
result = bytesPerSample;
327
bp->outputConverter =
328
PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
330
bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
332
bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
334
tempOutputBufferSize =
335
bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
337
bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
338
if( bp->tempOutputBuffer == 0 )
340
result = paInsufficientMemory;
344
if( bp->framesInTempOutputBuffer > 0 )
345
memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
347
if( userOutputSampleFormat & paNonInterleaved )
349
bp->tempOutputBufferPtrs =
350
(void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
351
if( bp->tempOutputBufferPtrs == 0 )
353
result = paInsufficientMemory;
358
bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
359
PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
360
if( bp->hostOutputChannels[0] == 0 )
362
result = paInsufficientMemory;
366
bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
369
PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
371
bp->samplePeriod = 1. / sampleRate;
373
bp->streamCallback = streamCallback;
374
bp->userData = userData;
379
if( bp->tempInputBuffer )
380
PaUtil_FreeMemory( bp->tempInputBuffer );
382
if( bp->tempInputBufferPtrs )
383
PaUtil_FreeMemory( bp->tempInputBufferPtrs );
385
if( bp->hostInputChannels[0] )
386
PaUtil_FreeMemory( bp->hostInputChannels[0] );
388
if( bp->tempOutputBuffer )
389
PaUtil_FreeMemory( bp->tempOutputBuffer );
391
if( bp->tempOutputBufferPtrs )
392
PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
394
if( bp->hostOutputChannels[0] )
395
PaUtil_FreeMemory( bp->hostOutputChannels[0] );
401
void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
403
if( bp->tempInputBuffer )
404
PaUtil_FreeMemory( bp->tempInputBuffer );
406
if( bp->tempInputBufferPtrs )
407
PaUtil_FreeMemory( bp->tempInputBufferPtrs );
409
if( bp->hostInputChannels[0] )
410
PaUtil_FreeMemory( bp->hostInputChannels[0] );
412
if( bp->tempOutputBuffer )
413
PaUtil_FreeMemory( bp->tempOutputBuffer );
415
if( bp->tempOutputBufferPtrs )
416
PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
418
if( bp->hostOutputChannels[0] )
419
PaUtil_FreeMemory( bp->hostOutputChannels[0] );
423
void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
425
unsigned long tempInputBufferSize, tempOutputBufferSize;
427
bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
428
bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
430
if( bp->framesInTempInputBuffer > 0 )
432
tempInputBufferSize =
433
bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
434
memset( bp->tempInputBuffer, 0, tempInputBufferSize );
437
if( bp->framesInTempOutputBuffer > 0 )
439
tempOutputBufferSize =
440
bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
441
memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
446
unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp )
448
return bp->initialFramesInTempInputBuffer;
452
unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bp )
454
return bp->initialFramesInTempOutputBuffer;
458
void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
459
unsigned long frameCount )
461
if( frameCount == 0 )
462
bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
464
bp->hostInputFrameCount[0] = frameCount;
468
void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
470
assert( bp->inputChannelCount > 0 );
472
bp->hostInputChannels[0][0].data = 0;
476
void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
477
unsigned int channel, void *data, unsigned int stride )
479
assert( channel < bp->inputChannelCount );
481
bp->hostInputChannels[0][channel].data = data;
482
bp->hostInputChannels[0][channel].stride = stride;
486
void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
487
unsigned int firstChannel, void *data, unsigned int channelCount )
490
unsigned int channel = firstChannel;
491
unsigned char *p = (unsigned char*)data;
493
if( channelCount == 0 )
494
channelCount = bp->inputChannelCount;
496
assert( firstChannel < bp->inputChannelCount );
497
assert( firstChannel + channelCount <= bp->inputChannelCount );
499
for( i=0; i< channelCount; ++i )
501
bp->hostInputChannels[0][channel+i].data = p;
502
p += bp->bytesPerHostInputSample;
503
bp->hostInputChannels[0][channel+i].stride = channelCount;
508
void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
509
unsigned int channel, void *data )
511
assert( channel < bp->inputChannelCount );
513
bp->hostInputChannels[0][channel].data = data;
514
bp->hostInputChannels[0][channel].stride = 1;
518
void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
519
unsigned long frameCount )
521
bp->hostInputFrameCount[1] = frameCount;
525
void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
526
unsigned int channel, void *data, unsigned int stride )
528
assert( channel < bp->inputChannelCount );
530
bp->hostInputChannels[1][channel].data = data;
531
bp->hostInputChannels[1][channel].stride = stride;
535
void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
536
unsigned int firstChannel, void *data, unsigned int channelCount )
539
unsigned int channel = firstChannel;
540
unsigned char *p = (unsigned char*)data;
542
if( channelCount == 0 )
543
channelCount = bp->inputChannelCount;
545
assert( firstChannel < bp->inputChannelCount );
546
assert( firstChannel + channelCount <= bp->inputChannelCount );
548
for( i=0; i< channelCount; ++i )
550
bp->hostInputChannels[1][channel+i].data = p;
551
p += bp->bytesPerHostInputSample;
552
bp->hostInputChannels[1][channel+i].stride = channelCount;
557
void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
558
unsigned int channel, void *data )
560
assert( channel < bp->inputChannelCount );
562
bp->hostInputChannels[1][channel].data = data;
563
bp->hostInputChannels[1][channel].stride = 1;
567
void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
568
unsigned long frameCount )
570
if( frameCount == 0 )
571
bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
573
bp->hostOutputFrameCount[0] = frameCount;
577
void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
579
assert( bp->outputChannelCount > 0 );
581
bp->hostOutputChannels[0][0].data = 0;
585
void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
586
unsigned int channel, void *data, unsigned int stride )
588
assert( channel < bp->outputChannelCount );
589
assert( data != NULL );
591
bp->hostOutputChannels[0][channel].data = data;
592
bp->hostOutputChannels[0][channel].stride = stride;
596
void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
597
unsigned int firstChannel, void *data, unsigned int channelCount )
600
unsigned int channel = firstChannel;
601
unsigned char *p = (unsigned char*)data;
603
if( channelCount == 0 )
604
channelCount = bp->outputChannelCount;
606
assert( firstChannel < bp->outputChannelCount );
607
assert( firstChannel + channelCount <= bp->outputChannelCount );
609
for( i=0; i< channelCount; ++i )
611
PaUtil_SetOutputChannel( bp, channel + i, p, channelCount );
612
p += bp->bytesPerHostOutputSample;
617
void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
618
unsigned int channel, void *data )
620
assert( channel < bp->outputChannelCount );
622
PaUtil_SetOutputChannel( bp, channel, data, 1 );
626
void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
627
unsigned long frameCount )
629
bp->hostOutputFrameCount[1] = frameCount;
633
void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
634
unsigned int channel, void *data, unsigned int stride )
636
assert( channel < bp->outputChannelCount );
637
assert( data != NULL );
639
bp->hostOutputChannels[1][channel].data = data;
640
bp->hostOutputChannels[1][channel].stride = stride;
644
void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
645
unsigned int firstChannel, void *data, unsigned int channelCount )
648
unsigned int channel = firstChannel;
649
unsigned char *p = (unsigned char*)data;
651
if( channelCount == 0 )
652
channelCount = bp->outputChannelCount;
654
assert( firstChannel < bp->outputChannelCount );
655
assert( firstChannel + channelCount <= bp->outputChannelCount );
657
for( i=0; i< channelCount; ++i )
659
PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount );
660
p += bp->bytesPerHostOutputSample;
665
void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
666
unsigned int channel, void *data )
668
assert( channel < bp->outputChannelCount );
670
PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
674
void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
675
PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
677
bp->timeInfo = timeInfo;
679
/* the first streamCallback will be called to process samples which are
680
currently in the input buffer before the ones starting at the timeInfo time */
682
bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
684
/* We just pass through timeInfo->currentTime provided by the caller. This is
685
not strictly conformant to the word of the spec, since the buffer processor
686
might call the callback multiple times, and we never refresh currentTime. */
688
/* the first streamCallback will be called to generate samples which will be
689
outputted after the frames currently in the output buffer have been
691
bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
693
bp->callbackStatusFlags = callbackStatusFlags;
695
bp->hostInputFrameCount[1] = 0;
696
bp->hostOutputFrameCount[1] = 0;
701
NonAdaptingProcess() is a simple buffer copying adaptor that can handle
702
both full and half duplex copies. It processes framesToProcess frames,
703
broken into blocks bp->framesPerTempBuffer long.
704
This routine can be used when the streamCallback doesn't care what length
705
the buffers are, or when framesToProcess is an integer multiple of
706
bp->framesPerTempBuffer, in which case streamCallback will always be called
707
with bp->framesPerTempBuffer samples.
709
static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
710
int *streamCallbackResult,
711
PaUtilChannelDescriptor *hostInputChannels,
712
PaUtilChannelDescriptor *hostOutputChannels,
713
unsigned long framesToProcess )
715
void *userInput, *userOutput;
716
unsigned char *srcBytePtr, *destBytePtr;
717
unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
718
unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
719
unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
720
unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
722
unsigned long frameCount;
723
unsigned long framesToGo = framesToProcess;
724
unsigned long framesProcessed = 0;
727
if( *streamCallbackResult == paContinue )
731
frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
733
/* configure user input buffer and convert input data (host -> user) */
734
if( bp->inputChannelCount == 0 )
739
else /* there are input channels */
742
could use more elaborate logic here and sometimes process
746
destBytePtr = (unsigned char *)bp->tempInputBuffer;
748
if( bp->userInputIsInterleaved )
750
destSampleStrideSamples = bp->inputChannelCount;
751
destChannelStrideBytes = bp->bytesPerUserInputSample;
752
userInput = bp->tempInputBuffer;
754
else /* user input is not interleaved */
756
destSampleStrideSamples = 1;
757
destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
759
/* setup non-interleaved ptrs */
760
for( i=0; i<bp->inputChannelCount; ++i )
762
bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
763
i * bp->bytesPerUserInputSample * frameCount;
766
userInput = bp->tempInputBufferPtrs;
769
if( !bp->hostInputChannels[0][0].data )
771
/* no input was supplied (see PaUtil_SetNoInput), so
772
zero the input buffer */
774
for( i=0; i<bp->inputChannelCount; ++i )
776
bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
777
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
782
for( i=0; i<bp->inputChannelCount; ++i )
784
bp->inputConverter( destBytePtr, destSampleStrideSamples,
785
hostInputChannels[i].data,
786
hostInputChannels[i].stride,
787
frameCount, &bp->ditherGenerator );
789
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
791
/* advance src ptr for next iteration */
792
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
793
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
798
/* configure user output buffer */
799
if( bp->outputChannelCount == 0 )
804
else /* there are output channels */
806
if( bp->userOutputIsInterleaved )
808
userOutput = bp->tempOutputBuffer;
810
else /* user output is not interleaved */
812
for( i = 0; i < bp->outputChannelCount; ++i )
814
bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
815
i * bp->bytesPerUserOutputSample * frameCount;
818
userOutput = bp->tempOutputBufferPtrs;
822
*streamCallbackResult = bp->streamCallback( userInput, userOutput,
823
frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
825
if( *streamCallbackResult == paAbort )
827
/* callback returned paAbort, don't advance framesProcessed
828
and framesToGo, they will be handled below */
832
bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
833
bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
835
/* convert output data (user -> host) */
837
if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
840
could use more elaborate logic here and sometimes process
844
srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
846
if( bp->userOutputIsInterleaved )
848
srcSampleStrideSamples = bp->outputChannelCount;
849
srcChannelStrideBytes = bp->bytesPerUserOutputSample;
851
else /* user output is not interleaved */
853
srcSampleStrideSamples = 1;
854
srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
857
for( i=0; i<bp->outputChannelCount; ++i )
859
bp->outputConverter( hostOutputChannels[i].data,
860
hostOutputChannels[i].stride,
861
srcBytePtr, srcSampleStrideSamples,
862
frameCount, &bp->ditherGenerator );
864
srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
866
/* advance dest ptr for next iteration */
867
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
868
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
872
framesProcessed += frameCount;
874
framesToGo -= frameCount;
877
while( framesToGo > 0 && *streamCallbackResult == paContinue );
882
/* zero any remaining frames output. There will only be remaining frames
883
if the callback has returned paComplete or paAbort */
885
frameCount = framesToGo;
887
if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
889
for( i=0; i<bp->outputChannelCount; ++i )
891
bp->outputZeroer( hostOutputChannels[i].data,
892
hostOutputChannels[i].stride,
895
/* advance dest ptr for next iteration */
896
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
897
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
901
framesProcessed += frameCount;
904
return framesProcessed;
909
AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
910
converts data from the input buffers into the temporary input buffer,
911
when the temporary input buffer is full, it calls the streamCallback.
913
static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
914
int *streamCallbackResult,
915
PaUtilChannelDescriptor *hostInputChannels,
916
unsigned long framesToProcess )
918
void *userInput, *userOutput;
919
unsigned char *destBytePtr;
920
unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
921
unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
923
unsigned long frameCount;
924
unsigned long framesToGo = framesToProcess;
925
unsigned long framesProcessed = 0;
931
frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
932
? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
935
/* convert frameCount samples into temp buffer */
937
if( bp->userInputIsInterleaved )
939
destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
940
bp->bytesPerUserInputSample * bp->inputChannelCount *
941
bp->framesInTempInputBuffer;
943
destSampleStrideSamples = bp->inputChannelCount;
944
destChannelStrideBytes = bp->bytesPerUserInputSample;
946
userInput = bp->tempInputBuffer;
948
else /* user input is not interleaved */
950
destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
951
bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
953
destSampleStrideSamples = 1;
954
destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
956
/* setup non-interleaved ptrs */
957
for( i=0; i<bp->inputChannelCount; ++i )
959
bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
960
i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
963
userInput = bp->tempInputBufferPtrs;
966
for( i=0; i<bp->inputChannelCount; ++i )
968
bp->inputConverter( destBytePtr, destSampleStrideSamples,
969
hostInputChannels[i].data,
970
hostInputChannels[i].stride,
971
frameCount, &bp->ditherGenerator );
973
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
975
/* advance src ptr for next iteration */
976
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
977
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
980
bp->framesInTempInputBuffer += frameCount;
982
if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
985
@todo (non-critical optimisation)
986
The conditional below implements the continue/complete/abort mechanism
987
simply by continuing on iterating through the input buffer, but not
988
passing the data to the callback. With care, the outer loop could be
989
terminated earlier, thus some unneeded conversion cycles would be
992
if( *streamCallbackResult == paContinue )
994
bp->timeInfo->outputBufferDacTime = 0;
996
*streamCallbackResult = bp->streamCallback( userInput, userOutput,
997
bp->framesPerUserBuffer, bp->timeInfo,
998
bp->callbackStatusFlags, bp->userData );
1000
bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
1003
bp->framesInTempInputBuffer = 0;
1006
framesProcessed += frameCount;
1008
framesToGo -= frameCount;
1009
}while( framesToGo > 0 );
1011
return framesProcessed;
1016
AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
1017
It converts data from the temporary output buffer, to the output buffers,
1018
when the temporary output buffer is empty, it calls the streamCallback.
1020
static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
1021
int *streamCallbackResult,
1022
PaUtilChannelDescriptor *hostOutputChannels,
1023
unsigned long framesToProcess )
1025
void *userInput, *userOutput;
1026
unsigned char *srcBytePtr;
1027
unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1028
unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1030
unsigned long frameCount;
1031
unsigned long framesToGo = framesToProcess;
1032
unsigned long framesProcessed = 0;
1036
if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
1040
/* setup userOutput */
1041
if( bp->userOutputIsInterleaved )
1043
userOutput = bp->tempOutputBuffer;
1045
else /* user output is not interleaved */
1047
for( i = 0; i < bp->outputChannelCount; ++i )
1049
bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
1050
i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1053
userOutput = bp->tempOutputBufferPtrs;
1056
bp->timeInfo->inputBufferAdcTime = 0;
1058
*streamCallbackResult = bp->streamCallback( userInput, userOutput,
1059
bp->framesPerUserBuffer, bp->timeInfo,
1060
bp->callbackStatusFlags, bp->userData );
1062
if( *streamCallbackResult == paAbort )
1064
/* if the callback returned paAbort, we disregard its output */
1068
bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
1070
bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
1074
if( bp->framesInTempOutputBuffer > 0 )
1076
/* convert frameCount frames from user buffer to host buffer */
1078
frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
1080
if( bp->userOutputIsInterleaved )
1082
srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1083
bp->bytesPerUserOutputSample * bp->outputChannelCount *
1084
(bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1086
srcSampleStrideSamples = bp->outputChannelCount;
1087
srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1089
else /* user output is not interleaved */
1091
srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1092
bp->bytesPerUserOutputSample *
1093
(bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1095
srcSampleStrideSamples = 1;
1096
srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1099
for( i=0; i<bp->outputChannelCount; ++i )
1101
bp->outputConverter( hostOutputChannels[i].data,
1102
hostOutputChannels[i].stride,
1103
srcBytePtr, srcSampleStrideSamples,
1104
frameCount, &bp->ditherGenerator );
1106
srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
1108
/* advance dest ptr for next iteration */
1109
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1110
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1113
bp->framesInTempOutputBuffer -= frameCount;
1117
/* no more user data is available because the callback has returned
1118
paComplete or paAbort. Fill the remainder of the host buffer
1122
frameCount = framesToGo;
1124
for( i=0; i<bp->outputChannelCount; ++i )
1126
bp->outputZeroer( hostOutputChannels[i].data,
1127
hostOutputChannels[i].stride,
1130
/* advance dest ptr for next iteration */
1131
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1132
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1136
framesProcessed += frameCount;
1138
framesToGo -= frameCount;
1140
}while( framesToGo > 0 );
1142
return framesProcessed;
1145
/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
1146
tempOutputBuffer to hostOutputChannels. This includes data conversion
1149
static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
1151
unsigned long maxFramesToCopy;
1152
PaUtilChannelDescriptor *hostOutputChannels;
1153
unsigned int frameCount;
1154
unsigned char *srcBytePtr;
1155
unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1156
unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1159
/* copy frames from user to host output buffers */
1160
while( bp->framesInTempOutputBuffer > 0 &&
1161
((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
1163
maxFramesToCopy = bp->framesInTempOutputBuffer;
1165
/* select the output buffer set (1st or 2nd) */
1166
if( bp->hostOutputFrameCount[0] > 0 )
1168
hostOutputChannels = bp->hostOutputChannels[0];
1169
frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
1173
hostOutputChannels = bp->hostOutputChannels[1];
1174
frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
1177
if( bp->userOutputIsInterleaved )
1179
srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1180
bp->bytesPerUserOutputSample * bp->outputChannelCount *
1181
(bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1183
srcSampleStrideSamples = bp->outputChannelCount;
1184
srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1186
else /* user output is not interleaved */
1188
srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1189
bp->bytesPerUserOutputSample *
1190
(bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1192
srcSampleStrideSamples = 1;
1193
srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1196
for( i=0; i<bp->outputChannelCount; ++i )
1198
assert( hostOutputChannels[i].data != NULL );
1199
bp->outputConverter( hostOutputChannels[i].data,
1200
hostOutputChannels[i].stride,
1201
srcBytePtr, srcSampleStrideSamples,
1202
frameCount, &bp->ditherGenerator );
1204
srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
1206
/* advance dest ptr for next iteration */
1207
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1208
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1211
if( bp->hostOutputFrameCount[0] > 0 )
1212
bp->hostOutputFrameCount[0] -= frameCount;
1214
bp->hostOutputFrameCount[1] -= frameCount;
1216
bp->framesInTempOutputBuffer -= frameCount;
1221
AdaptingProcess is a full duplex adapting buffer processor. It converts
1222
data from the temporary output buffer into the host output buffers, then
1223
from the host input buffers into the temporary input buffers. Calling the
1224
streamCallback when necessary.
1225
When processPartialUserBuffers is 0, all available input data will be
1226
consumed and all available output space will be filled. When
1227
processPartialUserBuffers is non-zero, as many full user buffers
1228
as possible will be processed, but partial buffers will not be consumed.
1230
static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
1231
int *streamCallbackResult, int processPartialUserBuffers )
1233
void *userInput, *userOutput;
1234
unsigned long framesProcessed = 0;
1235
unsigned long framesAvailable;
1236
unsigned long endProcessingMinFrameCount;
1237
unsigned long maxFramesToCopy;
1238
PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
1239
unsigned int frameCount;
1240
unsigned char *destBytePtr;
1241
unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1242
unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
1246
framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
1248
if( processPartialUserBuffers )
1249
endProcessingMinFrameCount = 0;
1251
endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
1253
/* Fill host output with remaining frames in user output (tempOutputBuffer) */
1254
CopyTempOutputBuffersToHostOutputBuffers( bp );
1256
while( framesAvailable > endProcessingMinFrameCount )
1259
if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
1261
/* the callback will not be called any more, so zero what remains
1262
of the host output buffers */
1264
for( i=0; i<2; ++i )
1266
frameCount = bp->hostOutputFrameCount[i];
1267
if( frameCount > 0 )
1269
hostOutputChannels = bp->hostOutputChannels[i];
1271
for( j=0; j<bp->outputChannelCount; ++j )
1273
bp->outputZeroer( hostOutputChannels[j].data,
1274
hostOutputChannels[j].stride,
1277
/* advance dest ptr for next iteration */
1278
hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
1279
frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
1281
bp->hostOutputFrameCount[i] = 0;
1287
/* copy frames from host to user input buffers */
1288
while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
1289
((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
1291
maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
1293
/* select the input buffer set (1st or 2nd) */
1294
if( bp->hostInputFrameCount[0] > 0 )
1296
hostInputChannels = bp->hostInputChannels[0];
1297
frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
1301
hostInputChannels = bp->hostInputChannels[1];
1302
frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
1305
/* configure conversion destination pointers */
1306
if( bp->userInputIsInterleaved )
1308
destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1309
bp->bytesPerUserInputSample * bp->inputChannelCount *
1310
bp->framesInTempInputBuffer;
1312
destSampleStrideSamples = bp->inputChannelCount;
1313
destChannelStrideBytes = bp->bytesPerUserInputSample;
1315
else /* user input is not interleaved */
1317
destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1318
bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
1320
destSampleStrideSamples = 1;
1321
destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1324
for( i=0; i<bp->inputChannelCount; ++i )
1326
bp->inputConverter( destBytePtr, destSampleStrideSamples,
1327
hostInputChannels[i].data,
1328
hostInputChannels[i].stride,
1329
frameCount, &bp->ditherGenerator );
1331
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
1333
/* advance src ptr for next iteration */
1334
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1335
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1338
if( bp->hostInputFrameCount[0] > 0 )
1339
bp->hostInputFrameCount[0] -= frameCount;
1341
bp->hostInputFrameCount[1] -= frameCount;
1343
bp->framesInTempInputBuffer += frameCount;
1345
/* update framesAvailable and framesProcessed based on input consumed
1346
unless something is very wrong this will also correspond to the
1347
amount of output generated */
1348
framesAvailable -= frameCount;
1349
framesProcessed += frameCount;
1352
/* call streamCallback */
1353
if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
1354
bp->framesInTempOutputBuffer == 0 )
1356
if( *streamCallbackResult == paContinue )
1358
/* setup userInput */
1359
if( bp->userInputIsInterleaved )
1361
userInput = bp->tempInputBuffer;
1363
else /* user input is not interleaved */
1365
for( i = 0; i < bp->inputChannelCount; ++i )
1367
bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
1368
i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1371
userInput = bp->tempInputBufferPtrs;
1374
/* setup userOutput */
1375
if( bp->userOutputIsInterleaved )
1377
userOutput = bp->tempOutputBuffer;
1379
else /* user output is not interleaved */
1381
for( i = 0; i < bp->outputChannelCount; ++i )
1383
bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
1384
i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1387
userOutput = bp->tempOutputBufferPtrs;
1390
/* call streamCallback */
1392
*streamCallbackResult = bp->streamCallback( userInput, userOutput,
1393
bp->framesPerUserBuffer, bp->timeInfo,
1394
bp->callbackStatusFlags, bp->userData );
1396
bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
1397
bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
1399
bp->framesInTempInputBuffer = 0;
1401
if( *streamCallbackResult == paAbort )
1402
bp->framesInTempOutputBuffer = 0;
1404
bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
1408
/* paComplete or paAbort has already been called. */
1410
bp->framesInTempInputBuffer = 0;
1414
/* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels)
1415
Means to process the user output provided by the callback. Has to be called after
1417
CopyTempOutputBuffersToHostOutputBuffers( bp );
1421
return framesProcessed;
1425
unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
1427
unsigned long framesToProcess, framesToGo;
1428
unsigned long framesProcessed = 0;
1430
if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
1431
&& bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
1432
&& bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
1434
assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
1435
(bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
1438
assert( *streamCallbackResult == paContinue
1439
|| *streamCallbackResult == paComplete
1440
|| *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
1442
if( bp->useNonAdaptingProcess )
1444
if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
1446
/* full duplex non-adapting process, splice buffers if they are
1447
different lengths */
1449
framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
1452
unsigned long noInputInputFrameCount;
1453
unsigned long *hostInputFrameCount;
1454
PaUtilChannelDescriptor *hostInputChannels;
1455
unsigned long noOutputOutputFrameCount;
1456
unsigned long *hostOutputFrameCount;
1457
PaUtilChannelDescriptor *hostOutputChannels;
1458
unsigned long framesProcessedThisIteration;
1460
if( !bp->hostInputChannels[0][0].data )
1462
/* no input was supplied (see PaUtil_SetNoInput)
1463
NonAdaptingProcess knows how to deal with this
1465
noInputInputFrameCount = framesToGo;
1466
hostInputFrameCount = &noInputInputFrameCount;
1467
hostInputChannels = 0;
1469
else if( bp->hostInputFrameCount[0] != 0 )
1471
hostInputFrameCount = &bp->hostInputFrameCount[0];
1472
hostInputChannels = bp->hostInputChannels[0];
1476
hostInputFrameCount = &bp->hostInputFrameCount[1];
1477
hostInputChannels = bp->hostInputChannels[1];
1480
if( !bp->hostOutputChannels[0][0].data )
1482
/* no output was supplied (see PaUtil_SetNoOutput)
1483
NonAdaptingProcess knows how to deal with this
1485
noOutputOutputFrameCount = framesToGo;
1486
hostOutputFrameCount = &noOutputOutputFrameCount;
1487
hostOutputChannels = 0;
1489
if( bp->hostOutputFrameCount[0] != 0 )
1491
hostOutputFrameCount = &bp->hostOutputFrameCount[0];
1492
hostOutputChannels = bp->hostOutputChannels[0];
1496
hostOutputFrameCount = &bp->hostOutputFrameCount[1];
1497
hostOutputChannels = bp->hostOutputChannels[1];
1500
framesToProcess = PA_MIN_( *hostInputFrameCount,
1501
*hostOutputFrameCount );
1503
assert( framesToProcess != 0 );
1505
framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
1506
hostInputChannels, hostOutputChannels,
1509
*hostInputFrameCount -= framesProcessedThisIteration;
1510
*hostOutputFrameCount -= framesProcessedThisIteration;
1512
framesProcessed += framesProcessedThisIteration;
1513
framesToGo -= framesProcessedThisIteration;
1515
}while( framesToGo > 0 );
1519
/* half duplex non-adapting process, just process 1st and 2nd buffer */
1520
/* process first buffer */
1522
framesToProcess = (bp->inputChannelCount != 0)
1523
? bp->hostInputFrameCount[0]
1524
: bp->hostOutputFrameCount[0];
1526
framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
1527
bp->hostInputChannels[0], bp->hostOutputChannels[0],
1530
/* process second buffer if provided */
1532
framesToProcess = (bp->inputChannelCount != 0)
1533
? bp->hostInputFrameCount[1]
1534
: bp->hostOutputFrameCount[1];
1535
if( framesToProcess > 0 )
1537
framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
1538
bp->hostInputChannels[1], bp->hostOutputChannels[1],
1543
else /* block adaption necessary*/
1546
if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
1550
if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed )
1552
framesProcessed = AdaptingProcess( bp, streamCallbackResult,
1553
0 /* dont process partial user buffers */ );
1557
framesProcessed = AdaptingProcess( bp, streamCallbackResult,
1558
1 /* process partial user buffers */ );
1561
else if( bp->inputChannelCount != 0 )
1564
framesToProcess = bp->hostInputFrameCount[0];
1566
framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
1567
bp->hostInputChannels[0], framesToProcess );
1569
framesToProcess = bp->hostInputFrameCount[1];
1570
if( framesToProcess > 0 )
1572
framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
1573
bp->hostInputChannels[1], framesToProcess );
1579
framesToProcess = bp->hostOutputFrameCount[0];
1581
framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
1582
bp->hostOutputChannels[0], framesToProcess );
1584
framesToProcess = bp->hostOutputFrameCount[1];
1585
if( framesToProcess > 0 )
1587
framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
1588
bp->hostOutputChannels[1], framesToProcess );
1593
return framesProcessed;
1597
int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
1599
return (bp->framesInTempOutputBuffer) ? 0 : 1;
1603
unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
1604
void **buffer, unsigned long frameCount )
1606
PaUtilChannelDescriptor *hostInputChannels;
1607
unsigned int framesToCopy;
1608
unsigned char *destBytePtr;
1609
void **nonInterleavedDestPtrs;
1610
unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1611
unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
1614
hostInputChannels = bp->hostInputChannels[0];
1615
framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
1617
if( bp->userInputIsInterleaved )
1619
destBytePtr = (unsigned char*)*buffer;
1621
destSampleStrideSamples = bp->inputChannelCount;
1622
destChannelStrideBytes = bp->bytesPerUserInputSample;
1624
for( i=0; i<bp->inputChannelCount; ++i )
1626
bp->inputConverter( destBytePtr, destSampleStrideSamples,
1627
hostInputChannels[i].data,
1628
hostInputChannels[i].stride,
1629
framesToCopy, &bp->ditherGenerator );
1631
destBytePtr += destChannelStrideBytes; /* skip to next source channel */
1633
/* advance dest ptr for next iteration */
1634
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1635
framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1638
/* advance callers dest pointer (buffer) */
1639
*buffer = ((unsigned char *)*buffer) +
1640
framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
1644
/* user input is not interleaved */
1646
nonInterleavedDestPtrs = (void**)*buffer;
1648
destSampleStrideSamples = 1;
1650
for( i=0; i<bp->inputChannelCount; ++i )
1652
destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
1654
bp->inputConverter( destBytePtr, destSampleStrideSamples,
1655
hostInputChannels[i].data,
1656
hostInputChannels[i].stride,
1657
framesToCopy, &bp->ditherGenerator );
1659
/* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
1660
destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
1661
nonInterleavedDestPtrs[i] = destBytePtr;
1663
/* advance dest ptr for next iteration */
1664
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1665
framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1669
bp->hostInputFrameCount[0] -= framesToCopy;
1671
return framesToCopy;
1674
unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
1675
const void ** buffer, unsigned long frameCount )
1677
PaUtilChannelDescriptor *hostOutputChannels;
1678
unsigned int framesToCopy;
1679
unsigned char *srcBytePtr;
1680
void **nonInterleavedSrcPtrs;
1681
unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1682
unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1685
hostOutputChannels = bp->hostOutputChannels[0];
1686
framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
1688
if( bp->userOutputIsInterleaved )
1690
srcBytePtr = (unsigned char*)*buffer;
1692
srcSampleStrideSamples = bp->outputChannelCount;
1693
srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1695
for( i=0; i<bp->outputChannelCount; ++i )
1697
bp->outputConverter( hostOutputChannels[i].data,
1698
hostOutputChannels[i].stride,
1699
srcBytePtr, srcSampleStrideSamples,
1700
framesToCopy, &bp->ditherGenerator );
1702
srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
1704
/* advance dest ptr for next iteration */
1705
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1706
framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1709
/* advance callers source pointer (buffer) */
1710
*buffer = ((unsigned char *)*buffer) +
1711
framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
1716
/* user output is not interleaved */
1718
nonInterleavedSrcPtrs = (void**)*buffer;
1720
srcSampleStrideSamples = 1;
1722
for( i=0; i<bp->outputChannelCount; ++i )
1724
srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
1726
bp->outputConverter( hostOutputChannels[i].data,
1727
hostOutputChannels[i].stride,
1728
srcBytePtr, srcSampleStrideSamples,
1729
framesToCopy, &bp->ditherGenerator );
1732
/* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
1733
srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
1734
nonInterleavedSrcPtrs[i] = srcBytePtr;
1736
/* advance dest ptr for next iteration */
1737
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1738
framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1742
bp->hostOutputFrameCount[0] += framesToCopy;
1744
return framesToCopy;
1748
unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
1750
PaUtilChannelDescriptor *hostOutputChannels;
1751
unsigned int framesToZero;
1754
hostOutputChannels = bp->hostOutputChannels[0];
1755
framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
1757
for( i=0; i<bp->outputChannelCount; ++i )
1759
bp->outputZeroer( hostOutputChannels[i].data,
1760
hostOutputChannels[i].stride,
1764
/* advance dest ptr for next iteration */
1765
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1766
framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1769
bp->hostOutputFrameCount[0] += framesToZero;
1771
return framesToZero;