annotate src/portaudio_20161030_catalina_patch/examples/paex_pink.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 4edcd14160a5
children
rev   line source
Chris@4 1 /** @file paex_pink.c
Chris@4 2 @ingroup examples_src
Chris@4 3 @brief Generate Pink Noise using Gardner method.
Chris@4 4
Chris@4 5 Optimization suggested by James McCartney uses a tree
Chris@4 6 to select which random value to replace.
Chris@4 7 <pre>
Chris@4 8 x x x x x x x x x x x x x x x x
Chris@4 9 x x x x x x x x
Chris@4 10 x x x x
Chris@4 11 x x
Chris@4 12 x
Chris@4 13 </pre>
Chris@4 14 Tree is generated by counting trailing zeros in an increasing index.
Chris@4 15 When the index is zero, no random number is selected.
Chris@4 16
Chris@4 17 @author Phil Burk http://www.softsynth.com
Chris@4 18 */
Chris@4 19 /*
Chris@55 20 * $Id$
Chris@4 21 *
Chris@4 22 * This program uses the PortAudio Portable Audio Library.
Chris@4 23 * For more information see: http://www.portaudio.com
Chris@4 24 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
Chris@4 25 *
Chris@4 26 * Permission is hereby granted, free of charge, to any person obtaining
Chris@4 27 * a copy of this software and associated documentation files
Chris@4 28 * (the "Software"), to deal in the Software without restriction,
Chris@4 29 * including without limitation the rights to use, copy, modify, merge,
Chris@4 30 * publish, distribute, sublicense, and/or sell copies of the Software,
Chris@4 31 * and to permit persons to whom the Software is furnished to do so,
Chris@4 32 * subject to the following conditions:
Chris@4 33 *
Chris@4 34 * The above copyright notice and this permission notice shall be
Chris@4 35 * included in all copies or substantial portions of the Software.
Chris@4 36 *
Chris@4 37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@4 38 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@4 39 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Chris@4 40 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
Chris@4 41 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@4 42 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@4 43 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@4 44 */
Chris@4 45
Chris@4 46 /*
Chris@4 47 * The text above constitutes the entire PortAudio license; however,
Chris@4 48 * the PortAudio community also makes the following non-binding requests:
Chris@4 49 *
Chris@4 50 * Any person wishing to distribute modifications to the Software is
Chris@4 51 * requested to send the modifications to the original developer so that
Chris@4 52 * they can be incorporated into the canonical version. It is also
Chris@4 53 * requested that these non-binding requests be included along with the
Chris@4 54 * license above.
Chris@4 55 */
Chris@4 56
Chris@4 57 #include <stdio.h>
Chris@4 58 #include <math.h>
Chris@4 59 #include "portaudio.h"
Chris@4 60
Chris@4 61 #define PINK_MAX_RANDOM_ROWS (30)
Chris@4 62 #define PINK_RANDOM_BITS (24)
Chris@4 63 #define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS)
Chris@4 64
Chris@4 65 typedef struct
Chris@4 66 {
Chris@4 67 long pink_Rows[PINK_MAX_RANDOM_ROWS];
Chris@4 68 long pink_RunningSum; /* Used to optimize summing of generators. */
Chris@4 69 int pink_Index; /* Incremented each sample. */
Chris@4 70 int pink_IndexMask; /* Index wrapped by ANDing with this mask. */
Chris@4 71 float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */
Chris@4 72 }
Chris@4 73 PinkNoise;
Chris@4 74
Chris@4 75 /* Prototypes */
Chris@4 76 static unsigned long GenerateRandomNumber( void );
Chris@4 77 void InitializePinkNoise( PinkNoise *pink, int numRows );
Chris@4 78 float GeneratePinkNoise( PinkNoise *pink );
Chris@4 79
Chris@4 80 /************************************************************/
Chris@4 81 /* Calculate pseudo-random 32 bit number based on linear congruential method. */
Chris@4 82 static unsigned long GenerateRandomNumber( void )
Chris@4 83 {
Chris@4 84 /* Change this seed for different random sequences. */
Chris@4 85 static unsigned long randSeed = 22222;
Chris@4 86 randSeed = (randSeed * 196314165) + 907633515;
Chris@4 87 return randSeed;
Chris@4 88 }
Chris@4 89
Chris@4 90 /************************************************************/
Chris@4 91 /* Setup PinkNoise structure for N rows of generators. */
Chris@4 92 void InitializePinkNoise( PinkNoise *pink, int numRows )
Chris@4 93 {
Chris@4 94 int i;
Chris@4 95 long pmax;
Chris@4 96 pink->pink_Index = 0;
Chris@4 97 pink->pink_IndexMask = (1<<numRows) - 1;
Chris@4 98 /* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
Chris@4 99 pmax = (numRows + 1) * (1<<(PINK_RANDOM_BITS-1));
Chris@4 100 pink->pink_Scalar = 1.0f / pmax;
Chris@4 101 /* Initialize rows. */
Chris@4 102 for( i=0; i<numRows; i++ ) pink->pink_Rows[i] = 0;
Chris@4 103 pink->pink_RunningSum = 0;
Chris@4 104 }
Chris@4 105
Chris@4 106 #define PINK_MEASURE
Chris@4 107 #ifdef PINK_MEASURE
Chris@4 108 float pinkMax = -999.0;
Chris@4 109 float pinkMin = 999.0;
Chris@4 110 #endif
Chris@4 111
Chris@4 112 /* Generate Pink noise values between -1.0 and +1.0 */
Chris@4 113 float GeneratePinkNoise( PinkNoise *pink )
Chris@4 114 {
Chris@4 115 long newRandom;
Chris@4 116 long sum;
Chris@4 117 float output;
Chris@4 118 /* Increment and mask index. */
Chris@4 119 pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask;
Chris@4 120 /* If index is zero, don't update any random values. */
Chris@4 121 if( pink->pink_Index != 0 )
Chris@4 122 {
Chris@4 123 /* Determine how many trailing zeros in PinkIndex. */
Chris@4 124 /* This algorithm will hang if n==0 so test first. */
Chris@4 125 int numZeros = 0;
Chris@4 126 int n = pink->pink_Index;
Chris@4 127 while( (n & 1) == 0 )
Chris@4 128 {
Chris@4 129 n = n >> 1;
Chris@4 130 numZeros++;
Chris@4 131 }
Chris@4 132 /* Replace the indexed ROWS random value.
Chris@4 133 * Subtract and add back to RunningSum instead of adding all the random
Chris@4 134 * values together. Only one changes each time.
Chris@4 135 */
Chris@4 136 pink->pink_RunningSum -= pink->pink_Rows[numZeros];
Chris@4 137 newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
Chris@4 138 pink->pink_RunningSum += newRandom;
Chris@4 139 pink->pink_Rows[numZeros] = newRandom;
Chris@4 140 }
Chris@4 141
Chris@4 142 /* Add extra white noise value. */
Chris@4 143 newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
Chris@4 144 sum = pink->pink_RunningSum + newRandom;
Chris@4 145 /* Scale to range of -1.0 to 0.9999. */
Chris@4 146 output = pink->pink_Scalar * sum;
Chris@4 147 #ifdef PINK_MEASURE
Chris@4 148 /* Check Min/Max */
Chris@4 149 if( output > pinkMax ) pinkMax = output;
Chris@4 150 else if( output < pinkMin ) pinkMin = output;
Chris@4 151 #endif
Chris@4 152 return output;
Chris@4 153 }
Chris@4 154
Chris@4 155 /*******************************************************************/
Chris@4 156 #define PINK_TEST
Chris@4 157 #ifdef PINK_TEST
Chris@4 158
Chris@4 159 /* Context for callback routine. */
Chris@4 160 typedef struct
Chris@4 161 {
Chris@4 162 PinkNoise leftPink;
Chris@4 163 PinkNoise rightPink;
Chris@4 164 unsigned int sampsToGo;
Chris@4 165 }
Chris@4 166 paTestData;
Chris@4 167
Chris@4 168 /* This routine will be called by the PortAudio engine when audio is needed.
Chris@4 169 ** It may called at interrupt level on some machines so don't do anything
Chris@4 170 ** that could mess up the system like calling malloc() or free().
Chris@4 171 */
Chris@4 172 static int patestCallback(const void* inputBuffer,
Chris@4 173 void* outputBuffer,
Chris@4 174 unsigned long framesPerBuffer,
Chris@4 175 const PaStreamCallbackTimeInfo* timeInfo,
Chris@4 176 PaStreamCallbackFlags statusFlags,
Chris@4 177 void* userData)
Chris@4 178 {
Chris@4 179 int finished;
Chris@4 180 int i;
Chris@4 181 int numFrames;
Chris@4 182 paTestData *data = (paTestData*)userData;
Chris@4 183 float *out = (float*)outputBuffer;
Chris@4 184 (void) inputBuffer; /* Prevent "unused variable" warnings. */
Chris@4 185
Chris@4 186 /* Are we almost at end. */
Chris@4 187 if( data->sampsToGo < framesPerBuffer )
Chris@4 188 {
Chris@4 189 numFrames = data->sampsToGo;
Chris@4 190 finished = 1;
Chris@4 191 }
Chris@4 192 else
Chris@4 193 {
Chris@4 194 numFrames = framesPerBuffer;
Chris@4 195 finished = 0;
Chris@4 196 }
Chris@4 197 for( i=0; i<numFrames; i++ )
Chris@4 198 {
Chris@4 199 *out++ = GeneratePinkNoise( &data->leftPink );
Chris@4 200 *out++ = GeneratePinkNoise( &data->rightPink );
Chris@4 201 }
Chris@4 202 data->sampsToGo -= numFrames;
Chris@4 203 return finished;
Chris@4 204 }
Chris@4 205
Chris@4 206 /*******************************************************************/
Chris@4 207 int main(void);
Chris@4 208 int main(void)
Chris@4 209 {
Chris@4 210 PaStream* stream;
Chris@4 211 PaError err;
Chris@4 212 paTestData data;
Chris@4 213 PaStreamParameters outputParameters;
Chris@4 214 int totalSamps;
Chris@4 215 static const double SR = 44100.0;
Chris@4 216 static const int FPB = 2048; /* Frames per buffer: 46 ms buffers. */
Chris@4 217
Chris@4 218 /* Initialize two pink noise signals with different numbers of rows. */
Chris@4 219 InitializePinkNoise( &data.leftPink, 12 );
Chris@4 220 InitializePinkNoise( &data.rightPink, 16 );
Chris@4 221
Chris@4 222 /* Look at a few values. */
Chris@4 223 {
Chris@4 224 int i;
Chris@4 225 float pink;
Chris@4 226 for( i=0; i<20; i++ )
Chris@4 227 {
Chris@4 228 pink = GeneratePinkNoise( &data.leftPink );
Chris@4 229 printf("Pink = %f\n", pink );
Chris@4 230 }
Chris@4 231 }
Chris@4 232
Chris@4 233 data.sampsToGo = totalSamps = (int)(60.0 * SR); /* Play a whole minute. */
Chris@4 234 err = Pa_Initialize();
Chris@4 235 if( err != paNoError ) goto error;
Chris@4 236
Chris@4 237 /* Open a stereo PortAudio stream so we can hear the result. */
Chris@4 238 outputParameters.device = Pa_GetDefaultOutputDevice(); /* Take the default output device. */
Chris@4 239 if (outputParameters.device == paNoDevice) {
Chris@4 240 fprintf(stderr,"Error: No default output device.\n");
Chris@4 241 goto error;
Chris@4 242 }
Chris@4 243 outputParameters.channelCount = 2; /* Stereo output, most likely supported. */
Chris@4 244 outputParameters.hostApiSpecificStreamInfo = NULL;
Chris@4 245 outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */
Chris@4 246 outputParameters.suggestedLatency =
Chris@4 247 Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
Chris@4 248 err = Pa_OpenStream(&stream,
Chris@4 249 NULL, /* No input. */
Chris@4 250 &outputParameters,
Chris@4 251 SR, /* Sample rate. */
Chris@4 252 FPB, /* Frames per buffer. */
Chris@4 253 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 254 patestCallback,
Chris@4 255 &data);
Chris@4 256 if( err != paNoError ) goto error;
Chris@4 257
Chris@4 258 err = Pa_StartStream( stream );
Chris@4 259 if( err != paNoError ) goto error;
Chris@4 260
Chris@4 261 printf("Stereo pink noise for one minute...\n");
Chris@4 262
Chris@4 263 while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
Chris@4 264 if( err < 0 ) goto error;
Chris@4 265
Chris@4 266 err = Pa_CloseStream( stream );
Chris@4 267 if( err != paNoError ) goto error;
Chris@4 268 #ifdef PINK_MEASURE
Chris@4 269 printf("Pink min = %f, max = %f\n", pinkMin, pinkMax );
Chris@4 270 #endif
Chris@4 271 Pa_Terminate();
Chris@4 272 return 0;
Chris@4 273 error:
Chris@4 274 Pa_Terminate();
Chris@4 275 fprintf( stderr, "An error occured while using the portaudio stream\n" );
Chris@4 276 fprintf( stderr, "Error number: %d\n", err );
Chris@4 277 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
Chris@4 278 return 0;
Chris@4 279 }
Chris@4 280 #endif /* PINK_TEST */