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 / test / patest_stop_playout.c @ 162:d43aab368df9

History | View | Annotate | Download (15.4 KB)

1
/** @file patest_stop_playout.c
2
        @ingroup test_src
3
        @brief Test whether all queued samples are played when Pa_StopStream()
4
            is used with a callback or read/write stream, or when the callback
5
            returns paComplete.
6
        @author Ross Bencina <rossb@audiomulch.com>
7
*/
8
/*
9
 * $Id$
10
 *
11
 * This program uses the PortAudio Portable Audio Library.
12
 * For more information see: http://www.portaudio.com/
13
 * Copyright (c) 1999-2004 Ross Bencina and Phil Burk
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining
16
 * a copy of this software and associated documentation files
17
 * (the "Software"), to deal in the Software without restriction,
18
 * including without limitation the rights to use, copy, modify, merge,
19
 * publish, distribute, sublicense, and/or sell copies of the Software,
20
 * and to permit persons to whom the Software is furnished to do so,
21
 * subject to the following conditions:
22
 *
23
 * The above copyright notice and this permission notice shall be
24
 * included in all copies or substantial portions of the Software.
25
 *
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
29
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
30
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
31
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
 */
34

    
35
/*
36
 * The text above constitutes the entire PortAudio license; however, 
37
 * the PortAudio community also makes the following non-binding requests:
38
 *
39
 * Any person wishing to distribute modifications to the Software is
40
 * requested to send the modifications to the original developer so that
41
 * they can be incorporated into the canonical version. It is also 
42
 * requested that these non-binding requests be included along with the 
43
 * license above.
44
 */
