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 / examples / paex_pink.c @ 162:d43aab368df9

History | View | Annotate | Download (9.69 KB)

1
/** @file paex_pink.c
2
        @ingroup examples_src
3
        @brief Generate Pink Noise using Gardner method.
4

5
        Optimization suggested by James McCartney uses a tree
6
        to select which random value to replace.
7
<pre>
8
        x x x x x x x x x x x x x x x x 
9
        x   x   x   x   x   x   x   x   
10
        x       x       x       x       
11
         x               x               
12
           x   
13
</pre>                            
14
        Tree is generated by counting trailing zeros in an increasing index.
15
        When the index is zero, no random number is selected.
16

17
        @author Phil Burk  http://www.softsynth.com
18
*/
19
/*
20
 * $Id$
21
 *
22
 * This program uses the PortAudio Portable Audio Library.
23
 * For more information see: http://www.portaudio.com
24
 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
25
 *
26
 * Permission is hereby granted, free of charge, to any person obtaining
27
 * a copy of this software and associated documentation files
28
 * (the "Software"), to deal in the Software without restriction,
29
 * including without limitation the rights to use, copy, modify, merge,
30
 * publish, distribute, sublicense, and/or sell copies of the Software,
31
 * and to permit persons to whom the Software is furnished to do so,
32
 * subject to the following conditions:
33
 *
34
 * The above copyright notice and this permission notice shall be
35
 * included in all copies or substantial portions of the Software.
36
 *
37
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
41
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
42
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
43
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44
 */
45

    
46
/*
47
 * The text above constitutes the entire PortAudio license; however, 
48
 * the PortAudio community also makes the following non-binding requests:
49
 *
50
 * Any person wishing to distribute modifications to the Software is
51
 * requested to send the modifications to the original developer so that
52
 * they can be incorporated into the canonical version. It is also 
53
 * requested that these non-binding requests be included along with the 
54
 * license above.
55
 */
56

    
57
#include <stdio.h>
58
#include <math.h>
59
#include "portaudio.h"
60

    
61
#define PINK_MAX_RANDOM_ROWS   (30)
62
#define PINK_RANDOM_BITS       (24)
63
#define PINK_RANDOM_SHIFT      ((sizeof(long)*8)-PINK_RANDOM_BITS)
64

    
65
typedef struct
66
{
67
    long      pink_Rows[PINK_MAX_RANDOM_ROWS];
68
    long      pink_RunningSum;   /* Used to optimize summing of generators. */
69
    int       pink_Index;        /* Incremented each sample. */
70
    int       pink_IndexMask;    /* Index wrapped by ANDing with this mask. */
71
    float     pink_Scalar;       /* Used to scale within range of -1.0 to +1.0 */
72
}
73
PinkNoise;
74

    
75
/* Prototypes */
76
static unsigned long GenerateRandomNumber( void );
77
void InitializePinkNoise( PinkNoise *pink, int numRows );
78
float GeneratePinkNoise( PinkNoise *pink );
79

    
80
/************************************************************/
81
/* Calculate pseudo-random 32 bit number based on linear congruential method. */
82
static unsigned long GenerateRandomNumber( void )
83
{
84
    /* Change this seed for different random sequences. */
85
    static unsigned long randSeed = 22222;
86
    randSeed = (randSeed * 196314165) + 907633515;
87
    return randSeed;
88
}
89

    
90
/************************************************************/
91
/* Setup PinkNoise structure for N rows of generators. */
92
void InitializePinkNoise( PinkNoise *pink, int numRows )
93
{
94
    int i;
95
    long pmax;
96
    pink->pink_Index = 0;
97
    pink->pink_IndexMask = (1<<numRows) - 1;
98
    /* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
99
    pmax = (numRows + 1) * (1<<(PINK_RANDOM_BITS-1));
100
    pink->pink_Scalar = 1.0f / pmax;
101
    /* Initialize rows. */
102
    for( i=0; i<numRows; i++ ) pink->pink_Rows[i] = 0;
103
    pink->pink_RunningSum = 0;
104
}
105

    
106
#define PINK_MEASURE
107
#ifdef PINK_MEASURE
108
float pinkMax = -999.0;
109
float pinkMin =  999.0;
110
#endif
111

    
112
/* Generate Pink noise values between -1.0 and +1.0 */
113
float GeneratePinkNoise( PinkNoise *pink )
114
{
115
    long newRandom;
116
    long sum;
117
    float output;
118
    /* Increment and mask index. */
119
    pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask;
120
    /* If index is zero, don't update any random values. */
121
    if( pink->pink_Index != 0 )
122
    {
123
        /* Determine how many trailing zeros in PinkIndex. */
124
        /* This algorithm will hang if n==0 so test first. */
125
        int numZeros = 0;
126
        int n = pink->pink_Index;
127
        while( (n & 1) == 0 )
128
        {
129
            n = n >> 1;
130
            numZeros++;
131
        }
132
        /* Replace the indexed ROWS random value.
133
         * Subtract and add back to RunningSum instead of adding all the random
134
         * values together. Only one changes each time.
135
         */
136
        pink->pink_RunningSum -= pink->pink_Rows[numZeros];
137
        newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
138
        pink->pink_RunningSum += newRandom;
139
        pink->pink_Rows[numZeros] = newRandom;
140
    }
141

    
142
    /* Add extra white noise value. */
143
    newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
144
    sum = pink->pink_RunningSum + newRandom;
145
    /* Scale to range of -1.0 to 0.9999. */
146
    output = pink->pink_Scalar * sum;
147
#ifdef PINK_MEASURE
148
    /* Check Min/Max */
149
    if( output > pinkMax ) pinkMax = output;
150
    else if( output < pinkMin ) pinkMin = output;
151
#endif
152
    return output;
153
}
154

    
155
/*******************************************************************/
156
#define PINK_TEST
157
#ifdef PINK_TEST
158

    
159
/* Context for callback routine. */
160
typedef struct
161
{
162
    PinkNoise   leftPink;
163
    PinkNoise   rightPink;
164
    unsigned int sampsToGo;
165
}
166
paTestData;
167

    
168
/* This routine will be called by the PortAudio engine when audio is needed.
169
** It may called at interrupt level on some machines so don't do anything
170
** that could mess up the system like calling malloc() or free().
171
*/
172
static int patestCallback(const void*                     inputBuffer,
173
                          void*                           outputBuffer,
174
                          unsigned long                   framesPerBuffer,
175
                                      const PaStreamCallbackTimeInfo* timeInfo,
176
                                      PaStreamCallbackFlags           statusFlags,
177
                          void*                           userData)
