Mercurial > hg > sv-dependency-builds
comparison src/portaudio_20140130/examples/paex_pink.c @ 124:e3d5853d5918
Current stable PortAudio source
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 18 Oct 2016 13:11:05 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
123:0cef3a1bd1ae | 124:e3d5853d5918 |
---|---|
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: paex_pink.c 1752 2011-09-08 03:21:55Z philburk $ | |
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 */ |