--- /dev/null
+/*
+ patest_pink.c
+
+ generate Pink Noise using Gardner method.
+ Optimization suggested by James McCartney uses a tree
+ to select which random value to replace.
+
+ 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
+
+ Tree is generated by counting trailing zeros in an increasing index.
+ When the index is zero, no random number is selected.
+
+ This program uses the Portable Audio library which is under development.
+ For more information see: http://www.audiomulch.com/portaudio/
+
+ Author: Phil Burk, http://www.softsynth.com
+
+ Revision History:
+
+ Copyleft 1999 Phil Burk - No rights reserved.
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include "pink.h"
+
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long generate_random_number( void )
+{
+ static unsigned long rand_seed = 22222; /* Change this for different random sequences. */
+ rand_seed = (rand_seed * 196314165) + 907633515;
+ return rand_seed;
+}
+
+/* Setup PinkNoise structure for N rows of generators. */
+void initialize_pink_noise( pink_noise_t *pink, int num_rows )
+{
+ int i;
+ long pmax;
+ pink->pink_index = 0;
+ pink->pink_index_mask = (1<<num_rows) - 1;
+/* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
+ pmax = (num_rows + 1) * (1<<(PINK_RANDOM_BITS-1));
+ pink->pink_scalar = 1.0f / pmax;
+/* Initialize rows. */
+ for( i=0; i<num_rows; i++ ) pink->pink_rows[i] = 0;
+ pink->pink_running_sum = 0;
+}
+
+/* generate Pink noise values between -1.0 and +1.0 */
+float generate_pink_noise_sample( pink_noise_t *pink )
+{
+ long new_random;
+ long sum;
+ float output;
+
+/* Increment and mask index. */
+ pink->pink_index = (pink->pink_index + 1) & pink->pink_index_mask;
+
+/* 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 num_zeros = 0;
+ int n = pink->pink_index;
+ while( (n & 1) == 0 )
+ {
+ n = n >> 1;
+ num_zeros++;
+ }
+
+ /* Replace the indexed ROWS random value.
+ * Subtract and add back to Running_sum instead of adding all the random
+ * values together. Only one changes each time.
+ */
+ pink->pink_running_sum -= pink->pink_rows[num_zeros];
+ new_random = ((long)generate_random_number()) >> PINK_RANDOM_SHIFT;
+ pink->pink_running_sum += new_random;
+ pink->pink_rows[num_zeros] = new_random;
+ }
+
+/* Add extra white noise value. */
+ new_random = ((long)generate_random_number()) >> PINK_RANDOM_SHIFT;
+ sum = pink->pink_running_sum + new_random;
+
+/* Scale to range of -1.0 to 0.9999. */
+ output = pink->pink_scalar * sum;
+
+ return output;
+}
/*
* Copyright (C) 2000-2004 James Courtier-Dutton
+ * Copyright (C) 2005 Nathan Hurst
*
* This file is part of the speaker-test tool.
*
*
* Main program by James Courtier-Dutton (including some source code fragments from the alsa project.)
* Some cleanup from Daniel Caujolle-Bert <segfault@club-internet.fr>
+ * Pink noise option added Nathan Hurst,
+ * based on generator by Phil Burk (pink.c)
*
* Changelog:
+ * 0.0.8 Added support for pink noise output.
+ * Changelog:
+ * 0.0.7 Added support for more than 6 channels.
+ * Changelog:
* 0.0.6 Added support for different sample formats.
*
* $Id: speaker_test.c,v 1.00 2003/11/26 19:43:38 jcdutton Exp $
#include <alsa/asoundlib.h>
#include <sys/time.h>
#include <math.h>
+#include "pink.h"
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */
static unsigned int period_time = 100000; /* period time in us */
#define PERIODS 4
static double freq = 440; /* sinusoidal wave frequency in Hz */
+static int test_type = 1; /* Test type. 1 = noise, 2 = sine wave */
+static pink_noise_t pink;
static snd_output_t *output = NULL;
static snd_pcm_uframes_t buffer_size;
static snd_pcm_uframes_t period_size;
*_phase = phase;
}
-/* FIXME: Implement, because it is a better test than sine wave
- * because we can tell where pink noise is coming from more easily that a sine wave
+/* Pink noise is a better test than sine wave because we can tell
+ * where pink noise is coming from more easily that a sine wave.
*/
-#if 0
-static void generate_pink_noise( snd_pcm_uframes_t offset, int count, double *_phase) {
+
+
+static void generate_pink_noise( signed short *samples, int channel, int count) {
+ double res;
+ int chn, ires;
+
+ while (count-- > 0) {
+ for(chn=0;chn<channels;chn++) {
+ if (chn==channel) {
+ // I've chosen to write different noise to each channel as it
+ // is more pleasant. -- njh
+ res = generate_pink_noise_sample(&pink) * 32767;
+ ires = res;
+ *samples++ = ires;
+ } else
+ *samples++ = 0;
+ }
+
+ }
+
}
-#endif
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) {
unsigned int rrate;
int err, cptr, n;
for(n = 0; n < periods; n++) {
-
- generate_sine(samples, channel, period_size, &phase);
+ if(test_type==1)
+ generate_pink_noise(samples, channel, period_size);
+ else
+ generate_sine(samples, channel, period_size, &phase);
+
ptr = samples;
cptr = period_size;
"-F,--format sample format\n"
"-b,--buffer ring buffer size in us\n"
"-p,--period period size in us\n"
+ "-t,--test 1=use pink noise, 2=use sine wave\n"
"-s,--speaker single speaker test. Values 1=Left or 2=right\n"
"\n");
#if 1
{"format", 1, NULL, 'F'},
{"buffer", 1, NULL, 'b'},
{"period", 1, NULL, 'p'},
- {"speaker", 1, NULL, 's'},
+ {"test", 1, NULL, 't'},
+ {"speaker", 1, NULL, 's'},
{NULL, 0, NULL, 0 },
};
while (1) {
int c;
- if ((c = getopt_long(argc, argv, "hD:r:c:f:F:b:p:s:", long_option, NULL)) < 0)
+ if ((c = getopt_long(argc, argv, "hD:r:c:f:F:b:p:t:s:", long_option, NULL)) < 0)
break;
switch (c) {
period_time = period_time < 1000 ? 1000 : period_time;
period_time = period_time > 1000000 ? 1000000 : period_time;
break;
+ case 't':
+ test_type = atoi(optarg);
+ test_type = test_type < 1 ? 1 : test_type;
+ test_type = test_type > 2 ? 2 : test_type;
+ break;
case 's':
speaker = atoi(optarg);
speaker = speaker < 1 ? 0 : speaker;
printf("Playback device is %s\n", device);
printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
- printf("Sine wave rate is %.4fHz\n", freq);
+ if(test_type==1)
+ printf("Using 16 octaves of pink noise\n");
+ else
+ printf("Sine wave rate is %.4fHz\n", freq);
+
loop:
while ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Playback open error: %d,%s\n", err,snd_strerror(err));
}
samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8);
+ initialize_pink_noise( &pink, 16);
+
if (samples == NULL) {
printf("No enough memory\n");
exit(EXIT_FAILURE);