To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / common / pa_process.c @ 164:9fa11135915a

History | View | Annotate | Download (66.7 KB)

1
/*
2
 * $Id$
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

    
46

    
47
#include <assert.h>
48
#include <string.h> /* memset() */
49

    
50
#include "pa_process.h"
51
#include "pa_util.h"
52

    
53

    
54
#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_    1024
55

    
56
#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
57

    
58

    
59
/* greatest common divisor - PGCD in French */
60
static unsigned long GCD( unsigned long a, unsigned long b )
61
{
62
    return (b==0) ? a : GCD( b, a%b);
63
}
64

    
65
/* least common multiple - PPCM in French */
66
static unsigned long LCM( unsigned long a, unsigned long b )
67
{
68
    return (a*b) / GCD(a,b);
69
}
70

    
71
#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
72

    
73
static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
74
{
75
    unsigned long result = 0;
76
    unsigned long i;
77
    unsigned long lcm;
78

    
79
    assert( M > 0 );
80
    assert( N > 0 );
81

    
82
    lcm = LCM( M, N );
83
    for( i = M; i < lcm; i += M )
84
        result = PA_MAX_( result, i % N );
85

    
86
    return result;
87
}
88

    
89

    
90
PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
91
        int inputChannelCount, PaSampleFormat userInputSampleFormat,
92
        PaSampleFormat hostInputSampleFormat,
93
        int outputChannelCount, PaSampleFormat userOutputSampleFormat,
94
        PaSampleFormat hostOutputSampleFormat,
95
        double sampleRate,
96
        PaStreamFlags streamFlags,
97
        unsigned long framesPerUserBuffer,
98
        unsigned long framesPerHostBuffer,
99
        PaUtilHostBufferSizeMode hostBufferSizeMode,
100
        PaStreamCallback *streamCallback, void *userData )
101
{
102
    PaError result = paNoError;
103
    PaError bytesPerSample;
104
    unsigned long tempInputBufferSize, tempOutputBufferSize;
105
    PaStreamFlags tempInputStreamFlags;
106

    
107
    if( streamFlags & paNeverDropInput )
108
    {
109
        /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */
110
        if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) ||
111
                framesPerUserBuffer != paFramesPerBufferUnspecified )
112
            return paInvalidFlag;
113
    }
114

    
115
    /* initialize buffer ptrs to zero so they can be freed if necessary in error */
116
    bp->tempInputBuffer = 0;
117
    bp->tempInputBufferPtrs = 0;
118
    bp->tempOutputBuffer = 0;
119
    bp->tempOutputBufferPtrs = 0;
120

    
121
    bp->framesPerUserBuffer = framesPerUserBuffer;
122
    bp->framesPerHostBuffer = framesPerHostBuffer;
123

    
124
    bp->inputChannelCount = inputChannelCount;
125
    bp->outputChannelCount = outputChannelCount;
126

    
127
    bp->hostBufferSizeMode = hostBufferSizeMode;
128

    
129
    bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;
130
    bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;
131

    
132
    if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
133
    {
134
        bp->useNonAdaptingProcess = 1;
135
        bp->initialFramesInTempInputBuffer = 0;
136
        bp->initialFramesInTempOutputBuffer = 0;
137

    
138
        if( hostBufferSizeMode == paUtilFixedHostBufferSize
139
                || hostBufferSizeMode == paUtilBoundedHostBufferSize )
140
        {
141
            bp->framesPerTempBuffer = framesPerHostBuffer;
142
        }
143
        else /* unknown host buffer size */
144
        {
145
             bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
146
        }
147
    }
148
    else
149
    {
150
        bp->framesPerTempBuffer = framesPerUserBuffer;
151

    
152
        if( hostBufferSizeMode == paUtilFixedHostBufferSize
153
                && framesPerHostBuffer % framesPerUserBuffer == 0 )
154
        {
155
            bp->useNonAdaptingProcess = 1;
156
            bp->initialFramesInTempInputBuffer = 0;
157
            bp->initialFramesInTempOutputBuffer = 0;
158
        }
159
        else
160
        {
161
            bp->useNonAdaptingProcess = 0;
162

    
163
            if( inputChannelCount > 0 && outputChannelCount > 0 )
164
            {
165
                /* full duplex */
166
                if( hostBufferSizeMode == paUtilFixedHostBufferSize )
167
                {
168
                    unsigned long frameShift =
169
                        CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
170

    
171
                    if( framesPerUserBuffer > framesPerHostBuffer )
172
                    {
173
                        bp->initialFramesInTempInputBuffer = frameShift;
174
                        bp->initialFramesInTempOutputBuffer = 0;
175
                    }
176
                    else
177
                    {
178
                        bp->initialFramesInTempInputBuffer = 0;
179
                        bp->initialFramesInTempOutputBuffer = frameShift;
180
                    }
181
                }
182
                else /* variable host buffer size, add framesPerUserBuffer latency */
183
                {
184
                    bp->initialFramesInTempInputBuffer = 0;
185
                    bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;
186
                }
187
            }
188
            else
189
            {
190
                /* half duplex */
191
                bp->initialFramesInTempInputBuffer = 0;
192
                bp->initialFramesInTempOutputBuffer = 0;
193
            }
194
        }
195
    }
196

    
197

    
198
    bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
199
    bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
200

    
201
    
202
    if( inputChannelCount > 0 )
203
    {
204
        bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
205
        if( bytesPerSample > 0 )
206
        {
207
            bp->bytesPerHostInputSample = bytesPerSample;
208
        }
209
        else
210
        {
211
            result = bytesPerSample;
212
            goto error;
213
        }
214

    
215
        bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
216
        if( bytesPerSample > 0 )
217
        {
218
            bp->bytesPerUserInputSample = bytesPerSample;
219
        }
220
        else
221
        {
222
            result = bytesPerSample;
223
            goto error;
224
        }
225

    
226
        /* Under the assumption that no ADC in existence delivers better than 24bits resolution,
227
            we disable dithering when host input format is paInt32 and user format is paInt24, 
228
            since the host samples will just be padded with zeros anyway. */
229

    
230
        tempInputStreamFlags = streamFlags;
231
        if( !(tempInputStreamFlags & paDitherOff) /* dither is on */
232
                && (hostInputSampleFormat & paInt32) /* host input format is int32 */
233
                && (userInputSampleFormat & paInt24) /* user requested format is int24 */ ){
234

    
235
            tempInputStreamFlags = tempInputStreamFlags | paDitherOff;
236
        }
237

    
238
        bp->inputConverter =
239
            PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags );
240

    
241
        bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat );
242
            
243
        bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
244
                
245
        bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1;
246

    
247
        bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved));
248

    
249
        tempInputBufferSize =
250
            bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
251
         
252
        bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
253
        if( bp->tempInputBuffer == 0 )
254
        {
255
            result = paInsufficientMemory;
256
            goto error;
257
        }
258
        
259
        if( bp->framesInTempInputBuffer > 0 )
260
            memset( bp->tempInputBuffer, 0, tempInputBufferSize );
