~ubuntu-branches/ubuntu/vivid/sflphone/vivid

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/third_party/portaudio/src/common/pa_process.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2013-06-30 11:40:56 UTC
  • mfrom: (4.1.18 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130630114056-0np50jkyqo6vnmii
Tags: 1.2.3-2
* changeset_r92d62cfc54732bbbcfff2b1d36c096b120b981a5.diff 
  - fixes automatic endian detection 
* Update Vcs: fixes vcs-field-not-canonical

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}