summaryrefslogtreecommitdiff
path: root/3rdparty/portaudio/examples/paex_pink.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portaudio/examples/paex_pink.c')
-rw-r--r--3rdparty/portaudio/examples/paex_pink.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/3rdparty/portaudio/examples/paex_pink.c b/3rdparty/portaudio/examples/paex_pink.c
new file mode 100644
index 0000000..519f979
--- /dev/null
+++ b/3rdparty/portaudio/examples/paex_pink.c
@@ -0,0 +1,280 @@
+/** @file paex_pink.c
+ @ingroup examples_src
+ @brief Generate Pink Noise using Gardner method.
+
+ Optimization suggested by James McCartney uses a tree
+ to select which random value to replace.
+<pre>
+ x x x x x x x x x x x x x x x x
+ x x x x x x x x
+ x x x x
+ x x
+ x
+</pre>
+ Tree is generated by counting trailing zeros in an increasing index.
+ When the index is zero, no random number is selected.
+
+ @author Phil Burk http://www.softsynth.com
+*/
+/*
+ * $Id$
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define PINK_MAX_RANDOM_ROWS (30)
+#define PINK_RANDOM_BITS (24)
+#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS)
+
+typedef struct
+{
+ long pink_Rows[PINK_MAX_RANDOM_ROWS];
+ long pink_RunningSum; /* Used to optimize summing of generators. */
+ int pink_Index; /* Incremented each sample. */
+ int pink_IndexMask; /* Index wrapped by ANDing with this mask. */
+ float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */
+}
+PinkNoise;
+
+/* Prototypes */
+static unsigned long GenerateRandomNumber( void );
+void InitializePinkNoise( PinkNoise *pink, int numRows );
+float GeneratePinkNoise( PinkNoise *pink );
+
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long GenerateRandomNumber( void )
+{
+ /* Change this seed for different random sequences. */
+ static unsigned long randSeed = 22222;
+ randSeed = (randSeed * 196314165) + 907633515;
+ return randSeed;
+}
+
+/************************************************************/
+/* Setup PinkNoise structure for N rows of generators. */
+void InitializePinkNoise( PinkNoise *pink, int numRows )
+{
+ int i;
+ long pmax;
+ pink->pink_Index = 0;
+ pink->pink_IndexMask = (1<<numRows) - 1;
+ /* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
+ pmax = (numRows + 1) * (1<<(PINK_RANDOM_BITS-1));
+ pink->pink_Scalar = 1.0f / pmax;
+ /* Initialize rows. */
+ for( i=0; i<numRows; i++ ) pink->pink_Rows[i] = 0;
+ pink->pink_RunningSum = 0;
+}
+
+#define PINK_MEASURE
+#ifdef PINK_MEASURE
+float pinkMax = -999.0;
+float pinkMin = 999.0;
+#endif
+
+/* Generate Pink noise values between -1.0 and +1.0 */
+float GeneratePinkNoise( PinkNoise *pink )
+{
+ long newRandom;
+ long sum;
+ float output;
+ /* Increment and mask index. */
+ pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask;
+ /* If index is zero, don't update any random values. */
+ if( pink->pink_Index != 0 )
+ {
+ /* Determine how many trailing zeros in PinkIndex. */
+ /* This algorithm will hang if n==0 so test first. */
+ int numZeros = 0;
+ int n = pink->pink_Index;
+ while( (n & 1) == 0 )
+ {
+ n = n >> 1;
+ numZeros++;
+ }
+ /* Replace the indexed ROWS random value.
+ * Subtract and add back to RunningSum instead of adding all the random
+ * values together. Only one changes each time.
+ */
+ pink->pink_RunningSum -= pink->pink_Rows[numZeros];
+ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
+ pink->pink_RunningSum += newRandom;
+ pink->pink_Rows[numZeros] = newRandom;
+ }
+
+ /* Add extra white noise value. */
+ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
+ sum = pink->pink_RunningSum + newRandom;
+ /* Scale to range of -1.0 to 0.9999. */
+ output = pink->pink_Scalar * sum;
+#ifdef PINK_MEASURE
+ /* Check Min/Max */
+ if( output > pinkMax ) pinkMax = output;
+ else if( output < pinkMin ) pinkMin = output;
+#endif
+ return output;
+}
+
+/*******************************************************************/
+#define PINK_TEST
+#ifdef PINK_TEST
+
+/* Context for callback routine. */
+typedef struct
+{
+ PinkNoise leftPink;
+ PinkNoise rightPink;
+ unsigned int sampsToGo;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback(const void* inputBuffer,
+ void* outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void* userData)
+{
+ int finished;
+ int i;
+ int numFrames;
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+
+ /* Are we almost at end. */
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ numFrames = data->sampsToGo;
+ finished = 1;
+ }
+ else
+ {
+ numFrames = framesPerBuffer;
+ finished = 0;
+ }
+ for( i=0; i<numFrames; i++ )
+ {
+ *out++ = GeneratePinkNoise( &data->leftPink );
+ *out++ = GeneratePinkNoise( &data->rightPink );
+ }
+ data->sampsToGo -= numFrames;
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream* stream;
+ PaError err;
+ paTestData data;
+ PaStreamParameters outputParameters;
+ int totalSamps;
+ static const double SR = 44100.0;
+ static const int FPB = 2048; /* Frames per buffer: 46 ms buffers. */
+
+ /* Initialize two pink noise signals with different numbers of rows. */
+ InitializePinkNoise( &data.leftPink, 12 );
+ InitializePinkNoise( &data.rightPink, 16 );
+
+ /* Look at a few values. */
+ {
+ int i;
+ float pink;
+ for( i=0; i<20; i++ )
+ {
+ pink = GeneratePinkNoise( &data.leftPink );
+ printf("Pink = %f\n", pink );
+ }
+ }
+
+ data.sampsToGo = totalSamps = (int)(60.0 * SR); /* Play a whole minute. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ /* Open a stereo PortAudio stream so we can hear the result. */
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* Take the default output device. */
+ if (outputParameters.device == paNoDevice) {
+ fprintf(stderr,"Error: No default output device.\n");
+ goto error;
+ }
+ outputParameters.channelCount = 2; /* Stereo output, most likely supported. */
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */
+ outputParameters.suggestedLatency =
+ Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
+ err = Pa_OpenStream(&stream,
+ NULL, /* No input. */
+ &outputParameters,
+ SR, /* Sample rate. */
+ FPB, /* Frames per buffer. */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data);
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Stereo pink noise for one minute...\n");
+
+ while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
+ if( err < 0 ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+#ifdef PINK_MEASURE
+ printf("Pink min = %f, max = %f\n", pinkMin, pinkMax );
+#endif
+ Pa_Terminate();
+ return 0;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occurred while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return 0;
+}
+#endif /* PINK_TEST */