261

    
262
        if( userInputSampleFormat & paNonInterleaved )
263
        {
264
            bp->tempInputBufferPtrs =
265
                (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
266
            if( bp->tempInputBufferPtrs == 0 )
267
            {
268
                result = paInsufficientMemory;
269
                goto error;
270
            }
271
        }
272

    
273
        bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
274
                PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
275
        if( bp->hostInputChannels[0] == 0 )
276
        {
277
            result = paInsufficientMemory;
278
            goto error;
279
        }
280

    
281
        bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
282
    }
283

    
284
    if( outputChannelCount > 0 )
285
    {
286
        bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
287
        if( bytesPerSample > 0 )
288
        {
289
            bp->bytesPerHostOutputSample = bytesPerSample;
290
        }
291
        else
292
        {
293
            result = bytesPerSample;
294
            goto error;
295
        }
296

    
297
        bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
298
        if( bytesPerSample > 0 )
299
        {
300
            bp->bytesPerUserOutputSample = bytesPerSample;
301
        }
302
        else
303
        {
304
            result = bytesPerSample;
305
            goto error;
306
        }
307

    
308
        bp->outputConverter =
309
            PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
310

    
311
        bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
312

    
313
        bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
314

    
315
        bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1;
316

    
317
        bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved));
318

    
319
        tempOutputBufferSize =
320
                bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
321

    
322
        bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
323
        if( bp->tempOutputBuffer == 0 )
324
        {
325
            result = paInsufficientMemory;
326
            goto error;
327
        }
328

    
329
        if( bp->framesInTempOutputBuffer > 0 )
330
            memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
331
        
332
        if( userOutputSampleFormat & paNonInterleaved )
333
        {
334
            bp->tempOutputBufferPtrs =
335
                (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
336
            if( bp->tempOutputBufferPtrs == 0 )
337
            {
338
                result = paInsufficientMemory;
339
                goto error;
340
            }
341
        }
342

    
343
        bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
344
                PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
345
        if( bp->hostOutputChannels[0] == 0 )
346
        {                                                                     
347
            result = paInsufficientMemory;
348
            goto error;
349
        }
350

    
351
        bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
352
    }
353

    
354
    PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
355

    
356
    bp->samplePeriod = 1. / sampleRate;
357

    
358
    bp->streamCallback = streamCallback;
359
    bp->userData = userData;
360

    
361
    return result;
362

    
363
error:
364
    if( bp->tempInputBuffer )
365
        PaUtil_FreeMemory( bp->tempInputBuffer );
366

    
367
    if( bp->tempInputBufferPtrs )
368
        PaUtil_FreeMemory( bp->tempInputBufferPtrs );
369

    
370
    if( bp->hostInputChannels[0] )
371
        PaUtil_FreeMemory( bp->hostInputChannels[0] );
372

    
373
    if( bp->tempOutputBuffer )
374
        PaUtil_FreeMemory( bp->tempOutputBuffer );
375

    
376
    if( bp->tempOutputBufferPtrs )
377
        PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
378

    
379
    if( bp->hostOutputChannels[0] )
380
        PaUtil_FreeMemory( bp->hostOutputChannels[0] );
381

    
382
    return result;
383
}
384

    
385

    
386
void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
387
{
388
    if( bp->tempInputBuffer )
389
        PaUtil_FreeMemory( bp->tempInputBuffer );
390

    
391
    if( bp->tempInputBufferPtrs )
392
        PaUtil_FreeMemory( bp->tempInputBufferPtrs );
393

    
394
    if( bp->hostInputChannels[0] )
395
        PaUtil_FreeMemory( bp->hostInputChannels[0] );
396
        
397
    if( bp->tempOutputBuffer )
398
        PaUtil_FreeMemory( bp->tempOutputBuffer );
399

    
400
    if( bp->tempOutputBufferPtrs )
401
        PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
402

    
403
    if( bp->hostOutputChannels[0] )
404
        PaUtil_FreeMemory( bp->hostOutputChannels[0] );
405
}
406

    
407

    
408
void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
409
{
410
    unsigned long tempInputBufferSize, tempOutputBufferSize;
411

    
412
    bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
413
    bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
414

    
415
    if( bp->framesInTempInputBuffer > 0 )
416
    {
417
        tempInputBufferSize =
418
            bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
419
        memset( bp->tempInputBuffer, 0, tempInputBufferSize );
420
    }
421

    
422
    if( bp->framesInTempOutputBuffer > 0 )
423
    {      
424
        tempOutputBufferSize =
425
            bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
426
        memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
427
    }
428
}
429

    
430

    
431
unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bp )
432
{
433
    return bp->initialFramesInTempInputBuffer;
434
}
435

    
436

    
437
unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bp )
438
{
439
    return bp->initialFramesInTempOutputBuffer;
440
}
441

    
442

    
443
void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
444
        unsigned long frameCount )
445
{
446
    if( frameCount == 0 )
447
        bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
448
    else
449
        bp->hostInputFrameCount[0] = frameCount;
450
}
451
        
452

    
453
void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
454
{
455
    assert( bp->inputChannelCount > 0 );
456

    
457
    bp->hostInputChannels[0][0].data = 0;
458
}
459

    
460

    
461
void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
462
        unsigned int channel, void *data, unsigned int stride )
463
{
464
    assert( channel < bp->inputChannelCount );
465
    
466
    bp->hostInputChannels[0][channel].data = data;
467
    bp->hostInputChannels[0][channel].stride = stride;
468
}
469

    
470

    
471
void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
472
        unsigned int firstChannel, void *data, unsigned int channelCount )
473
{
474
    unsigned int i;
475
    unsigned int channel = firstChannel;
476
    unsigned char *p = (unsigned char*)data;
477

    
478
    if( channelCount == 0 )
479
        channelCount = bp->inputChannelCount;
480

    
481
    assert( firstChannel < bp->inputChannelCount );
482
    assert( firstChannel + channelCount <= bp->inputChannelCount );
483
    assert( bp->hostInputIsInterleaved );
484

    
485
    for( i=0; i< channelCount; ++i )
486
    {
487
        bp->hostInputChannels[0][channel+i].data = p;
488
        p += bp->bytesPerHostInputSample;
489
        bp->hostInputChannels[0][channel+i].stride = channelCount;
490
    }
491
}
492

    
493

    
494
void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
495
        unsigned int channel, void *data )
496
{
497
    assert( channel < bp->inputChannelCount );
498
    assert( !bp->hostInputIsInterleaved );
499
    
500
    bp->hostInputChannels[0][channel].data = data;
501
    bp->hostInputChannels[0][channel].stride = 1;
502
}
503

    
504

    
505
void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
506
        unsigned long frameCount )
507
{
508
    bp->hostInputFrameCount[1] = frameCount;
509
}
510

    
511

    
512
void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
513
        unsigned int channel, void *data, unsigned int stride )
514
{
515
    assert( channel < bp->inputChannelCount );
516

    
517
    bp->hostInputChannels[1][channel].data = data;
518
    bp->hostInputChannels[1][channel].stride = stride;
519
}
520

    
521

    
522
void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
523
        unsigned int firstChannel, void *data, unsigned int channelCount )