45
#include <stdio.h>
46
#include <math.h>
47
#include "portaudio.h"
48

    
49
#define SAMPLE_RATE         (44100)
50
#define FRAMES_PER_BUFFER   (1024)
51

    
52
#define TONE_SECONDS        (1)      /* long tone */
53
#define TONE_FADE_SECONDS   (.04)    /* fades at start and end of long tone */
54
#define GAP_SECONDS         (.25)     /* gap between long tone and blip */
55
#define BLIP_SECONDS        (.035)   /* short blip */
56

    
57
#define NUM_REPEATS         (3)
58

    
59
#ifndef M_PI
60
#define M_PI (3.14159265)
61
#endif
62

    
63
#define TABLE_SIZE          (2048)
64
typedef struct
65
{
66
    float sine[TABLE_SIZE+1];
67

    
68
    int repeatCount;
69
    
70
    double phase;
71
    double lowIncrement, highIncrement;
72
    
73
    int gap1Length, toneLength, toneFadesLength, gap2Length, blipLength;
74
    int gap1Countdown, toneCountdown, gap2Countdown, blipCountdown;
75
}
76
TestData;
77

    
78

    
79
static void RetriggerTestSignalGenerator( TestData *data )
80
{
81
    data->phase = 0.;
82
    data->gap1Countdown = data->gap1Length;
83
    data->toneCountdown = data->toneLength;
84
    data->gap2Countdown = data->gap2Length;
85
    data->blipCountdown = data->blipLength;
86
}
87

    
88

    
89
static void ResetTestSignalGenerator( TestData *data )
90
{
91
    data->repeatCount = 0;
92
    RetriggerTestSignalGenerator( data );
93
}
94

    
95

    
96
static void InitTestSignalGenerator( TestData *data )
97
{
98
    int signalLengthModBufferLength, i;
99

    
100
    /* initialise sinusoidal wavetable */
101
    for( i=0; i<TABLE_SIZE; i++ )
102
    {
103
        data->sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
104
    }
105
    data->sine[TABLE_SIZE] = data->sine[0]; /* guard point for linear interpolation */
106

    
107

    
108
    
109
    data->lowIncrement = (330. / SAMPLE_RATE) * TABLE_SIZE;
110
    data->highIncrement = (1760. / SAMPLE_RATE) * TABLE_SIZE;
111

    
112
    data->gap1Length = GAP_SECONDS * SAMPLE_RATE;
113
    data->toneLength = TONE_SECONDS * SAMPLE_RATE;
114
    data->toneFadesLength = TONE_FADE_SECONDS * SAMPLE_RATE;
115
    data->gap2Length = GAP_SECONDS * SAMPLE_RATE;
116
    data->blipLength = BLIP_SECONDS * SAMPLE_RATE;
117

    
118
    /* adjust signal length to be a multiple of the buffer length */
119
    signalLengthModBufferLength = (data->gap1Length + data->toneLength + data->gap2Length + data->blipLength) % FRAMES_PER_BUFFER;
120
    if( signalLengthModBufferLength > 0 )
121
        data->toneLength += signalLengthModBufferLength;
122

    
123
    ResetTestSignalGenerator( data );
124
}
125

    
126

    
127
#define MIN( a, b ) (((a)<(b))?(a):(b))
128

    
129
static void GenerateTestSignal( TestData *data, float *stereo, int frameCount )
130
{
131
    int framesGenerated = 0;
132
    float output;
133
    long index;
134
    float fraction;
135
    int count, i;
136

    
137
    while( framesGenerated < frameCount && data->repeatCount < NUM_REPEATS )
138
    {
139
        if( framesGenerated < frameCount && data->gap1Countdown > 0 ){
140
            count = MIN( frameCount - framesGenerated, data->gap1Countdown );
141
            for( i=0; i < count; ++i )
142
            {
143
                *stereo++ = 0.f;
144
                *stereo++ = 0.f;
145
            }
146

    
147
            data->gap1Countdown -= count;
148
            framesGenerated += count;
149
        }
150
    
151
        if( framesGenerated < frameCount && data->toneCountdown > 0 ){
152
            count = MIN( frameCount - framesGenerated, data->toneCountdown );
153
            for( i=0; i < count; ++i )
154
            {
155
                /* tone with data->lowIncrement phase increment */
156
                index = (long)data->phase;
157
                fraction = data->phase - index;
158
                output = data->sine[ index ] + (data->sine[ index + 1 ] - data->sine[ index ]) * fraction;
159

    
160
                data->phase += data->lowIncrement;
161
                while( data->phase >= TABLE_SIZE )
162
                    data->phase -= TABLE_SIZE;
163

    
164
                /* apply fade to ends */
165

    
166
                if( data->toneCountdown < data->toneFadesLength )
167
                {
168
                    /* cosine-bell fade out at end */
169
                    output *= (-cos(((float)data->toneCountdown / (float)data->toneFadesLength) * M_PI) + 1.) * .5;
170
                }
171
                else if( data->toneCountdown > data->toneLength - data->toneFadesLength ) 
172
                {
173
                    /* cosine-bell fade in at start */
174
                    output *= (cos(((float)(data->toneCountdown - (data->toneLength - data->toneFadesLength)) / (float)data->toneFadesLength) * M_PI) + 1.) * .5;
175
                }
176

    
177
                output *= .5; /* play tone half as loud as blip */
178
            
179
                *stereo++ = output;
180
                *stereo++ = output;
181

    
182
                data->toneCountdown--;
183
            }                         
184

    
185
            framesGenerated += count;
186
        }
187

    
188
        if( framesGenerated < frameCount && data->gap2Countdown > 0 ){
189
            count = MIN( frameCount - framesGenerated, data->gap2Countdown );
190
            for( i=0; i < count; ++i )
191
            {
192
                *stereo++ = 0.f;
193
                *stereo++ = 0.f;
194
            }
195

    
196
            data->gap2Countdown -= count;
197
            framesGenerated += count;
198
        }
199

    
200
        if( framesGenerated < frameCount && data->blipCountdown > 0 ){
201
            count = MIN( frameCount - framesGenerated, data->blipCountdown );
202
            for( i=0; i < count; ++i )
203
            {
204
                /* tone with data->highIncrement phase increment */
205
                index = (long)data->phase;
206
                fraction = data->phase - index;
207
                output = data->sine[ index ] + (data->sine[ index + 1 ] - data->sine[ index ]) * fraction;
208

    
209
                data->phase += data->highIncrement;
210
                while( data->phase >= TABLE_SIZE )
211
                    data->phase -= TABLE_SIZE;
212

    
213
                /* cosine-bell envelope over whole blip */
214
                output *= (-cos( ((float)data->blipCountdown / (float)data->blipLength) * 2. * M_PI) + 1.) * .5;
215
                
216
                *stereo++ = output;
217
                *stereo++ = output;
218

    
219
                data->blipCountdown--;
220
            }
221

    
222
            framesGenerated += count;
223
        }
224

    
225

    
226
        if( data->blipCountdown == 0 )
227
        {
228
            RetriggerTestSignalGenerator( data );
229
            data->repeatCount++;
230
        }        
231
    }
232

    
233
    if( framesGenerated < frameCount )
234
    {
235
        count = frameCount - framesGenerated;
236
        for( i=0; i < count; ++i )
237
        {
238
            *stereo++ = 0.f;
239
            *stereo++ = 0.f;
240
        }
241
    }
242
}
243

    
244

    
245
static int IsTestSignalFinished( TestData *data )
246
{
247
    if( data->repeatCount >= NUM_REPEATS )
248
        return 1;
249
    else
250
        return 0;
251
}
252

    
253

    
254
static int TestCallback1( const void *inputBuffer, void *outputBuffer,
255
                            unsigned long frameCount,
256
                            const PaStreamCallbackTimeInfo* timeInfo,
257
                            PaStreamCallbackFlags statusFlags,
258
                            void *userData )
