/[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 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 2 months ago) by william
File MIME type: text/plain
File size: 68779 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-latest) in ./trunk
1 /*
2 * $Id: pa_process.c 1523 2010-07-10 17:41:25Z dmitrykos $
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 bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1;
268
269 bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved));
270
271 tempInputBufferSize =
272 bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
273
274 bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
275 if( bp->tempInputBuffer == 0 )
276 {
277 result = paInsufficientMemory;
278 goto error;
279 }
280
281 if( bp->framesInTempInputBuffer > 0 )
282 memset( bp->tempInputBuffer, 0, tempInputBufferSize );
283
284 if( userInputSampleFormat & paNonInterleaved )
285 {
286 bp->tempInputBufferPtrs =
287 (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
288 if( bp->tempInputBufferPtrs == 0 )
289 {
290 result = paInsufficientMemory;
291 goto error;
292 }
293 }
294
295 bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
296 PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
297 if( bp->hostInputChannels[0] == 0 )
298 {
299 result = paInsufficientMemory;
300 goto error;
301 }
302
303 bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
304 }
305
306 if( outputChannelCount > 0 )
307 {
308 bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
309 if( bytesPerSample > 0 )
310 {
311 bp->bytesPerHostOutputSample = bytesPerSample;
312 }
313 else
314 {
315 result = bytesPerSample;
316 goto error;
317 }
318
319 bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
320 if( bytesPerSample > 0 )
321 {
322 bp->bytesPerUserOutputSample = bytesPerSample;
323 }
324 else
325 {
326 result = bytesPerSample;
327 goto error;
328 }
329
330 bp->outputConverter =
331 PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
332
333 bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
334
335 bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
336
337 bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1;
338
339 bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved));
340
341 tempOutputBufferSize =
342 bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
343
344 bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
345 if( bp->tempOutputBuffer == 0 )
346 {
347 result = paInsufficientMemory;
348 goto error;
349 }
350
351 if( bp->framesInTempOutputBuffer > 0 )
352 memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
353
354 if( userOutputSampleFormat & paNonInterleaved )
355 {
356 bp->tempOutputBufferPtrs =
357 (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
358 if( bp->tempOutputBufferPtrs == 0 )
359 {
360 result = paInsufficientMemory;
361 goto error;
362 }
363 }
364
365 bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
366 PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
367 if( bp->hostOutputChannels[0] == 0 )
368 {
369 result = paInsufficientMemory;
370 goto error;
371 }
372
373 bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
374 }
375
376 PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
377
378 bp->samplePeriod = 1. / sampleRate;
379
380 bp->streamCallback = streamCallback;
381 bp->userData = userData;
382
383 return result;
384
385 error:
386 if( bp->tempInputBuffer )
387 PaUtil_FreeMemory( bp->tempInputBuffer );
388
389 if( bp->tempInputBufferPtrs )
390 PaUtil_FreeMemory( bp->tempInputBufferPtrs );
391
392 if( bp->hostInputChannels[0] )
393 PaUtil_FreeMemory( bp->hostInputChannels[0] );
394
395 if( bp->tempOutputBuffer )
396 PaUtil_FreeMemory( bp->tempOutputBuffer );
397
398 if( bp->tempOutputBufferPtrs )
399 PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
400
401 if( bp->hostOutputChannels[0] )
402 PaUtil_FreeMemory( bp->hostOutputChannels[0] );
403
404 return result;
405 }
406
407
408 void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
409 {
410 if( bp->tempInputBuffer )
411 PaUtil_FreeMemory( bp->tempInputBuffer );
412
413 if( bp->tempInputBufferPtrs )
414 PaUtil_FreeMemory( bp->tempInputBufferPtrs );
415
416 if( bp->hostInputChannels[0] )
417 PaUtil_FreeMemory( bp->hostInputChannels[0] );
418
419 if( bp->tempOutputBuffer )
420 PaUtil_FreeMemory( bp->tempOutputBuffer );
421
422 if( bp->tempOutputBufferPtrs )
423 PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
424
425 if( bp->hostOutputChannels[0] )
426 PaUtil_FreeMemory( bp->hostOutputChannels[0] );
427 }
428
429
430 void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
431 {
432 unsigned long tempInputBufferSize, tempOutputBufferSize;
433
434 bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
435 bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
436
437 if( bp->framesInTempInputBuffer > 0 )
438 {
439 tempInputBufferSize =
440 bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
441 memset( bp->tempInputBuffer, 0, tempInputBufferSize );
442 }
443
444 if( bp->framesInTempOutputBuffer > 0 )
445 {
446 tempOutputBufferSize =
447 bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
448 memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
449 }
450 }
451
452
453 unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp )
454 {
455 return bp->initialFramesInTempInputBuffer;
456 }
457
458
459 unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bp )
460 {
461 return bp->initialFramesInTempOutputBuffer;
462 }
463
464
465 void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
466 unsigned long frameCount )
467 {
468 if( frameCount == 0 )
469 bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
470 else
471 bp->hostInputFrameCount[0] = frameCount;
472 }
473
474
475 void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
476 {
477 assert( bp->inputChannelCount > 0 );
478
479 bp->hostInputChannels[0][0].data = 0;
480 }
481
482
483 void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
484 unsigned int channel, void *data, unsigned int stride )
485 {
486 assert( channel < bp->inputChannelCount );
487
488 bp->hostInputChannels[0][channel].data = data;
489 bp->hostInputChannels[0][channel].stride = stride;
490 }
491
492
493 void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
494 unsigned int firstChannel, void *data, unsigned int channelCount )
495 {
496 unsigned int i;
497 unsigned int channel = firstChannel;
498 unsigned char *p = (unsigned char*)data;
499
500 if( channelCount == 0 )
501 channelCount = bp->inputChannelCount;
502
503 assert( firstChannel < bp->inputChannelCount );
504 assert( firstChannel + channelCount <= bp->inputChannelCount );
505 assert( bp->hostInputIsInterleaved );
506
507 for( i=0; i< channelCount; ++i )
508 {
509 bp->hostInputChannels[0][channel+i].data = p;
510 p += bp->bytesPerHostInputSample;
511 bp->hostInputChannels[0][channel+i].stride = channelCount;
512 }
513 }
514
515
516 void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
517 unsigned int channel, void *data )
518 {
519 assert( channel < bp->inputChannelCount );
520 assert( !bp->hostInputIsInterleaved );
521
522 bp->hostInputChannels[0][channel].data = data;
523 bp->hostInputChannels[0][channel].stride = 1;
524 }
525
526
527 void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
528 unsigned long frameCount )
529 {
530 bp->hostInputFrameCount[1] = frameCount;
531 }
532
533
534 void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
535 unsigned int channel, void *data, unsigned int stride )
536 {
537 assert( channel < bp->inputChannelCount );
538
539 bp->hostInputChannels[1][channel].data = data;
540 bp->hostInputChannels[1][channel].stride = stride;
541 }
542
543
544 void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
545 unsigned int firstChannel, void *data, unsigned int channelCount )
546 {
547 unsigned int i;
548 unsigned int channel = firstChannel;
549 unsigned char *p = (unsigned char*)data;
550
551 if( channelCount == 0 )
552 channelCount = bp->inputChannelCount;
553
554 assert( firstChannel < bp->inputChannelCount );
555 assert( firstChannel + channelCount <= bp->inputChannelCount );
556 assert( bp->hostInputIsInterleaved );
557
558 for( i=0; i< channelCount; ++i )
559 {
560 bp->hostInputChannels[1][channel+i].data = p;
561 p += bp->bytesPerHostInputSample;
562 bp->hostInputChannels[1][channel+i].stride = channelCount;
563 }
564 }
565
566
567 void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
568 unsigned int channel, void *data )
569 {
570 assert( channel < bp->inputChannelCount );
571 assert( !bp->hostInputIsInterleaved );
572
573 bp->hostInputChannels[1][channel].data = data;
574 bp->hostInputChannels[1][channel].stride = 1;
575 }
576
577
578 void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
579 unsigned long frameCount )
580 {
581 if( frameCount == 0 )
582 bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
583 else
584 bp->hostOutputFrameCount[0] = frameCount;
585 }
586
587
588 void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
589 {
590 assert( bp->outputChannelCount > 0 );
591
592 bp->hostOutputChannels[0][0].data = 0;
593 }
594
595
596 void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
597 unsigned int channel, void *data, unsigned int stride )
598 {
599 assert( channel < bp->outputChannelCount );
600 assert( data != NULL );
601
602 bp->hostOutputChannels[0][channel].data = data;
603 bp->hostOutputChannels[0][channel].stride = stride;
604 }
605
606
607 void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
608 unsigned int firstChannel, void *data, unsigned int channelCount )
609 {
610 unsigned int i;
611 unsigned int channel = firstChannel;
612 unsigned char *p = (unsigned char*)data;
613
614 if( channelCount == 0 )
615 channelCount = bp->outputChannelCount;
616
617 assert( firstChannel < bp->outputChannelCount );
618 assert( firstChannel + channelCount <= bp->outputChannelCount );
619 assert( bp->hostOutputIsInterleaved );
620
621 for( i=0; i< channelCount; ++i )
622 {
623 PaUtil_SetOutputChannel( bp, channel + i, p, channelCount );
624 p += bp->bytesPerHostOutputSample;
625 }
626 }
627
628
629 void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
630 unsigned int channel, void *data )
631 {
632 assert( channel < bp->outputChannelCount );
633 assert( !bp->hostOutputIsInterleaved );
634
635 PaUtil_SetOutputChannel( bp, channel, data, 1 );
636 }
637
638
639 void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
640 unsigned long frameCount )
641 {
642 bp->hostOutputFrameCount[1] = frameCount;
643 }
644
645
646 void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
647 unsigned int channel, void *data, unsigned int stride )
648 {
649 assert( channel < bp->outputChannelCount );
650 assert( data != NULL );
651
652 bp->hostOutputChannels[1][channel].data = data;
653 bp->hostOutputChannels[1][channel].stride = stride;
654 }
655
656
657 void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
658 unsigned int firstChannel, void *data, unsigned int channelCount )
659 {
660 unsigned int i;
661 unsigned int channel = firstChannel;
662 unsigned char *p = (unsigned char*)data;
663
664 if( channelCount == 0 )
665 channelCount = bp->outputChannelCount;
666
667 assert( firstChannel < bp->outputChannelCount );
668 assert( firstChannel + channelCount <= bp->outputChannelCount );
669 assert( bp->hostOutputIsInterleaved );
670
671 for( i=0; i< channelCount; ++i )
672 {
673 PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount );
674 p += bp->bytesPerHostOutputSample;
675 }
676 }
677
678
679 void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
680 unsigned int channel, void *data )
681 {
682 assert( channel < bp->outputChannelCount );
683 assert( !bp->hostOutputIsInterleaved );
684
685 PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
686 }
687
688
689 void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
690 PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
691 {
692 bp->timeInfo = timeInfo;
693
694 /* the first streamCallback will be called to process samples which are
695 currently in the input buffer before the ones starting at the timeInfo time */
696
697 bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
698
699 /* We just pass through timeInfo->currentTime provided by the caller. This is
700 not strictly conformant to the word of the spec, since the buffer processor
701 might call the callback multiple times, and we never refresh currentTime. */
702
703 /* the first streamCallback will be called to generate samples which will be
704 outputted after the frames currently in the output buffer have been
705 outputted. */
706 bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
707
708 bp->callbackStatusFlags = callbackStatusFlags;
709
710 bp->hostInputFrameCount[1] = 0;
711 bp->hostOutputFrameCount[1] = 0;
712 }
713
714
715 /*
716 NonAdaptingProcess() is a simple buffer copying adaptor that can handle
717 both full and half duplex copies. It processes framesToProcess frames,
718 broken into blocks bp->framesPerTempBuffer long.
719 This routine can be used when the streamCallback doesn't care what length
720 the buffers are, or when framesToProcess is an integer multiple of
721 bp->framesPerTempBuffer, in which case streamCallback will always be called
722 with bp->framesPerTempBuffer samples.
723 */
724 static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
725 int *streamCallbackResult,
726 PaUtilChannelDescriptor *hostInputChannels,
727 PaUtilChannelDescriptor *hostOutputChannels,
728 unsigned long framesToProcess )
729 {
730 void *userInput, *userOutput;
731 unsigned char *srcBytePtr, *destBytePtr;
732 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
733 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
734 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
735 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
736 unsigned int i;
737 unsigned long frameCount;
738 unsigned long framesToGo = framesToProcess;
739 unsigned long framesProcessed = 0;
740 int skipOutputConvert = 0;
741 int skipInputConvert = 0;
742
743
744 if( *streamCallbackResult == paContinue )
745 {
746 do
747 {
748 frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
749
750 /* configure user input buffer and convert input data (host -> user) */
751 if( bp->inputChannelCount == 0 )
752 {
753 /* no input */
754 userInput = 0;
755 }
756 else /* there are input channels */
757 {
758
759 destBytePtr = (unsigned char *)bp->tempInputBuffer;
760
761 if( bp->userInputIsInterleaved )
762 {
763 destSampleStrideSamples = bp->inputChannelCount;
764 destChannelStrideBytes = bp->bytesPerUserInputSample;
765
766 /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */
767 if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved )
768 {
769 userInput = hostInputChannels[0].data;
770 destBytePtr = (unsigned char *)hostInputChannels[0].data;
771 skipInputConvert = 1;
772 }
773 else
774 {
775 userInput = bp->tempInputBuffer;
776 }
777 }
778 else /* user input is not interleaved */
779 {
780 destSampleStrideSamples = 1;
781 destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
782
783 /* setup non-interleaved ptrs */
784 if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved )
785 {
786 for( i=0; i<bp->inputChannelCount; ++i )
787 {
788 bp->tempInputBufferPtrs[i] = hostInputChannels[i].data;
789 }
790 skipInputConvert = 1;
791 }
792 else
793 {
794 for( i=0; i<bp->inputChannelCount; ++i )
795 {
796 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
797 i * bp->bytesPerUserInputSample * frameCount;
798 }
799 }
800
801 userInput = bp->tempInputBufferPtrs;
802 }
803
804 if( !bp->hostInputChannels[0][0].data )
805 {
806 /* no input was supplied (see PaUtil_SetNoInput), so
807 zero the input buffer */
808
809 for( i=0; i<bp->inputChannelCount; ++i )
810 {
811 bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
812 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
813 }
814 }
815 else
816 {
817 if( skipInputConvert )
818 {
819 for( i=0; i<bp->inputChannelCount; ++i )
820 {
821 /* advance src ptr for next iteration */
822 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
823 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
824 }
825 }
826 else
827 {
828 for( i=0; i<bp->inputChannelCount; ++i )
829 {
830 bp->inputConverter( destBytePtr, destSampleStrideSamples,
831 hostInputChannels[i].data,
832 hostInputChannels[i].stride,
833 frameCount, &bp->ditherGenerator );
834
835 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
836
837 /* advance src ptr for next iteration */
838 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
839 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
840 }
841 }
842 }
843 }
844
845 /* configure user output buffer */
846 if( bp->outputChannelCount == 0 )
847 {
848 /* no output */
849 userOutput = 0;
850 }
851 else /* there are output channels */
852 {
853 if( bp->userOutputIsInterleaved )
854 {
855 /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */
856 if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved )
857 {
858 userOutput = hostOutputChannels[0].data;
859 skipOutputConvert = 1;
860 }
861 else
862 {
863 userOutput = bp->tempOutputBuffer;
864 }
865 }
866 else /* user output is not interleaved */
867 {
868 if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved )
869 {
870 for( i=0; i<bp->outputChannelCount; ++i )
871 {
872 bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data;
873 }
874 skipOutputConvert = 1;
875 }
876 else
877 {
878 for( i=0; i<bp->outputChannelCount; ++i )
879 {
880 bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
881 i * bp->bytesPerUserOutputSample * frameCount;
882 }
883 }
884
885 userOutput = bp->tempOutputBufferPtrs;
886 }
887 }
888
889 *streamCallbackResult = bp->streamCallback( userInput, userOutput,
890 frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
891
892 if( *streamCallbackResult == paAbort )
893 {
894 /* callback returned paAbort, don't advance framesProcessed
895 and framesToGo, they will be handled below */
896 }
897 else
898 {
899 bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
900 bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
901
902 /* convert output data (user -> host) */
903
904 if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
905 {
906 if( skipOutputConvert )
907 {
908 for( i=0; i<bp->outputChannelCount; ++i )
909 {
910 /* advance dest ptr for next iteration */
911 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
912 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
913 }
914 }
915 else
916 {
917
918 srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
919
920 if( bp->userOutputIsInterleaved )
921 {
922 srcSampleStrideSamples = bp->outputChannelCount;
923 srcChannelStrideBytes = bp->bytesPerUserOutputSample;
924 }
925 else /* user output is not interleaved */
926 {
927 srcSampleStrideSamples = 1;
928 srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
929 }
930
931 for( i=0; i<bp->outputChannelCount; ++i )
932 {
933 bp->outputConverter( hostOutputChannels[i].data,
934 hostOutputChannels[i].stride,
935 srcBytePtr, srcSampleStrideSamples,
936 frameCount, &bp->ditherGenerator );
937
938 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
939
940 /* advance dest ptr for next iteration */
941 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
942 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
943 }
944 }
945 }
946
947 framesProcessed += frameCount;
948
949 framesToGo -= frameCount;
950 }
951 }
952 while( framesToGo > 0 && *streamCallbackResult == paContinue );
953 }
954
955 if( framesToGo > 0 )
956 {
957 /* zero any remaining frames output. There will only be remaining frames
958 if the callback has returned paComplete or paAbort */
959
960 frameCount = framesToGo;
961
962 if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
963 {
964 for( i=0; i<bp->outputChannelCount; ++i )
965 {
966 bp->outputZeroer( hostOutputChannels[i].data,
967 hostOutputChannels[i].stride,
968 frameCount );
969
970 /* advance dest ptr for next iteration */
971 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
972 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
973 }
974 }
975
976 framesProcessed += frameCount;
977 }
978
979 return framesProcessed;
980 }
981
982
983 /*
984 AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
985 converts data from the input buffers into the temporary input buffer,
986 when the temporary input buffer is full, it calls the streamCallback.
987 */
988 static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
989 int *streamCallbackResult,
990 PaUtilChannelDescriptor *hostInputChannels,
991 unsigned long framesToProcess )
992 {
993 void *userInput, *userOutput;
994 unsigned char *destBytePtr;
995 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
996 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
997 unsigned int i;
998 unsigned long frameCount;
999 unsigned long framesToGo = framesToProcess;
1000 unsigned long framesProcessed = 0;
1001
1002 userOutput = 0;
1003
1004 do
1005 {
1006 frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
1007 ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
1008 : framesToGo;
1009
1010 /* convert frameCount samples into temp buffer */
1011
1012 if( bp->userInputIsInterleaved )
1013 {
1014 destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1015 bp->bytesPerUserInputSample * bp->inputChannelCount *
1016 bp->framesInTempInputBuffer;
1017
1018 destSampleStrideSamples = bp->inputChannelCount;
1019 destChannelStrideBytes = bp->bytesPerUserInputSample;
1020
1021 userInput = bp->tempInputBuffer;
1022 }
1023 else /* user input is not interleaved */
1024 {
1025 destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1026 bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
1027
1028 destSampleStrideSamples = 1;
1029 destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1030
1031 /* setup non-interleaved ptrs */
1032 for( i=0; i<bp->inputChannelCount; ++i )
1033 {
1034 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
1035 i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
1036 }
1037
1038 userInput = bp->tempInputBufferPtrs;
1039 }
1040
1041 for( i=0; i<bp->inputChannelCount; ++i )
1042 {
1043 bp->inputConverter( destBytePtr, destSampleStrideSamples,
1044 hostInputChannels[i].data,
1045 hostInputChannels[i].stride,
1046 frameCount, &bp->ditherGenerator );
1047
1048 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
1049
1050 /* advance src ptr for next iteration */
1051 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1052 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1053 }
1054
1055 bp->framesInTempInputBuffer += frameCount;
1056
1057 if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
1058 {
1059 /**
1060 @todo (non-critical optimisation)
1061 The conditional below implements the continue/complete/abort mechanism
1062 simply by continuing on iterating through the input buffer, but not
1063 passing the data to the callback. With care, the outer loop could be
1064 terminated earlier, thus some unneeded conversion cycles would be
1065 saved.
1066 */
1067 if( *streamCallbackResult == paContinue )
1068 {
1069 bp->timeInfo->outputBufferDacTime = 0;
1070
1071 *streamCallbackResult = bp->streamCallback( userInput, userOutput,
1072 bp->framesPerUserBuffer, bp->timeInfo,
1073 bp->callbackStatusFlags, bp->userData );
1074
1075 bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
1076 }
1077
1078 bp->framesInTempInputBuffer = 0;
1079 }
1080
1081 framesProcessed += frameCount;
1082
1083 framesToGo -= frameCount;
1084 }while( framesToGo > 0 );
1085
1086 return framesProcessed;
1087 }
1088
1089
1090 /*
1091 AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
1092 It converts data from the temporary output buffer, to the output buffers,
1093 when the temporary output buffer is empty, it calls the streamCallback.
1094 */
1095 static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
1096 int *streamCallbackResult,
1097 PaUtilChannelDescriptor *hostOutputChannels,
1098 unsigned long framesToProcess )
1099 {
1100 void *userInput, *userOutput;
1101 unsigned char *srcBytePtr;
1102 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1103 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1104 unsigned int i;
1105 unsigned long frameCount;
1106 unsigned long framesToGo = framesToProcess;
1107 unsigned long framesProcessed = 0;
1108
1109 do
1110 {
1111 if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
1112 {
1113 userInput = 0;
1114
1115 /* setup userOutput */
1116 if( bp->userOutputIsInterleaved )
1117 {
1118 userOutput = bp->tempOutputBuffer;
1119 }
1120 else /* user output is not interleaved */
1121 {
1122 for( i = 0; i < bp->outputChannelCount; ++i )
1123 {
1124 bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
1125 i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1126 }
1127
1128 userOutput = bp->tempOutputBufferPtrs;
1129 }
1130
1131 bp->timeInfo->inputBufferAdcTime = 0;
1132
1133 *streamCallbackResult = bp->streamCallback( userInput, userOutput,
1134 bp->framesPerUserBuffer, bp->timeInfo,
1135 bp->callbackStatusFlags, bp->userData );
1136
1137 if( *streamCallbackResult == paAbort )
1138 {
1139 /* if the callback returned paAbort, we disregard its output */
1140 }
1141 else
1142 {
1143 bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
1144
1145 bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
1146 }
1147 }
1148
1149 if( bp->framesInTempOutputBuffer > 0 )
1150 {
1151 /* convert frameCount frames from user buffer to host buffer */
1152
1153 frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
1154
1155 if( bp->userOutputIsInterleaved )
1156 {
1157 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1158 bp->bytesPerUserOutputSample * bp->outputChannelCount *
1159 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1160
1161 srcSampleStrideSamples = bp->outputChannelCount;
1162 srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1163 }
1164 else /* user output is not interleaved */
1165 {
1166 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1167 bp->bytesPerUserOutputSample *
1168 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1169
1170 srcSampleStrideSamples = 1;
1171 srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1172 }
1173
1174 for( i=0; i<bp->outputChannelCount; ++i )
1175 {
1176 bp->outputConverter( hostOutputChannels[i].data,
1177 hostOutputChannels[i].stride,
1178 srcBytePtr, srcSampleStrideSamples,
1179 frameCount, &bp->ditherGenerator );
1180
1181 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
1182
1183 /* advance dest ptr for next iteration */
1184 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1185 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1186 }
1187
1188 bp->framesInTempOutputBuffer -= frameCount;
1189 }
1190 else
1191 {
1192 /* no more user data is available because the callback has returned
1193 paComplete or paAbort. Fill the remainder of the host buffer
1194 with zeros.
1195 */
1196
1197 frameCount = framesToGo;
1198
1199 for( i=0; i<bp->outputChannelCount; ++i )
1200 {
1201 bp->outputZeroer( hostOutputChannels[i].data,
1202 hostOutputChannels[i].stride,
1203 frameCount );
1204
1205 /* advance dest ptr for next iteration */
1206 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1207 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1208 }
1209 }
1210
1211 framesProcessed += frameCount;
1212
1213 framesToGo -= frameCount;
1214
1215 }while( framesToGo > 0 );
1216
1217 return framesProcessed;
1218 }
1219
1220 /* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
1221 tempOutputBuffer to hostOutputChannels. This includes data conversion
1222 and interleaving.
1223 */
1224 static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
1225 {
1226 unsigned long maxFramesToCopy;
1227 PaUtilChannelDescriptor *hostOutputChannels;
1228 unsigned int frameCount;
1229 unsigned char *srcBytePtr;
1230 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1231 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1232 unsigned int i;
1233
1234 /* copy frames from user to host output buffers */
1235 while( bp->framesInTempOutputBuffer > 0 &&
1236 ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
1237 {
1238 maxFramesToCopy = bp->framesInTempOutputBuffer;
1239
1240 /* select the output buffer set (1st or 2nd) */
1241 if( bp->hostOutputFrameCount[0] > 0 )
1242 {
1243 hostOutputChannels = bp->hostOutputChannels[0];
1244 frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
1245 }
1246 else
1247 {
1248 hostOutputChannels = bp->hostOutputChannels[1];
1249 frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
1250 }
1251
1252 if( bp->userOutputIsInterleaved )
1253 {
1254 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1255 bp->bytesPerUserOutputSample * bp->outputChannelCount *
1256 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1257
1258 srcSampleStrideSamples = bp->outputChannelCount;
1259 srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1260 }
1261 else /* user output is not interleaved */
1262 {
1263 srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1264 bp->bytesPerUserOutputSample *
1265 (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1266
1267 srcSampleStrideSamples = 1;
1268 srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1269 }
1270
1271 for( i=0; i<bp->outputChannelCount; ++i )
1272 {
1273 assert( hostOutputChannels[i].data != NULL );
1274 bp->outputConverter( hostOutputChannels[i].data,
1275 hostOutputChannels[i].stride,
1276 srcBytePtr, srcSampleStrideSamples,
1277 frameCount, &bp->ditherGenerator );
1278
1279 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
1280
1281 /* advance dest ptr for next iteration */
1282 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1283 frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1284 }
1285
1286 if( bp->hostOutputFrameCount[0] > 0 )
1287 bp->hostOutputFrameCount[0] -= frameCount;
1288 else
1289 bp->hostOutputFrameCount[1] -= frameCount;
1290
1291 bp->framesInTempOutputBuffer -= frameCount;
1292 }
1293 }
1294
1295 /*
1296 AdaptingProcess is a full duplex adapting buffer processor. It converts
1297 data from the temporary output buffer into the host output buffers, then
1298 from the host input buffers into the temporary input buffers. Calling the
1299 streamCallback when necessary.
1300 When processPartialUserBuffers is 0, all available input data will be
1301 consumed and all available output space will be filled. When
1302 processPartialUserBuffers is non-zero, as many full user buffers
1303 as possible will be processed, but partial buffers will not be consumed.
1304 */
1305 static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
1306 int *streamCallbackResult, int processPartialUserBuffers )
1307 {
1308 void *userInput, *userOutput;
1309 unsigned long framesProcessed = 0;
1310 unsigned long framesAvailable;
1311 unsigned long endProcessingMinFrameCount;
1312 unsigned long maxFramesToCopy;
1313 PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
1314 unsigned int frameCount;
1315 unsigned char *destBytePtr;
1316 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1317 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
1318 unsigned int i, j;
1319
1320
1321 framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
1322
1323 if( processPartialUserBuffers )
1324 endProcessingMinFrameCount = 0;
1325 else
1326 endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
1327
1328 /* Fill host output with remaining frames in user output (tempOutputBuffer) */
1329 CopyTempOutputBuffersToHostOutputBuffers( bp );
1330
1331 while( framesAvailable > endProcessingMinFrameCount )
1332 {
1333
1334 if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
1335 {
1336 /* the callback will not be called any more, so zero what remains
1337 of the host output buffers */
1338
1339 for( i=0; i<2; ++i )
1340 {
1341 frameCount = bp->hostOutputFrameCount[i];
1342 if( frameCount > 0 )
1343 {
1344 hostOutputChannels = bp->hostOutputChannels[i];
1345
1346 for( j=0; j<bp->outputChannelCount; ++j )
1347 {
1348 bp->outputZeroer( hostOutputChannels[j].data,
1349 hostOutputChannels[j].stride,
1350 frameCount );
1351
1352 /* advance dest ptr for next iteration */
1353 hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
1354 frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
1355 }
1356 bp->hostOutputFrameCount[i] = 0;
1357 }
1358 }
1359 }
1360
1361
1362 /* copy frames from host to user input buffers */
1363 while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
1364 ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
1365 {
1366 maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
1367
1368 /* select the input buffer set (1st or 2nd) */
1369 if( bp->hostInputFrameCount[0] > 0 )
1370 {
1371 hostInputChannels = bp->hostInputChannels[0];
1372 frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
1373 }
1374 else
1375 {
1376 hostInputChannels = bp->hostInputChannels[1];
1377 frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
1378 }
1379
1380 /* configure conversion destination pointers */
1381 if( bp->userInputIsInterleaved )
1382 {
1383 destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1384 bp->bytesPerUserInputSample * bp->inputChannelCount *
1385 bp->framesInTempInputBuffer;
1386
1387 destSampleStrideSamples = bp->inputChannelCount;
1388 destChannelStrideBytes = bp->bytesPerUserInputSample;
1389 }
1390 else /* user input is not interleaved */
1391 {
1392 destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1393 bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
1394
1395 destSampleStrideSamples = 1;
1396 destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1397 }
1398
1399 for( i=0; i<bp->inputChannelCount; ++i )
1400 {
1401 bp->inputConverter( destBytePtr, destSampleStrideSamples,
1402 hostInputChannels[i].data,
1403 hostInputChannels[i].stride,
1404 frameCount, &bp->ditherGenerator );
1405
1406 destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
1407
1408 /* advance src ptr for next iteration */
1409 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1410 frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1411 }
1412
1413 if( bp->hostInputFrameCount[0] > 0 )
1414 bp->hostInputFrameCount[0] -= frameCount;
1415 else
1416 bp->hostInputFrameCount[1] -= frameCount;
1417
1418 bp->framesInTempInputBuffer += frameCount;
1419
1420 /* update framesAvailable and framesProcessed based on input consumed
1421 unless something is very wrong this will also correspond to the
1422 amount of output generated */
1423 framesAvailable -= frameCount;
1424 framesProcessed += frameCount;
1425 }
1426
1427 /* call streamCallback */
1428 if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
1429 bp->framesInTempOutputBuffer == 0 )
1430 {
1431 if( *streamCallbackResult == paContinue )
1432 {
1433 /* setup userInput */
1434 if( bp->userInputIsInterleaved )
1435 {
1436 userInput = bp->tempInputBuffer;
1437 }
1438 else /* user input is not interleaved */
1439 {
1440 for( i = 0; i < bp->inputChannelCount; ++i )
1441 {
1442 bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
1443 i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1444 }
1445
1446 userInput = bp->tempInputBufferPtrs;
1447 }
1448
1449 /* setup userOutput */
1450 if( bp->userOutputIsInterleaved )
1451 {
1452 userOutput = bp->tempOutputBuffer;
1453 }
1454 else /* user output is not interleaved */
1455 {
1456 for( i = 0; i < bp->outputChannelCount; ++i )
1457 {
1458 bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
1459 i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1460 }
1461
1462 userOutput = bp->tempOutputBufferPtrs;
1463 }
1464
1465 /* call streamCallback */
1466
1467 *streamCallbackResult = bp->streamCallback( userInput, userOutput,
1468 bp->framesPerUserBuffer, bp->timeInfo,
1469 bp->callbackStatusFlags, bp->userData );
1470
1471 bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
1472 bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
1473
1474 bp->framesInTempInputBuffer = 0;
1475
1476 if( *streamCallbackResult == paAbort )
1477 bp->framesInTempOutputBuffer = 0;
1478 else
1479 bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
1480 }
1481 else
1482 {
1483 /* paComplete or paAbort has already been called. */
1484
1485 bp->framesInTempInputBuffer = 0;
1486 }
1487 }
1488
1489 /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels)
1490 Means to process the user output provided by the callback. Has to be called after
1491 each callback. */
1492 CopyTempOutputBuffersToHostOutputBuffers( bp );
1493
1494 }
1495
1496 return framesProcessed;
1497 }
1498
1499
1500 unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
1501 {
1502 unsigned long framesToProcess, framesToGo;
1503 unsigned long framesProcessed = 0;
1504
1505 if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
1506 && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
1507 && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
1508 {
1509 assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
1510 (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
1511 }
1512
1513 assert( *streamCallbackResult == paContinue
1514 || *streamCallbackResult == paComplete
1515 || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
1516
1517 if( bp->useNonAdaptingProcess )
1518 {
1519 if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
1520 {
1521 /* full duplex non-adapting process, splice buffers if they are
1522 different lengths */
1523
1524 framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
1525
1526 do{
1527 unsigned long noInputInputFrameCount;
1528 unsigned long *hostInputFrameCount;
1529 PaUtilChannelDescriptor *hostInputChannels;
1530 unsigned long noOutputOutputFrameCount;
1531 unsigned long *hostOutputFrameCount;
1532 PaUtilChannelDescriptor *hostOutputChannels;
1533 unsigned long framesProcessedThisIteration;
1534
1535 if( !bp->hostInputChannels[0][0].data )
1536 {
1537 /* no input was supplied (see PaUtil_SetNoInput)
1538 NonAdaptingProcess knows how to deal with this
1539 */
1540 noInputInputFrameCount = framesToGo;
1541 hostInputFrameCount = &noInputInputFrameCount;
1542 hostInputChannels = 0;
1543 }
1544 else if( bp->hostInputFrameCount[0] != 0 )
1545 {
1546 hostInputFrameCount = &bp->hostInputFrameCount[0];
1547 hostInputChannels = bp->hostInputChannels[0];
1548 }
1549 else
1550 {
1551 hostInputFrameCount = &bp->hostInputFrameCount[1];
1552 hostInputChannels = bp->hostInputChannels[1];
1553 }
1554
1555 if( !bp->hostOutputChannels[0][0].data )
1556 {
1557 /* no output was supplied (see PaUtil_SetNoOutput)
1558 NonAdaptingProcess knows how to deal with this
1559 */
1560 noOutputOutputFrameCount = framesToGo;
1561 hostOutputFrameCount = &noOutputOutputFrameCount;
1562 hostOutputChannels = 0;
1563 }
1564 if( bp->hostOutputFrameCount[0] != 0 )
1565 {
1566 hostOutputFrameCount = &bp->hostOutputFrameCount[0];
1567 hostOutputChannels = bp->hostOutputChannels[0];
1568 }
1569 else
1570 {
1571 hostOutputFrameCount = &bp->hostOutputFrameCount[1];
1572 hostOutputChannels = bp->hostOutputChannels[1];
1573 }
1574
1575 framesToProcess = PA_MIN_( *hostInputFrameCount,
1576 *hostOutputFrameCount );
1577
1578 assert( framesToProcess != 0 );
1579
1580 framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
1581 hostInputChannels, hostOutputChannels,
1582 framesToProcess );
1583
1584 *hostInputFrameCount -= framesProcessedThisIteration;
1585 *hostOutputFrameCount -= framesProcessedThisIteration;
1586
1587 framesProcessed += framesProcessedThisIteration;
1588 framesToGo -= framesProcessedThisIteration;
1589
1590 }while( framesToGo > 0 );
1591 }
1592 else
1593 {
1594 /* half duplex non-adapting process, just process 1st and 2nd buffer */
1595 /* process first buffer */
1596
1597 framesToProcess = (bp->inputChannelCount != 0)
1598 ? bp->hostInputFrameCount[0]
1599 : bp->hostOutputFrameCount[0];
1600
1601 framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
1602 bp->hostInputChannels[0], bp->hostOutputChannels[0],
1603 framesToProcess );
1604
1605 /* process second buffer if provided */
1606
1607 framesToProcess = (bp->inputChannelCount != 0)
1608 ? bp->hostInputFrameCount[1]
1609 : bp->hostOutputFrameCount[1];
1610 if( framesToProcess > 0 )
1611 {
1612 framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
1613 bp->hostInputChannels[1], bp->hostOutputChannels[1],
1614 framesToProcess );
1615 }
1616 }
1617 }
1618 else /* block adaption necessary*/
1619 {
1620
1621 if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
1622 {
1623 /* full duplex */
1624
1625 if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed )
1626 {
1627 framesProcessed = AdaptingProcess( bp, streamCallbackResult,
1628 0 /* dont process partial user buffers */ );
1629 }
1630 else
1631 {
1632 framesProcessed = AdaptingProcess( bp, streamCallbackResult,
1633 1 /* process partial user buffers */ );
1634 }
1635 }
1636 else if( bp->inputChannelCount != 0 )
1637 {
1638 /* input only */
1639 framesToProcess = bp->hostInputFrameCount[0];
1640
1641 framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
1642 bp->hostInputChannels[0], framesToProcess );
1643
1644 framesToProcess = bp->hostInputFrameCount[1];
1645 if( framesToProcess > 0 )
1646 {
1647 framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
1648 bp->hostInputChannels[1], framesToProcess );
1649 }
1650 }
1651 else
1652 {
1653 /* output only */
1654 framesToProcess = bp->hostOutputFrameCount[0];
1655
1656 framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
1657 bp->hostOutputChannels[0], framesToProcess );
1658
1659 framesToProcess = bp->hostOutputFrameCount[1];
1660 if( framesToProcess > 0 )
1661 {
1662 framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
1663 bp->hostOutputChannels[1], framesToProcess );
1664 }
1665 }
1666 }
1667
1668 return framesProcessed;
1669 }
1670
1671
1672 int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
1673 {
1674 return (bp->framesInTempOutputBuffer) ? 0 : 1;
1675 }
1676
1677
1678 unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
1679 void **buffer, unsigned long frameCount )
1680 {
1681 PaUtilChannelDescriptor *hostInputChannels;
1682 unsigned int framesToCopy;
1683 unsigned char *destBytePtr;
1684 void **nonInterleavedDestPtrs;
1685 unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1686 unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
1687 unsigned int i;
1688
1689 hostInputChannels = bp->hostInputChannels[0];
1690 framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
1691
1692 if( bp->userInputIsInterleaved )
1693 {
1694 destBytePtr = (unsigned char*)*buffer;
1695
1696 destSampleStrideSamples = bp->inputChannelCount;
1697 destChannelStrideBytes = bp->bytesPerUserInputSample;
1698
1699 for( i=0; i<bp->inputChannelCount; ++i )
1700 {
1701 bp->inputConverter( destBytePtr, destSampleStrideSamples,
1702 hostInputChannels[i].data,
1703 hostInputChannels[i].stride,
1704 framesToCopy, &bp->ditherGenerator );
1705
1706 destBytePtr += destChannelStrideBytes; /* skip to next source channel */
1707
1708 /* advance dest ptr for next iteration */
1709 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1710 framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1711 }
1712
1713 /* advance callers dest pointer (buffer) */
1714 *buffer = ((unsigned char *)*buffer) +
1715 framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
1716 }
1717 else
1718 {
1719 /* user input is not interleaved */
1720
1721 nonInterleavedDestPtrs = (void**)*buffer;
1722
1723 destSampleStrideSamples = 1;
1724
1725 for( i=0; i<bp->inputChannelCount; ++i )
1726 {
1727 destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
1728
1729 bp->inputConverter( destBytePtr, destSampleStrideSamples,
1730 hostInputChannels[i].data,
1731 hostInputChannels[i].stride,
1732 framesToCopy, &bp->ditherGenerator );
1733
1734 /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
1735 destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
1736 nonInterleavedDestPtrs[i] = destBytePtr;
1737
1738 /* advance dest ptr for next iteration */
1739 hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1740 framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1741 }
1742 }
1743
1744 bp->hostInputFrameCount[0] -= framesToCopy;
1745
1746 return framesToCopy;
1747 }
1748
1749 unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
1750 const void ** buffer, unsigned long frameCount )
1751 {
1752 PaUtilChannelDescriptor *hostOutputChannels;
1753 unsigned int framesToCopy;
1754 unsigned char *srcBytePtr;
1755 void **nonInterleavedSrcPtrs;
1756 unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1757 unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1758 unsigned int i;
1759
1760 hostOutputChannels = bp->hostOutputChannels[0];
1761 framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
1762
1763 if( bp->userOutputIsInterleaved )
1764 {
1765 srcBytePtr = (unsigned char*)*buffer;
1766
1767 srcSampleStrideSamples = bp->outputChannelCount;
1768 srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1769
1770 for( i=0; i<bp->outputChannelCount; ++i )
1771 {
1772 bp->outputConverter( hostOutputChannels[i].data,
1773 hostOutputChannels[i].stride,
1774 srcBytePtr, srcSampleStrideSamples,
1775 framesToCopy, &bp->ditherGenerator );
1776
1777 srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
1778
1779 /* advance dest ptr for next iteration */
1780 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1781 framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1782 }
1783
1784 /* advance callers source pointer (buffer) */
1785 *buffer = ((unsigned char *)*buffer) +
1786 framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
1787
1788 }
1789 else
1790 {
1791 /* user output is not interleaved */
1792
1793 nonInterleavedSrcPtrs = (void**)*buffer;
1794
1795 srcSampleStrideSamples = 1;
1796
1797 for( i=0; i<bp->outputChannelCount; ++i )
1798 {
1799 srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
1800
1801 bp->outputConverter( hostOutputChannels[i].data,
1802 hostOutputChannels[i].stride,
1803 srcBytePtr, srcSampleStrideSamples,
1804 framesToCopy, &bp->ditherGenerator );
1805
1806
1807 /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
1808 srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
1809 nonInterleavedSrcPtrs[i] = srcBytePtr;
1810
1811 /* advance dest ptr for next iteration */
1812 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1813 framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1814 }
1815 }
1816
1817 bp->hostOutputFrameCount[0] += framesToCopy;
1818
1819 return framesToCopy;
1820 }
1821
1822
1823 unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
1824 {
1825 PaUtilChannelDescriptor *hostOutputChannels;
1826 unsigned int framesToZero;
1827 unsigned int i;
1828
1829 hostOutputChannels = bp->hostOutputChannels[0];
1830 framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
1831
1832 for( i=0; i<bp->outputChannelCount; ++i )
1833 {
1834 bp->outputZeroer( hostOutputChannels[i].data,
1835 hostOutputChannels[i].stride,
1836 framesToZero );
1837
1838
1839 /* advance dest ptr for next iteration */
1840 hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1841 framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1842 }
1843
1844 bp->hostOutputFrameCount[0] += framesToZero;
1845
1846 return framesToZero;
1847 }

  ViewVC Help
Powered by ViewVC 1.1.22