524
{
525
    unsigned int i;
526
    unsigned int channel = firstChannel;
527
    unsigned char *p = (unsigned char*)data;
528

    
529
    if( channelCount == 0 )
530
        channelCount = bp->inputChannelCount;
531

    
532
    assert( firstChannel < bp->inputChannelCount );
533
    assert( firstChannel + channelCount <= bp->inputChannelCount );
534
    assert( bp->hostInputIsInterleaved );
535
    
536
    for( i=0; i< channelCount; ++i )
537
    {
538
        bp->hostInputChannels[1][channel+i].data = p;
539
        p += bp->bytesPerHostInputSample;
540
        bp->hostInputChannels[1][channel+i].stride = channelCount;
541
    }
542
}
543

    
544
        
545
void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
546
        unsigned int channel, void *data )
547
{
548
    assert( channel < bp->inputChannelCount );
549
    assert( !bp->hostInputIsInterleaved );
550
    
551
    bp->hostInputChannels[1][channel].data = data;
552
    bp->hostInputChannels[1][channel].stride = 1;
553
}
554

    
555

    
556
void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
557
        unsigned long frameCount )
558
{
559
    if( frameCount == 0 )
560
        bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
561
    else
562
        bp->hostOutputFrameCount[0] = frameCount;
563
}
564

    
565

    
566
void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
567
{
568
    assert( bp->outputChannelCount > 0 );
569

    
570
    bp->hostOutputChannels[0][0].data = 0;
571

    
572
    /* note that only NonAdaptingProcess is able to deal with no output at this stage. not implemented for AdaptingProcess */
573
}
574

    
575

    
576
void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
577
        unsigned int channel, void *data, unsigned int stride )
578
{
579
    assert( channel < bp->outputChannelCount );
580
    assert( data != NULL );
581

    
582
    bp->hostOutputChannels[0][channel].data = data;
583
    bp->hostOutputChannels[0][channel].stride = stride;
584
}
585

    
586

    
587
void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
588
        unsigned int firstChannel, void *data, unsigned int channelCount )
589
{
590
    unsigned int i;
591
    unsigned int channel = firstChannel;
592
    unsigned char *p = (unsigned char*)data;
593

    
594
    if( channelCount == 0 )
595
        channelCount = bp->outputChannelCount;
596

    
597
    assert( firstChannel < bp->outputChannelCount );
598
    assert( firstChannel + channelCount <= bp->outputChannelCount );
599
    assert( bp->hostOutputIsInterleaved );
600
    
601
    for( i=0; i< channelCount; ++i )
602
    {
603
        PaUtil_SetOutputChannel( bp, channel + i, p, channelCount );
604
        p += bp->bytesPerHostOutputSample;
605
    }
606
}
607

    
608

    
609
void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
610
        unsigned int channel, void *data )
611
{
612
    assert( channel < bp->outputChannelCount );
613
    assert( !bp->hostOutputIsInterleaved );
614

    
615
    PaUtil_SetOutputChannel( bp, channel, data, 1 );
616
}
617

    
618

    
619
void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
620
        unsigned long frameCount )
621
{
622
    bp->hostOutputFrameCount[1] = frameCount;
623
}
624

    
625

    
626
void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
627
        unsigned int channel, void *data, unsigned int stride )
628
{
629
    assert( channel < bp->outputChannelCount );
630
    assert( data != NULL );
631

    
632
    bp->hostOutputChannels[1][channel].data = data;
633
    bp->hostOutputChannels[1][channel].stride = stride;
634
}
635

    
636

    
637
void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
638
        unsigned int firstChannel, void *data, unsigned int channelCount )
639
{
640
    unsigned int i;
641
    unsigned int channel = firstChannel;
642
    unsigned char *p = (unsigned char*)data;
643

    
644
    if( channelCount == 0 )
645
        channelCount = bp->outputChannelCount;
646

    
647
    assert( firstChannel < bp->outputChannelCount );
648
    assert( firstChannel + channelCount <= bp->outputChannelCount );
649
    assert( bp->hostOutputIsInterleaved );
650
    
651
    for( i=0; i< channelCount; ++i )
652
    {
653
        PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount );
654
        p += bp->bytesPerHostOutputSample;
655
    }
656
}
657

    
658
        
659
void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
660
        unsigned int channel, void *data )
661
{
662
    assert( channel < bp->outputChannelCount );
663
    assert( !bp->hostOutputIsInterleaved );
664
    
665
    PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
666
}
667

    
668

    
669
void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
670
        PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
671
{
672
    bp->timeInfo = timeInfo;
673

    
674
    /* the first streamCallback will be called to process samples which are
675
        currently in the input buffer before the ones starting at the timeInfo time */
676
        
677
    bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
678
    
679
    /* We just pass through timeInfo->currentTime provided by the caller. This is
680
        not strictly conformant to the word of the spec, since the buffer processor 
681
        might call the callback multiple times, and we never refresh currentTime. */
682

    
683
    /* the first streamCallback will be called to generate samples which will be
684
        outputted after the frames currently in the output buffer have been
685
        outputted. */
686
    bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
687

    
688
    bp->callbackStatusFlags = callbackStatusFlags;
689

    
690
    bp->hostInputFrameCount[1] = 0;
691
    bp->hostOutputFrameCount[1] = 0;
692
}
693

    
694

    
695
/*
696
    NonAdaptingProcess() is a simple buffer copying adaptor that can handle
697
    both full and half duplex copies. It processes framesToProcess frames,
698
    broken into blocks bp->framesPerTempBuffer long.
699
    This routine can be used when the streamCallback doesn't care what length
700
    the buffers are, or when framesToProcess is an integer multiple of
701
    bp->framesPerTempBuffer, in which case streamCallback will always be called
702
    with bp->framesPerTempBuffer samples.
703
*/
704
static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
705
        int *streamCallbackResult,
706
        PaUtilChannelDescriptor *hostInputChannels,
707
        PaUtilChannelDescriptor *hostOutputChannels,
708
        unsigned long framesToProcess )
