/[pcsx2_0.9.7]/trunk/3rdparty/portaudio/src/common/pa_process.c
ViewVC logotype

Annotation of /trunk/3rdparty/portaudio/src/common/pa_process.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22