259
{
260
    (void) inputBuffer; /* Prevent unused variable warnings. */
261
    (void) timeInfo;
262
    (void) statusFlags;
263

    
264
    GenerateTestSignal( (TestData*)userData, (float*)outputBuffer, frameCount );
265

    
266
    if( IsTestSignalFinished( (TestData*)userData ) )
267
        return paComplete;
268
    else
269
        return paContinue;
270
}
271

    
272

    
273
volatile int testCallback2Finished = 0;
274

    
275
static int TestCallback2( const void *inputBuffer, void *outputBuffer,
276
                            unsigned long frameCount,
277
                            const PaStreamCallbackTimeInfo* timeInfo,
278
                            PaStreamCallbackFlags statusFlags,
279
                            void *userData )
280
{
281
    (void) inputBuffer; /* Prevent unused variable warnings. */
282
    (void) timeInfo;
283
    (void) statusFlags;
284

    
285
    GenerateTestSignal( (TestData*)userData, (float*)outputBuffer, frameCount );
286

    
287
    if( IsTestSignalFinished( (TestData*)userData ) )
288
        testCallback2Finished = 1;
289
   
290
    return paContinue;
291
}
292

    
293
/*******************************************************************/
294
int main(void);
295
int main(void)
296
{
297
    PaStreamParameters outputParameters;
298
    PaStream *stream;
299
    PaError err;
300
    TestData data;
301
    float writeBuffer[ FRAMES_PER_BUFFER * 2 ];
302
    
303
    printf("PortAudio Test: check that stopping stream plays out all queued samples. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
304

    
305
    InitTestSignalGenerator( &data );
306
    
307
    err = Pa_Initialize();
308
    if( err != paNoError ) goto error;
309

    
310
    outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
311
    outputParameters.channelCount = 2;       /* stereo output */
312
    outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
313
    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
314
    outputParameters.hostApiSpecificStreamInfo = NULL;
315

    
316
/* test paComplete ---------------------------------------------------------- */
317

    
318
    ResetTestSignalGenerator( &data );
319

    
320
    err = Pa_OpenStream(
321
              &stream,
322
              NULL, /* no input */
323
              &outputParameters,
324
              SAMPLE_RATE,
325
              FRAMES_PER_BUFFER,
326
              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
327
              TestCallback1,
328
              &data );
329
    if( err != paNoError ) goto error;
330

    
331
    err = Pa_StartStream( stream );
332
    if( err != paNoError ) goto error;
333

    
334
    printf("\nPlaying 'tone-blip' %d times using callback, stops by returning paComplete from callback.\n", NUM_REPEATS );
335
    printf("If final blip is not intact, callback+paComplete implementation may be faulty.\n\n" );
336

    
337
    while( (err = Pa_IsStreamActive( stream )) == 1 )
338
        Pa_Sleep( 2 );
339

    
340
    if( err != 0 ) goto error;
341

    
342
    err = Pa_StopStream( stream );
343
    if( err != paNoError ) goto error;
344

    
345
    err = Pa_CloseStream( stream );
346
    if( err != paNoError ) goto error;
347

    
348
    Pa_Sleep( 500 );
349

    
350

    
351
/* test paComplete ---------------------------------------------------------- */
352

    
353
    ResetTestSignalGenerator( &data );
354

    
355
    err = Pa_OpenStream(
356
              &stream,
357
              NULL, /* no input */
358
              &outputParameters,
359
              SAMPLE_RATE,
360
              FRAMES_PER_BUFFER,
361
              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
362
              TestCallback1,
363
              &data );
364
    if( err != paNoError ) goto error;
365

    
366
    err = Pa_StartStream( stream );
367
    if( err != paNoError ) goto error;
368

    
369
    printf("\nPlaying 'tone-blip' %d times using callback, stops by returning paComplete from callback.\n", NUM_REPEATS );
370
    printf("If final blip is not intact or is followed by garbage, callback+paComplete implementation may be faulty.\n\n" );
371

    
372
    while( (err = Pa_IsStreamActive( stream )) == 1 )
373
        Pa_Sleep( 5 );
374

    
375
    printf("Waiting 5 seconds after paComplete before stopping the stream. Tests that buffers are flushed correctly.\n");
376
    Pa_Sleep( 5000 );
377

    
378
    if( err != 0 ) goto error;
379

    
380
    err = Pa_StopStream( stream );
381
    if( err != paNoError ) goto error;
382

    
383
    err = Pa_CloseStream( stream );
384
    if( err != paNoError ) goto error;
385

    
386
    Pa_Sleep( 500 );
387

    
388

    
389
/* test Pa_StopStream() with callback --------------------------------------- */
390

    
391
    ResetTestSignalGenerator( &data );
392

    
393
    testCallback2Finished = 0;
394
    
395
    err = Pa_OpenStream(
396
              &stream,
397
              NULL, /* no input */
398
              &outputParameters,
399
              SAMPLE_RATE,
400
              FRAMES_PER_BUFFER,
401
              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
402
              TestCallback2,
403
              &data );
404
    if( err != paNoError ) goto error;
405

    
406
    err = Pa_StartStream( stream );
407
    if( err != paNoError ) goto error;
408

    
409

    
410
    printf("\nPlaying 'tone-blip' %d times using callback, stops by calling Pa_StopStream.\n", NUM_REPEATS );
411
    printf("If final blip is not intact, callback+Pa_StopStream implementation may be faulty.\n\n" );
412

    
413
    /* note that polling a volatile flag is not a good way to synchronise with
414
        the callback, but it's the best we can do portably. */
415
    while( !testCallback2Finished )
416
        Pa_Sleep( 2 );
417

    
418
    Pa_Sleep( 500 );
419

    
420
    err = Pa_StopStream( stream );
421
    if( err != paNoError ) goto error;
422
    
423

    
424
    err = Pa_CloseStream( stream );
425
    if( err != paNoError ) goto error;
426

    
427
    Pa_Sleep( 500 );
428

    
429
/* test Pa_StopStream() with Pa_WriteStream --------------------------------- */
430

    
431
    ResetTestSignalGenerator( &data );
432

    
433
    err = Pa_OpenStream(
434
              &stream,
435
              NULL, /* no input */
436
              &outputParameters,
437
              SAMPLE_RATE,
438
              FRAMES_PER_BUFFER,
439
              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
440
              NULL, /* no callback, use blocking API */
441
              NULL ); /* no callback, so no callback userData */
442
    if( err != paNoError ) goto error;
443

    
444
    err = Pa_StartStream( stream );
445
    if( err != paNoError ) goto error;
446

    
447

    
448
    printf("\nPlaying 'tone-blip' %d times using Pa_WriteStream, stops by calling Pa_StopStream.\n", NUM_REPEATS );
449
    printf("If final blip is not intact, Pa_WriteStream+Pa_StopStream implementation may be faulty.\n\n" );
450

    
451
    do{
452
        GenerateTestSignal( &data, writeBuffer, FRAMES_PER_BUFFER );
453
        err = Pa_WriteStream( stream, writeBuffer, FRAMES_PER_BUFFER );
454
        if( err != paNoError ) goto error;
455
        
456
    }while( !IsTestSignalFinished( &data ) );
457

    
458
    err = Pa_StopStream( stream );
459
    if( err != paNoError ) goto error;
460
    
461

    
462
    err = Pa_CloseStream( stream );
463
    if( err != paNoError ) goto error;
464

    
465
/* -------------------------------------------------------------------------- */
466
    
467
    Pa_Terminate();
468
    printf("Test finished.\n");
469
    
470
    return err;
471
    
472
error:
473
    Pa_Terminate();
474
    fprintf( stderr, "An error occured while using the portaudio stream\n" );
475
    fprintf( stderr, "Error number: %d\n", err );
476
    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
477
    return err;
478
}