709
{
710
    void *userInput, *userOutput;
711
    unsigned char *srcBytePtr, *destBytePtr;
712
    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
713
    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
714
    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
715
    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
716
    unsigned int i;
717
    unsigned long frameCount;
718
    unsigned long framesToGo = framesToProcess;
719
    unsigned long framesProcessed = 0;
720
    int skipOutputConvert = 0;
721
    int skipInputConvert = 0;
722

    
723

    
724
    if( *streamCallbackResult == paContinue )
725
    {
726
        do
727
        {
728
            frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
729

    
730
            /* configure user input buffer and convert input data (host -> user) */
731
            if( bp->inputChannelCount == 0 )
732
            {
733
                /* no input */
734
                userInput = 0;
735
            }
736
            else /* there are input channels */
737
            {
738
                
739
                destBytePtr = (unsigned char *)bp->tempInputBuffer;
740

    
741
                if( bp->userInputIsInterleaved )
742
                {
743
                    destSampleStrideSamples = bp->inputChannelCount;
744
                    destChannelStrideBytes = bp->bytesPerUserInputSample;
745

    
746
                    /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved,
747
                     * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */
748
                    if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved
749
                        && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride )
750
                    {
751
                        userInput = hostInputChannels[0].data;
752
                        destBytePtr = (unsigned char *)hostInputChannels[0].data;
753
                        skipInputConvert = 1;
754
                    }
755
                    else
756
                    {
757
                        userInput = bp->tempInputBuffer;
758
                    }
759
                }
760
                else /* user input is not interleaved */
761
                {
762
                    destSampleStrideSamples = 1;
763
                    destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
764

    
765
                    /* setup non-interleaved ptrs */
766
                    if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data )
767
                    {
768
                        for( i=0; i<bp->inputChannelCount; ++i )
769
                        {
770
                            bp->tempInputBufferPtrs[i] = hostInputChannels[i].data;
771
                        }
772
                        skipInputConvert = 1;
773
                    }
774
                    else
775
                    {
776
                        for( i=0; i<bp->inputChannelCount; ++i )
777
                        {
778
                            bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
779
                                i * bp->bytesPerUserInputSample * frameCount;
780
                        }
781
                    }
782
                
783
                    userInput = bp->tempInputBufferPtrs;
784
                }
785

    
786
                if( !bp->hostInputChannels[0][0].data )
787
                {
788
                    /* no input was supplied (see PaUtil_SetNoInput), so
789
                        zero the input buffer */
790

    
791
                    for( i=0; i<bp->inputChannelCount; ++i )
792
                    {
793
                        bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
794
                        destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
795
                    }
796
                }
797
                else
798
                    {
799
                    if( skipInputConvert )
800
                    {
801
                        for( i=0; i<bp->inputChannelCount; ++i )
802
                        {
803
                            /* advance src ptr for next iteration */
804
                            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
805
                                    frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
806
                        }
807
                    }
808
                    else
809
                    {
810
                        for( i=0; i<bp->inputChannelCount; ++i )
811
                        {
812
                            bp->inputConverter( destBytePtr, destSampleStrideSamples,
813
                                                    hostInputChannels[i].data,
814
                                                    hostInputChannels[i].stride,
815
                                                    frameCount, &bp->ditherGenerator );
816

    
817
                            destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
818

    
819
                            /* advance src ptr for next iteration */
820
                            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
821
                                    frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
822
                        }
823
                    }
824
                }
825
            }
826

    
827
            /* configure user output buffer */
828
            if( bp->outputChannelCount == 0 )
829
            {
830
                /* no output */
831
                userOutput = 0;
832
            }
833
            else /* there are output channels */
834
            {
835
                if( bp->userOutputIsInterleaved )
836
                {
837
                    /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved,
838
                     * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */
839
                    if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved
840
                          && bp->outputChannelCount == hostOutputChannels[0].stride )
841
                    {
842
                        userOutput = hostOutputChannels[0].data;
843
                        skipOutputConvert = 1;
844
                    }
845
                    else
846
                    {
847
                        userOutput = bp->tempOutputBuffer;
848
                    }
849
                }
850
                else /* user output is not interleaved */
851
                {
852
                    if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved )
853
                    {
854
                        for( i=0; i<bp->outputChannelCount; ++i )
855
                        {
856
                            bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data;
857
                        }
858
                        skipOutputConvert = 1;
859
                    }
860
                    else
861
                    {
862
                        for( i=0; i<bp->outputChannelCount; ++i )
863
                        {
864
                            bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
865
                                i * bp->bytesPerUserOutputSample * frameCount;
866
                        }
867
                    }
868

    
869
                    userOutput = bp->tempOutputBufferPtrs;
870
                }
871
            }
872
        
873
            *streamCallbackResult = bp->streamCallback( userInput, userOutput,
874
                    frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
875

    
876
            if( *streamCallbackResult == paAbort )
877
            {
878
                /* callback returned paAbort, don't advance framesProcessed
879
                        and framesToGo, they will be handled below */
880
            }
881
            else
882
            {
883
                bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
884
                bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
885

    
886
                /* convert output data (user -> host) */
887
                
888
                if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
889
                {
890
                    if( skipOutputConvert )
891
                                        {
892
                                                for( i=0; i<bp->outputChannelCount; ++i )
893
                            {
894
                                /* advance dest ptr for next iteration */
895
                                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
896
                                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
897
                            }
898
                                        }
899
                                        else
900
                                        {
901

    
902
                            srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
903

    
904
                            if( bp->userOutputIsInterleaved )
905
                            {
906
                                srcSampleStrideSamples = bp->outputChannelCount;
907
                                srcChannelStrideBytes = bp->bytesPerUserOutputSample;
908
                            }
909
                            else /* user output is not interleaved */
910
                            {
911
                                srcSampleStrideSamples = 1;
912
                                srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
913
                            }
914

    
915
                            for( i=0; i<bp->outputChannelCount; ++i )
916
                            {
917
                                bp->outputConverter(    hostOutputChannels[i].data,
918
                                                        hostOutputChannels[i].stride,
919
                                                        srcBytePtr, srcSampleStrideSamples,
920
                                                        frameCount, &bp->ditherGenerator );
921

    
922
                                srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
923

    
924
                                /* advance dest ptr for next iteration */
925
                                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
926
                                                frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
927
                            }
928
                                        }
929
                }
930
             
931
                framesProcessed += frameCount;
932

    
933
                framesToGo -= frameCount;
934
            }
935
        }
936
        while( framesToGo > 0  && *streamCallbackResult == paContinue );
937
    }
938

    
939
    if( framesToGo > 0 )
940
    {
941
        /* zero any remaining frames output. There will only be remaining frames
942
            if the callback has returned paComplete or paAbort */
943

    
944
        frameCount = framesToGo;
945

    
946
        if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
947
        {
948
            for( i=0; i<bp->outputChannelCount; ++i )
949
            {
950
                bp->outputZeroer(   hostOutputChannels[i].data,
951
                                    hostOutputChannels[i].stride,
952
                                    frameCount );
953

    
954
                /* advance dest ptr for next iteration */
955
                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
956
                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
957
            }
958
        }
959

    
960
        framesProcessed += frameCount;
961
    }
962

    
963
    return framesProcessed;
964
}
965

    
966

    
967
/*
968
    AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
969
    converts data from the input buffers into the temporary input buffer,
970
    when the temporary input buffer is full, it calls the streamCallback.
971
*/
972
static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
973
        int *streamCallbackResult,
974
        PaUtilChannelDescriptor *hostInputChannels,
975
        unsigned long framesToProcess )