178
{
179
    int finished;
180
    int i;
181
    int numFrames;
182
    paTestData *data = (paTestData*)userData;
183
    float *out = (float*)outputBuffer;
184
    (void) inputBuffer; /* Prevent "unused variable" warnings. */
185

    
186
    /* Are we almost at end. */
187
    if( data->sampsToGo < framesPerBuffer )
188
    {
189
        numFrames = data->sampsToGo;
190
        finished = 1;
191
    }
192
    else
193
    {
194
        numFrames = framesPerBuffer;
195
        finished = 0;
196
    }
197
    for( i=0; i<numFrames; i++ )
198
    {
199
        *out++ = GeneratePinkNoise( &data->leftPink );
200
        *out++ = GeneratePinkNoise( &data->rightPink );
201
    }
202
    data->sampsToGo -= numFrames;
203
    return finished;
204
}
205

    
206
/*******************************************************************/
207
int main(void);
208
int main(void)
209
{
210
    PaStream*           stream;
211
    PaError             err;
212
    paTestData          data;
213
    PaStreamParameters  outputParameters;
214
    int                 totalSamps;
215
    static const double SR  = 44100.0;
216
    static const int    FPB = 2048; /* Frames per buffer: 46 ms buffers. */
217
    
218
    /* Initialize two pink noise signals with different numbers of rows. */
219
    InitializePinkNoise( &data.leftPink,  12 );
220
    InitializePinkNoise( &data.rightPink, 16 );
221

    
222
    /* Look at a few values. */
223
    {
224
        int i;
225
        float pink;
226
        for( i=0; i<20; i++ )
227
        {
228
            pink = GeneratePinkNoise( &data.leftPink );
229
            printf("Pink = %f\n", pink );
230
        }
231
    }
232

    
233
    data.sampsToGo = totalSamps = (int)(60.0 * SR);   /* Play a whole minute. */
234
    err = Pa_Initialize();
235
    if( err != paNoError ) goto error;
236

    
237
    /* Open a stereo PortAudio stream so we can hear the result. */
238
    outputParameters.device = Pa_GetDefaultOutputDevice(); /* Take the default output device. */
239
    if (outputParameters.device == paNoDevice) {
240
      fprintf(stderr,"Error: No default output device.\n");
241
      goto error;
242
    }
243
    outputParameters.channelCount = 2;                     /* Stereo output, most likely supported. */
244
    outputParameters.hostApiSpecificStreamInfo = NULL;
245
    outputParameters.sampleFormat = paFloat32;             /* 32 bit floating point output. */
246
    outputParameters.suggestedLatency =
247
                     Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
248
    err = Pa_OpenStream(&stream,
249
                        NULL,                              /* No input. */
250
                        &outputParameters,
251
                        SR,                                /* Sample rate. */
252
                        FPB,                               /* Frames per buffer. */
253
                        paClipOff, /* we won't output out of range samples so don't bother clipping them */
254
                        patestCallback,
255
                        &data);
256
    if( err != paNoError ) goto error;
257

    
258
    err = Pa_StartStream( stream );
259
    if( err != paNoError ) goto error;
260

    
261
    printf("Stereo pink noise for one minute...\n");
262

    
263
    while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
264
    if( err < 0 ) goto error;
265

    
266
    err = Pa_CloseStream( stream );
267
    if( err != paNoError ) goto error;
268
#ifdef PINK_MEASURE
269
    printf("Pink min = %f, max = %f\n", pinkMin, pinkMax );
270
#endif
271
    Pa_Terminate();
272
    return 0;
273
error:
274
    Pa_Terminate();
275
    fprintf( stderr, "An error occured while using the portaudio stream\n" );
276
    fprintf( stderr, "Error number: %d\n", err );
277
    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
278
    return 0;
279
}
280
#endif /* PINK_TEST */