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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations) (download)
Mon Sep 6 11:40:06 2010 UTC (9 years, 11 months ago) by william
File MIME type: text/plain
File size: 66345 byte(s)
exported r3113 from ./upstream/trunk
1 /*
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