976
{
977
    void *userInput, *userOutput;
978
    unsigned char *destBytePtr;
979
    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
980
    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
981
    unsigned int i;
982
    unsigned long frameCount;
983
    unsigned long framesToGo = framesToProcess;
984
    unsigned long framesProcessed = 0;
985
    
986
    userOutput = 0;
987

    
988
    do
989
    {
990
        frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
991
                ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
992
                : framesToGo;
993

    
994
        /* convert frameCount samples into temp buffer */
995

    
996
        if( bp->userInputIsInterleaved )
997
        {
998
            destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
999
                    bp->bytesPerUserInputSample * bp->inputChannelCount *
1000
                    bp->framesInTempInputBuffer;
1001
                      
1002
            destSampleStrideSamples = bp->inputChannelCount;
1003
            destChannelStrideBytes = bp->bytesPerUserInputSample;
1004

    
1005
            userInput = bp->tempInputBuffer;
1006
        }
1007
        else /* user input is not interleaved */
1008
        {
1009
            destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1010
                    bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
1011

    
1012
            destSampleStrideSamples = 1;
1013
            destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1014

    
1015
            /* setup non-interleaved ptrs */
1016
            for( i=0; i<bp->inputChannelCount; ++i )
1017
            {
1018
                bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
1019
                    i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
1020
            }
1021
                    
1022
            userInput = bp->tempInputBufferPtrs;
1023
        }
1024

    
1025
        for( i=0; i<bp->inputChannelCount; ++i )
1026
        {
1027
            bp->inputConverter( destBytePtr, destSampleStrideSamples,
1028
                                    hostInputChannels[i].data,
1029
                                    hostInputChannels[i].stride,
1030
                                    frameCount, &bp->ditherGenerator );
1031

    
1032
            destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
1033

    
1034
            /* advance src ptr for next iteration */
1035
            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1036
                    frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1037
        }
1038

    
1039
        bp->framesInTempInputBuffer += frameCount;
1040

    
1041
        if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
1042
        {
1043
            /**
1044
            @todo (non-critical optimisation)
1045
            The conditional below implements the continue/complete/abort mechanism
1046
            simply by continuing on iterating through the input buffer, but not
1047
            passing the data to the callback. With care, the outer loop could be
1048
            terminated earlier, thus some unneeded conversion cycles would be
1049
            saved.
1050
            */
1051
            if( *streamCallbackResult == paContinue )
1052
            {
1053
                bp->timeInfo->outputBufferDacTime = 0;
1054

    
1055
                *streamCallbackResult = bp->streamCallback( userInput, userOutput,
1056
                        bp->framesPerUserBuffer, bp->timeInfo,
1057
                        bp->callbackStatusFlags, bp->userData );
1058

    
1059
                bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
1060
            }
1061
            
1062
            bp->framesInTempInputBuffer = 0;
1063
        }
1064

    
1065
        framesProcessed += frameCount;
1066

    
1067
        framesToGo -= frameCount;
1068
    }while( framesToGo > 0 );
1069

    
1070
    return framesProcessed;
1071
}
1072

    
1073

    
1074
/*
1075
    AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
1076
    It converts data from the temporary output buffer, to the output buffers,
1077
    when the temporary output buffer is empty, it calls the streamCallback.
1078
*/
1079
static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
1080
        int *streamCallbackResult,
1081
        PaUtilChannelDescriptor *hostOutputChannels,
1082
        unsigned long framesToProcess )
