diff --git a/speaker-test/Makefile.am b/speaker-test/Makefile.am index e4db484..c80e3fb 100644 --- a/speaker-test/Makefile.am +++ b/speaker-test/Makefile.am @@ -1,7 +1,7 @@ -SPEAKER_TEST_VERSION = 0.0.7 +SPEAKER_TEST_VERSION = 0.0.8 INCLUDES = -I$(top_srcdir)/include -DVERSION=\"$(SPEAKER_TEST_VERSION)\" bin_PROGRAMS = speaker-test -speaker_test_SOURCES = speaker-test.c +speaker_test_SOURCES = speaker-test.c pink.c man_MANS = speaker-test.1 -EXTRA_DIST = readme.txt speaker-test.1 +EXTRA_DIST = readme.txt speaker-test.1 pink.h diff --git a/speaker-test/pink.c b/speaker-test/pink.c new file mode 100644 index 0000000..ef30755 --- /dev/null +++ b/speaker-test/pink.c @@ -0,0 +1,96 @@ +/* + 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 +#include +#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<pink_scalar = 1.0f / pmax; +/* Initialize rows. */ + for( i=0; ipink_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; +} diff --git a/speaker-test/pink.h b/speaker-test/pink.h new file mode 100644 index 0000000..0d17f7a --- /dev/null +++ b/speaker-test/pink.h @@ -0,0 +1,15 @@ +#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_running_sum; /* Used to optimize summing of generators. */ + int pink_index; /* Incremented each sample. */ + int pink_index_mask; /* Index wrapped by ANDing with this mask. */ + float pink_scalar; /* Used to scale within range of -1.0 to +1.0 */ +} pink_noise_t; + +void initialize_pink_noise( pink_noise_t *pink, int num_rows ); +float generate_pink_noise_sample( pink_noise_t *pink ); diff --git a/speaker-test/speaker-test.1 b/speaker-test/speaker-test.1 index e9f521b..07a6485 100644 --- a/speaker-test/speaker-test.1 +++ b/speaker-test/speaker-test.1 @@ -26,6 +26,8 @@ speaker\-test \- command-line speaker test tone generator for ALSA .IR FREQ ] .BR "" [ \-p | \-\-period .IR TIME ] +.BR "" [ \-n | \-\-noise +.IR TIME ] .BR "" [ \-s | \-\-speaker " " "1|2" ] .P .B speaker\-test @@ -60,6 +62,14 @@ period size of \fITIME\fP microseconds \fB\-r\fP | \fB\-\-rate\fP \fIRATE\fP stream of \fIRATE\fP Hz +.TP +\fB\-t\fP | \fB\-\-test\fP \fB1\fP|\fB2\fP +-t1 means use pink noise (default). + +Pink noise is perceptually uniform noise - that is, it sounds like every frequency at once. If you can hear any tone it may indicate resonances in your speaker system or room. + +-t2 means use sine wave. + .TP \fB\-s\fP | \fB\-\-speaker\fP \fB1\fP|\fB2\fP Test speaker 1 or speaker 2 only, rather than both @@ -88,3 +98,4 @@ To send a nice low 75Hz tone to the Woofer and then exit without touching any ot .SH AUTHOR The speaker-test program was written by James Courtier-Dutton. +Pink noise support was added by Nathan Hurst. diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c index d3e8691..867735c 100644 --- a/speaker-test/speaker-test.c +++ b/speaker-test/speaker-test.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2000-2004 James Courtier-Dutton + * Copyright (C) 2005 Nathan Hurst * * This file is part of the speaker-test tool. * @@ -22,8 +23,14 @@ * * Main program by James Courtier-Dutton (including some source code fragments from the alsa project.) * Some cleanup from Daniel Caujolle-Bert + * 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 $ @@ -42,6 +49,7 @@ #include #include #include +#include "pink.h" static char *device = "plughw:0,0"; /* playback device */ static snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */ @@ -52,6 +60,8 @@ static unsigned int buffer_time = 500000; /* ring buffer lengt 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; @@ -151,13 +161,30 @@ static void generate_sine(signed short *samples, int channel, int count, double *_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 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; @@ -507,7 +544,11 @@ int main(int argc, char *argv[]) { 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)); @@ -529,6 +570,8 @@ loop: } 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);