1083
{
1084
    void *userInput, *userOutput;
1085
    unsigned char *srcBytePtr;
1086
    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1087
    unsigned int srcChannelStrideBytes;  /* stride from one channel to the next, in bytes */
1088
    unsigned int i;
1089
    unsigned long frameCount;
1090
    unsigned long framesToGo = framesToProcess;
1091
    unsigned long framesProcessed = 0;
1092

    
1093
    do
1094
    {
1095
        if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
1096
        {
1097
            userInput = 0;
1098

    
1099
            /* setup userOutput */
1100
            if( bp->userOutputIsInterleaved )
1101
            {
1102
                userOutput = bp->tempOutputBuffer;
1103
            }
1104
            else /* user output is not interleaved */
1105
            {
1106
                for( i = 0; i < bp->outputChannelCount; ++i )
1107
                {
1108
                    bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
1109
                            i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1110
                }
1111

    
1112
                userOutput = bp->tempOutputBufferPtrs;
1113
            }
1114

    
1115
            bp->timeInfo->inputBufferAdcTime = 0;
1116
            
1117
            *streamCallbackResult = bp->streamCallback( userInput, userOutput,
1118
                    bp->framesPerUserBuffer, bp->timeInfo,
1119
                    bp->callbackStatusFlags, bp->userData );
1120

    
1121
            if( *streamCallbackResult == paAbort )
1122
            {
1123
                /* if the callback returned paAbort, we disregard its output */
1124
            }
1125
            else
1126
            {
1127
                bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
1128

    
1129
                bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
1130
            }
1131
        }
1132

    
1133
        if( bp->framesInTempOutputBuffer > 0 )
1134
        {
1135
            /* convert frameCount frames from user buffer to host buffer */
1136

    
1137
            frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
1138

    
1139
            if( bp->userOutputIsInterleaved )
1140
            {
1141
                srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1142
                        bp->bytesPerUserOutputSample * bp->outputChannelCount *
1143
                        (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1144

    
1145
                srcSampleStrideSamples = bp->outputChannelCount;
1146
                srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1147
            }
1148
            else /* user output is not interleaved */
1149
            {
1150
                srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1151
                        bp->bytesPerUserOutputSample *
1152
                        (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1153
                            
1154
                srcSampleStrideSamples = 1;
1155
                srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1156
            }
1157

    
1158
            for( i=0; i<bp->outputChannelCount; ++i )
1159
            {
1160
                bp->outputConverter(    hostOutputChannels[i].data,
1161
                                        hostOutputChannels[i].stride,
1162
                                        srcBytePtr, srcSampleStrideSamples,
1163
                                        frameCount, &bp->ditherGenerator );
1164

    
1165
                srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
1166

    
1167
                /* advance dest ptr for next iteration */
1168
                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1169
                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1170
            }
1171

    
1172
            bp->framesInTempOutputBuffer -= frameCount;
1173
        }
1174
        else
1175
        {
1176
            /* no more user data is available because the callback has returned
1177
                paComplete or paAbort. Fill the remainder of the host buffer
1178
                with zeros.
1179
            */
1180

    
1181
            frameCount = framesToGo;
1182

    
1183
            for( i=0; i<bp->outputChannelCount; ++i )
1184
            {
1185
                bp->outputZeroer(   hostOutputChannels[i].data,
1186
                                    hostOutputChannels[i].stride,
1187
                                    frameCount );
1188

    
1189
                /* advance dest ptr for next iteration */
1190
                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1191
                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1192
            }
1193
        }
1194
        
1195
        framesProcessed += frameCount;
1196
        
1197
        framesToGo -= frameCount;
1198

    
1199
    }while( framesToGo > 0 );
1200

    
1201
    return framesProcessed;
1202
}
1203

    
1204
/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
1205
        tempOutputBuffer to hostOutputChannels. This includes data conversion
1206
        and interleaving. 
1207
*/
1208
static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
1209
{
1210
    unsigned long maxFramesToCopy;
1211
    PaUtilChannelDescriptor *hostOutputChannels;
1212
    unsigned int frameCount;
1213
    unsigned char *srcBytePtr;
1214
    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1215
    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1216
    unsigned int i;
1217

    
1218
     /* copy frames from user to host output buffers */
1219
     while( bp->framesInTempOutputBuffer > 0 &&
1220
             ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
1221
     {
1222
         maxFramesToCopy = bp->framesInTempOutputBuffer;
1223

    
1224
         /* select the output buffer set (1st or 2nd) */
1225
         if( bp->hostOutputFrameCount[0] > 0 )
1226
         {
1227
             hostOutputChannels = bp->hostOutputChannels[0];
1228
             frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
1229
         }
1230
         else
1231
         {
1232
             hostOutputChannels = bp->hostOutputChannels[1];
1233
             frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
1234
         }
1235

    
1236
         if( bp->userOutputIsInterleaved )
1237
         {
1238
             srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1239
                     bp->bytesPerUserOutputSample * bp->outputChannelCount *
1240
                     (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1241
                         
1242
             srcSampleStrideSamples = bp->outputChannelCount;
1243
             srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1244
         }
1245
         else /* user output is not interleaved */
1246
         {
1247
             srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
1248
                     bp->bytesPerUserOutputSample *
1249
                     (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
1250

    
1251
             srcSampleStrideSamples = 1;
1252
             srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1253
         }
1254

    
1255
         for( i=0; i<bp->outputChannelCount; ++i )
1256
         {
1257
             assert( hostOutputChannels[i].data != NULL );
1258
             bp->outputConverter(    hostOutputChannels[i].data,
1259
                                     hostOutputChannels[i].stride,
1260
                                     srcBytePtr, srcSampleStrideSamples,
1261
                                     frameCount, &bp->ditherGenerator );
1262

    
1263
             srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
1264

    
1265
             /* advance dest ptr for next iteration */
1266
             hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1267
                     frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1268
         }
1269

    
1270
         if( bp->hostOutputFrameCount[0] > 0 )
1271
             bp->hostOutputFrameCount[0] -= frameCount;
1272
         else
1273
             bp->hostOutputFrameCount[1] -= frameCount;
1274

    
1275
         bp->framesInTempOutputBuffer -= frameCount;
1276
     }
1277
}
1278

    
1279
/*
1280
    AdaptingProcess is a full duplex adapting buffer processor. It converts
1281
    data from the temporary output buffer into the host output buffers, then
1282
    from the host input buffers into the temporary input buffers. Calling the
1283
    streamCallback when necessary.
1284
    When processPartialUserBuffers is 0, all available input data will be
1285
    consumed and all available output space will be filled. When
1286
    processPartialUserBuffers is non-zero, as many full user buffers
1287
    as possible will be processed, but partial buffers will not be consumed.
1288
*/
1289
static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
1290
        int *streamCallbackResult, int processPartialUserBuffers )
1291
{
1292
    void *userInput, *userOutput;
1293
    unsigned long framesProcessed = 0;
1294
    unsigned long framesAvailable;
1295
    unsigned long endProcessingMinFrameCount;
1296
    unsigned long maxFramesToCopy;
1297
    PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
1298
    unsigned int frameCount;
1299
    unsigned char *destBytePtr;
1300
    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1301
    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
1302
    unsigned int i, j;
1303
 
1304

    
1305
    framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
1306

    
1307
    if( processPartialUserBuffers )
1308
        endProcessingMinFrameCount = 0;
1309
    else
1310
        endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
1311

    
1312
    /* Fill host output with remaining frames in user output (tempOutputBuffer) */
1313
    CopyTempOutputBuffersToHostOutputBuffers( bp );                          
1314

    
1315
    while( framesAvailable > endProcessingMinFrameCount ) 
1316
    {
1317

    
1318
        if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
1319
        {
1320
            /* the callback will not be called any more, so zero what remains
1321
                of the host output buffers */
1322

    
1323
            for( i=0; i<2; ++i )
1324
            {
1325
                frameCount = bp->hostOutputFrameCount[i];
1326
                if( frameCount > 0 )
1327
                {
1328
                    hostOutputChannels = bp->hostOutputChannels[i];
1329
                    
1330
                    for( j=0; j<bp->outputChannelCount; ++j )
1331
                    {
1332
                        bp->outputZeroer(   hostOutputChannels[j].data,
1333
                                            hostOutputChannels[j].stride,
1334
                                            frameCount );
1335

    
1336
                        /* advance dest ptr for next iteration  */
1337
                        hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
1338
                                frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
1339
                    }
1340
                    bp->hostOutputFrameCount[i] = 0;
1341
                }
1342
            }
1343
        }          
1344

    
1345

    
1346
        /* copy frames from host to user input buffers */
1347
        while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
1348
                ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
1349
        {
1350
            maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
1351

    
1352
            /* select the input buffer set (1st or 2nd) */
1353
            if( bp->hostInputFrameCount[0] > 0 )
1354
            {
1355
                hostInputChannels = bp->hostInputChannels[0];
1356
                frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
1357
            }
1358
            else
1359
            {
1360
                hostInputChannels = bp->hostInputChannels[1];
1361
                frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
1362
            }
1363

    
1364
            /* configure conversion destination pointers */
1365
            if( bp->userInputIsInterleaved )
1366
            {
1367
                destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1368
                        bp->bytesPerUserInputSample * bp->inputChannelCount *
1369
                        bp->framesInTempInputBuffer;
1370

    
1371
                destSampleStrideSamples = bp->inputChannelCount;
1372
                destChannelStrideBytes = bp->bytesPerUserInputSample;
1373
            }
1374
            else /* user input is not interleaved */
1375
            {
1376
                destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
1377
                        bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
1378

    
1379
                destSampleStrideSamples = 1;
1380
                destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1381
            }
1382

    
1383
            for( i=0; i<bp->inputChannelCount; ++i )
1384
            {
1385
                bp->inputConverter( destBytePtr, destSampleStrideSamples,
1386
                                        hostInputChannels[i].data,
1387
                                        hostInputChannels[i].stride,
1388
                                        frameCount, &bp->ditherGenerator );
1389

    
1390
                destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
1391

    
1392
                /* advance src ptr for next iteration */
1393
                hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1394
                        frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1395
            }
1396

    
1397
            if( bp->hostInputFrameCount[0] > 0 )
1398
                bp->hostInputFrameCount[0] -= frameCount;
1399
            else
1400
                bp->hostInputFrameCount[1] -= frameCount;
1401
                
1402
            bp->framesInTempInputBuffer += frameCount;
1403

    
1404
            /* update framesAvailable and framesProcessed based on input consumed
1405
                unless something is very wrong this will also correspond to the
1406
                amount of output generated */
1407
            framesAvailable -= frameCount;
1408
            framesProcessed += frameCount;
1409
        }
1410

    
1411
        /* call streamCallback */
1412
        if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
1413
            bp->framesInTempOutputBuffer == 0 )
1414
        {
1415
            if( *streamCallbackResult == paContinue )
1416
            {
1417
                /* setup userInput */
1418
                if( bp->userInputIsInterleaved )
1419
                {
1420
                    userInput = bp->tempInputBuffer;
1421
                }
1422
                else /* user input is not interleaved */
1423
                {
1424
                    for( i = 0; i < bp->inputChannelCount; ++i )
1425
                    {
1426
                        bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
1427
                                i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
1428
                    }
1429

    
1430
                    userInput = bp->tempInputBufferPtrs;
1431
                }
1432

    
1433
                /* setup userOutput */
1434
                if( bp->userOutputIsInterleaved )
1435
                {
1436
                    userOutput = bp->tempOutputBuffer;
1437
                }
1438
                else /* user output is not interleaved */
1439
                {
1440
                    for( i = 0; i < bp->outputChannelCount; ++i )
1441
                    {
1442
                        bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
1443
                                i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
1444
                    }
1445

    
1446
                    userOutput = bp->tempOutputBufferPtrs;
1447
                }
1448

    
1449
                /* call streamCallback */
1450

    
1451
                *streamCallbackResult = bp->streamCallback( userInput, userOutput,
1452
                        bp->framesPerUserBuffer, bp->timeInfo,
1453
                        bp->callbackStatusFlags, bp->userData );
1454

    
1455
                bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
1456
                bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
1457

    
1458
                bp->framesInTempInputBuffer = 0;
1459

    
1460
                if( *streamCallbackResult == paAbort )
1461
                    bp->framesInTempOutputBuffer = 0;
1462
                else
1463
                    bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
1464
            }
1465
            else
1466
            {
1467
                /* paComplete or paAbort has already been called. */
1468

    
1469
                bp->framesInTempInputBuffer = 0;
1470
            }
1471
        }
1472

    
1473
        /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) 
1474
           Means to process the user output provided by the callback. Has to be called after
1475
            each callback. */
1476
        CopyTempOutputBuffersToHostOutputBuffers( bp );                          
1477

    
1478
    }
1479
    
1480
    return framesProcessed;
1481
}
1482

    
1483

    
1484
unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
1485
{
1486
    unsigned long framesToProcess, framesToGo;
1487
    unsigned long framesProcessed = 0;
1488
    
1489
    if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
1490
            && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
1491
            && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
1492
    {
1493
        assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
1494
                (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
1495
    }
1496

    
1497
    assert( *streamCallbackResult == paContinue
1498
            || *streamCallbackResult == paComplete
1499
            || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
1500

    
1501
    if( bp->useNonAdaptingProcess )
1502
    {
1503
        if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
1504
        {
1505
            /* full duplex non-adapting process, splice buffers if they are
1506
                different lengths */
1507

    
1508
            framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
1509

    
1510
            do{
1511
                unsigned long noInputInputFrameCount;
1512
                unsigned long *hostInputFrameCount;
1513
                PaUtilChannelDescriptor *hostInputChannels;
1514
                unsigned long noOutputOutputFrameCount;
1515
                unsigned long *hostOutputFrameCount;
1516
                PaUtilChannelDescriptor *hostOutputChannels;
1517
                unsigned long framesProcessedThisIteration;
1518

    
1519
                if( !bp->hostInputChannels[0][0].data )
1520
                {
1521
                    /* no input was supplied (see PaUtil_SetNoInput)
1522
                        NonAdaptingProcess knows how to deal with this
1523
                    */
1524
                    noInputInputFrameCount = framesToGo;
1525
                    hostInputFrameCount = &noInputInputFrameCount;
1526
                    hostInputChannels = 0;
1527
                }
1528
                else if( bp->hostInputFrameCount[0] != 0 )
1529
                {
1530
                    hostInputFrameCount = &bp->hostInputFrameCount[0];
1531
                    hostInputChannels = bp->hostInputChannels[0];
1532
                }
1533
                else
1534
                {
1535
                    hostInputFrameCount = &bp->hostInputFrameCount[1];
1536
                    hostInputChannels = bp->hostInputChannels[1];
1537
                }
1538

    
1539
                if( !bp->hostOutputChannels[0][0].data )
1540
                {
1541
                    /* no output was supplied (see PaUtil_SetNoOutput)
1542
                        NonAdaptingProcess knows how to deal with this
1543
                    */
1544
                    noOutputOutputFrameCount = framesToGo;
1545
                    hostOutputFrameCount = &noOutputOutputFrameCount;
1546
                    hostOutputChannels = 0;
1547
                }
1548
                if( bp->hostOutputFrameCount[0] != 0 )
1549
                {
1550
                    hostOutputFrameCount = &bp->hostOutputFrameCount[0];
1551
                    hostOutputChannels = bp->hostOutputChannels[0];
1552
                }
1553
                else
1554
                {
1555
                    hostOutputFrameCount = &bp->hostOutputFrameCount[1];
1556
                    hostOutputChannels = bp->hostOutputChannels[1];
1557
                }
1558

    
1559
                framesToProcess = PA_MIN_( *hostInputFrameCount,
1560
                                       *hostOutputFrameCount );
1561

    
1562
                assert( framesToProcess != 0 );
1563
                
1564
                framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
1565
                        hostInputChannels, hostOutputChannels,
1566
                        framesToProcess );                                       
1567

    
1568
                *hostInputFrameCount -= framesProcessedThisIteration;
1569
                *hostOutputFrameCount -= framesProcessedThisIteration;
1570

    
1571
                framesProcessed += framesProcessedThisIteration;
1572
                framesToGo -= framesProcessedThisIteration;
1573
                
1574
            }while( framesToGo > 0 );
1575
        }
1576
        else
1577
        {
1578
            /* half duplex non-adapting process, just process 1st and 2nd buffer */
1579
            /* process first buffer */
1580

    
1581
            framesToProcess = (bp->inputChannelCount != 0)
1582
                            ? bp->hostInputFrameCount[0]
1583
                            : bp->hostOutputFrameCount[0];
1584

    
1585
            framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
1586
                        bp->hostInputChannels[0], bp->hostOutputChannels[0],
1587
                        framesToProcess );
1588

    
1589
            /* process second buffer if provided */
1590
    
1591
            framesToProcess = (bp->inputChannelCount != 0)
1592
                            ? bp->hostInputFrameCount[1]
1593
                            : bp->hostOutputFrameCount[1];
1594
            if( framesToProcess > 0 )
1595
            {
1596
                framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
1597
                    bp->hostInputChannels[1], bp->hostOutputChannels[1],
1598
                    framesToProcess );
1599
            }
1600
        }
1601
    }
1602
    else /* block adaption necessary*/
1603
    {
1604

    
1605
        if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
1606
        {
1607
            /* full duplex */
1608
            
1609
            if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed  )
1610
            {
1611
                framesProcessed = AdaptingProcess( bp, streamCallbackResult,
1612
                        0 /* dont process partial user buffers */ );
1613
            }
1614
            else
1615
            {
1616
                framesProcessed = AdaptingProcess( bp, streamCallbackResult,
1617
                        1 /* process partial user buffers */ );
1618
            }
1619
        }
1620
        else if( bp->inputChannelCount != 0 )
1621
        {
1622
            /* input only */
1623
            framesToProcess = bp->hostInputFrameCount[0];
1624

    
1625
            framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
1626
                        bp->hostInputChannels[0], framesToProcess );
1627

    
1628
            framesToProcess = bp->hostInputFrameCount[1];
1629
            if( framesToProcess > 0 )
1630
            {
1631
                framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
1632
                        bp->hostInputChannels[1], framesToProcess );
1633
            }
1634
        }
1635
        else
1636
        {
1637
            /* output only */
1638
            framesToProcess = bp->hostOutputFrameCount[0];
1639

    
1640
            framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
1641
                        bp->hostOutputChannels[0], framesToProcess );
1642

    
1643
            framesToProcess = bp->hostOutputFrameCount[1];
1644
            if( framesToProcess > 0 )
1645
            {
1646
                framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
1647
                        bp->hostOutputChannels[1], framesToProcess );
1648
            }
1649
        }
1650
    }
1651

    
1652
    return framesProcessed;
1653
}
1654

    
1655

    
1656
int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
1657
{
1658
    return (bp->framesInTempOutputBuffer) ? 0 : 1;
1659
} 
1660

    
1661

    
1662
unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
1663
        void **buffer, unsigned long frameCount )
1664
{
1665
    PaUtilChannelDescriptor *hostInputChannels;
1666
    unsigned int framesToCopy;
1667
    unsigned char *destBytePtr;
1668
    void **nonInterleavedDestPtrs;
1669
    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1670
    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
1671
    unsigned int i;
1672

    
1673
    hostInputChannels = bp->hostInputChannels[0];
1674
    framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
1675

    
1676
    if( bp->userInputIsInterleaved )
1677
    {
1678
        destBytePtr = (unsigned char*)*buffer;
1679
        
1680
        destSampleStrideSamples = bp->inputChannelCount;
1681
        destChannelStrideBytes = bp->bytesPerUserInputSample;
1682

    
1683
        for( i=0; i<bp->inputChannelCount; ++i )
1684
        {
1685
            bp->inputConverter( destBytePtr, destSampleStrideSamples,
1686
                                hostInputChannels[i].data,
1687
                                hostInputChannels[i].stride,
1688
                                framesToCopy, &bp->ditherGenerator );
1689

    
1690
            destBytePtr += destChannelStrideBytes;  /* skip to next dest channel */
1691

    
1692
            /* advance source ptr for next iteration */
1693
            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1694
                    framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1695
        }
1696

    
1697
        /* advance callers dest pointer (buffer) */
1698
        *buffer = ((unsigned char *)*buffer) +
1699
                framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
1700
    }
1701
    else
1702
    {
1703
        /* user input is not interleaved */
1704
        
1705
        nonInterleavedDestPtrs = (void**)*buffer;
1706

    
1707
        destSampleStrideSamples = 1;
1708
        
1709
        for( i=0; i<bp->inputChannelCount; ++i )
1710
        {
1711
            destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
1712

    
1713
            bp->inputConverter( destBytePtr, destSampleStrideSamples,
1714
                                hostInputChannels[i].data,
1715
                                hostInputChannels[i].stride,
1716
                                framesToCopy, &bp->ditherGenerator );
1717

    
1718
            /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
1719
            destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
1720
            nonInterleavedDestPtrs[i] = destBytePtr;
1721
            
1722
            /* advance source ptr for next iteration */
1723
            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
1724
                    framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
1725
        }
1726
    }
1727

    
1728
    bp->hostInputFrameCount[0] -= framesToCopy;
1729
    
1730
    return framesToCopy;
1731
}
1732

    
1733
unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
1734
        const void ** buffer, unsigned long frameCount )
1735
{
1736
    PaUtilChannelDescriptor *hostOutputChannels;
1737
    unsigned int framesToCopy;
1738
    unsigned char *srcBytePtr;
1739
    void **nonInterleavedSrcPtrs;
1740
    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
1741
    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
1742
    unsigned int i;
1743

    
1744
    hostOutputChannels = bp->hostOutputChannels[0];
1745
    framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
1746

    
1747
    if( bp->userOutputIsInterleaved )
1748
    {
1749
        srcBytePtr = (unsigned char*)*buffer;
1750
        
1751
        srcSampleStrideSamples = bp->outputChannelCount;
1752
        srcChannelStrideBytes = bp->bytesPerUserOutputSample;
1753

    
1754
        for( i=0; i<bp->outputChannelCount; ++i )
1755
        {
1756
            bp->outputConverter(    hostOutputChannels[i].data,
1757
                                    hostOutputChannels[i].stride,
1758
                                    srcBytePtr, srcSampleStrideSamples,
1759
                                    framesToCopy, &bp->ditherGenerator );
1760

    
1761
            srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
1762

    
1763
            /* advance dest ptr for next iteration */
1764
            hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1765
                    framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1766
        }
1767

    
1768
        /* advance callers source pointer (buffer) */
1769
        *buffer = ((unsigned char *)*buffer) +
1770
                framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
1771

    
1772
    }
1773
    else
1774
    {
1775
        /* user output is not interleaved */
1776
        
1777
        nonInterleavedSrcPtrs = (void**)*buffer;
1778

    
1779
        srcSampleStrideSamples = 1;
1780
        
1781
        for( i=0; i<bp->outputChannelCount; ++i )
1782
        {
1783
            srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
1784
            
1785
            bp->outputConverter(    hostOutputChannels[i].data,
1786
                                    hostOutputChannels[i].stride,
1787
                                    srcBytePtr, srcSampleStrideSamples,
1788
                                    framesToCopy, &bp->ditherGenerator );
1789

    
1790

    
1791
            /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
1792
            srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
1793
            nonInterleavedSrcPtrs[i] = srcBytePtr;
1794
            
1795
            /* advance dest ptr for next iteration */
1796
            hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1797
                    framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1798
        }
1799
    }
1800

    
1801
    bp->hostOutputFrameCount[0] += framesToCopy;
1802
    
1803
    return framesToCopy;
1804
}
1805

    
1806

    
1807
unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
1808
{
1809
    PaUtilChannelDescriptor *hostOutputChannels;
1810
    unsigned int framesToZero;
1811
    unsigned int i;
1812

    
1813
    hostOutputChannels = bp->hostOutputChannels[0];
1814
    framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
1815

    
1816
    for( i=0; i<bp->outputChannelCount; ++i )
1817
    {
1818
        bp->outputZeroer(   hostOutputChannels[i].data,
1819
                            hostOutputChannels[i].stride,
1820
                            framesToZero );
1821

    
1822

    
1823
        /* advance dest ptr for next iteration */
1824
        hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
1825
                framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
1826
    }
1827

    
1828
    bp->hostOutputFrameCount[0] += framesToZero;
1829
    
1830
    return framesToZero;
1831
}