summaryrefslogtreecommitdiff
path: root/speaker-test
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-03-05 16:10:42 +0100
committerTakashi Iwai <tiwai@suse.de>2018-03-05 16:13:41 +0100
commit9bc49645720ad1deefbb3d152430634b811e94df (patch)
tree7f1431a7737121eea47ee64cc74973d62d172a8b /speaker-test
parent66b31f24513aeccc730e203b30c15b43cf7a7f36 (diff)
downloadalsa-utils-9bc49645720ad1deefbb3d152430634b811e94df.tar.gz
speaker-test: Refactor the tone-generator codes
There are many redundant open codes in speaker-test for performing the similar things, and especially the tone generator codes are ugly. Let's clean up a bit. This patch combines all open-codes into a single common helper with the callback for generating the tone. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'speaker-test')
-rw-r--r--speaker-test/speaker-test.c274
1 files changed, 91 insertions, 183 deletions
diff --git a/speaker-test/speaker-test.c b/speaker-test/speaker-test.c
index 46b0589..65ab523 100644
--- a/speaker-test/speaker-test.c
+++ b/speaker-test/speaker-test.c
@@ -101,7 +101,6 @@ static unsigned int nperiods = 4; /* number of periods
static double freq = 440.0; /* sinusoidal wave frequency in Hz */
static int test_type = TEST_PINK_NOISE; /* Test type. 1 = noise, 2 = sine wave */
static float generator_scale = 0.8; /* Scale to use for sine volume */
-static pink_noise_t pink;
static snd_pcm_uframes_t buffer_size;
static snd_pcm_uframes_t period_size;
static const char *given_test_wav_file = NULL;
@@ -289,12 +288,15 @@ static const int supported_formats[] = {
-1
};
-static void generate_sine(uint8_t *frames, int channel, int count, double *_phase) {
- double phase = *_phase;
- double max_phase = 1.0 / freq;
- double step = 1.0 / (double)rate;
- double res;
- float fres;
+typedef union {
+ float f;
+ int32_t i;
+} value_t;
+
+static void do_generate(uint8_t *frames, int channel, int count,
+ value_t (*generate)(void *), void *arg)
+{
+ value_t res;
int chn;
int32_t ires;
int8_t *samp8 = (int8_t*) frames;
@@ -304,205 +306,95 @@ static void generate_sine(uint8_t *frames, int channel, int count, double *_phas
while (count-- > 0) {
for(chn=0;chn<channels;chn++) {
+ if (chn==channel) {
+ res = generate(arg);
+ } else {
+ res.i = 0;
+ }
+
switch (format) {
case SND_PCM_FORMAT_S8:
- if (chn==channel) {
- res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
- ires = res;
- *samp8++ = ires >> 24;
- } else {
- *samp8++ = 0;
- }
+ *samp8++ = res.i >> 24;
break;
case SND_PCM_FORMAT_S16_LE:
- if (chn==channel) {
- res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
- ires = res;
- *samp16++ = LE_SHORT(ires >> 16);
- } else {
- *samp16++ = 0;
- }
+ *samp16++ = LE_SHORT(res.i >> 16);
break;
case SND_PCM_FORMAT_S16_BE:
- if (chn==channel) {
- res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
- ires = res;
- *samp16++ = BE_SHORT(ires >> 16);
- } else {
- *samp16++ = 0;
- }
+ *samp16++ = BE_SHORT(res.i >> 16);
break;
case SND_PCM_FORMAT_FLOAT_LE:
- if (chn==channel) {
- res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale;
- fres = res;
- *samp_f++ = fres;
- } else {
- *samp_f++ = 0.0;
- }
+ *samp_f++ = res.f;
break;
case SND_PCM_FORMAT_S32_LE:
- if (chn==channel) {
- res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
- ires = res;
- *samp32++ = LE_INT(ires);
- } else {
- *samp32++ = 0;
- }
+ *samp32++ = LE_INT(res.i);
break;
case SND_PCM_FORMAT_S32_BE:
- if (chn==channel) {
- res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
- ires = res;
- *samp32++ = BE_INT(ires);
- } else {
- *samp32++ = 0;
- }
+ *samp32++ = BE_INT(res.i);
break;
default:
;
}
}
-
- phase += step;
- if (phase >= max_phase)
- phase -= max_phase;
}
+}
+
+/*
+ * Sine generator
+ */
+typedef struct {
+ double phase;
+ double max_phase;
+ double step;
+} sine_t;
+
+static void init_sine(sine_t *sine)
+{
+ sine->phase = 0;
+ sine->max_phase = 1.0 / freq;
+ sine->step = 1.0 / (double)rate;
+}
- *_phase = phase;
+static value_t generate_sine(void *arg)
+{
+ sine_t *sine = arg;
+ value_t res;
+
+ res.f = sin((sine->phase * 2 * M_PI) / sine->max_phase - M_PI);
+ res.f *= generator_scale;
+ if (format != SND_PCM_FORMAT_FLOAT_LE)
+ res.i = res.f * INT32_MAX;
+ sine->phase += sine->step;
+ if (sine->phase >= sine->max_phase)
+ sine->phase -= sine->max_phase;
+ return res;
}
/* 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.
*/
+static value_t generate_pink_noise(void *arg)
+{
+ pink_noise_t *pink = arg;
+ value_t res;
-
-static void generate_pink_noise( uint8_t *frames, int channel, int count) {
- double res;
- int chn;
- int32_t ires;
- int8_t *samp8 = (int8_t*) frames;
- int16_t *samp16 = (int16_t*) frames;
- int32_t *samp32 = (int32_t*) frames;
-
- while (count-- > 0) {
- for(chn=0;chn<channels;chn++) {
- switch (format) {
- case SND_PCM_FORMAT_S8:
- if (chn==channel) {
- res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
- ires = res;
- *samp8++ = ires >> 24;
- } else {
- *samp8++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S16_LE:
- if (chn==channel) {
- res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
- ires = res;
- *samp16++ = LE_SHORT(ires >> 16);
- } else {
- *samp16++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S16_BE:
- if (chn==channel) {
- res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
- ires = res;
- *samp16++ = BE_SHORT(ires >> 16);
- } else {
- *samp16++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S32_LE:
- if (chn==channel) {
- res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
- ires = res;
- *samp32++ = LE_INT(ires);
- } else {
- *samp32++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S32_BE:
- if (chn==channel) {
- res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
- ires = res;
- *samp32++ = BE_INT(ires);
- } else {
- *samp32++ = 0;
- }
- break;
- default:
- ;
- }
- }
- }
+ res.f = generate_pink_noise_sample(pink) * generator_scale;
+ if (format != SND_PCM_FORMAT_FLOAT_LE)
+ res.i = res.f * INT32_MAX;
+ return res;
}
/*
* useful for tests
*/
-static void generate_pattern(uint8_t *frames, int channel, int count, int *_pattern) {
- int pattern = *_pattern;
- int chn;
- int8_t *samp8 = (int8_t*) frames;
- int16_t *samp16 = (int16_t*) frames;
- int32_t *samp32 = (int32_t*) frames;
- float *samp_f = (float*) frames;
-
- while (count-- > 0) {
- for(chn=0;chn<channels;chn++,pattern++) {
- switch (format) {
- case SND_PCM_FORMAT_S8:
- if (chn==channel) {
- *samp8++ = pattern & 0xff;
- } else {
- *samp8++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S16_LE:
- if (chn==channel) {
- *samp16++ = LE_SHORT(pattern & 0xfffff);
- } else {
- *samp16++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S16_BE:
- if (chn==channel) {
- *samp16++ = BE_SHORT(pattern & 0xffff);
- } else {
- *samp16++ = 0;
- }
- break;
- case SND_PCM_FORMAT_FLOAT_LE:
- if (chn==channel) {
- *samp_f++ = LE_INT(((double)pattern) / INT32_MAX);
- } else {
- *samp_f++ = 0.0;
- }
- break;
- case SND_PCM_FORMAT_S32_LE:
- if (chn==channel) {
- *samp32++ = LE_INT(pattern);
- } else {
- *samp32++ = 0;
- }
- break;
- case SND_PCM_FORMAT_S32_BE:
- if (chn==channel) {
- *samp32++ = BE_INT(pattern);
- } else {
- *samp32++ = 0;
- }
- break;
- default:
- ;
- }
- }
- }
+static value_t generate_pattern(void *arg)
+{
+ value_t res;
- *_pattern = pattern;
+ res.i = *(int *)arg;
+ *(int *)arg = res.i + 1;
+ if (format != SND_PCM_FORMAT_FLOAT_LE)
+ res.f = (float)res.i / (float)INT32_MAX;
+ return res;
}
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) {
@@ -927,10 +819,27 @@ static int write_buffer(snd_pcm_t *handle, uint8_t *ptr, int cptr)
return 0;
}
+static int pattern;
+static sine_t sine;
+static pink_noise_t pink;
+
+static void init_loop(void)
+{
+ switch (test_type) {
+ case TEST_PINK_NOISE:
+ initialize_pink_noise(&pink, 16);
+ break;
+ case TEST_SINE:
+ init_sine(&sine);
+ break;
+ case TEST_PATTERN:
+ pattern = 0;
+ break;
+ }
+}
+
static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *frames)
{
- double phase = 0;
- int pattern = 0;
int err, n;
fflush(stdout);
@@ -956,11 +865,11 @@ static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *fram
for(n = 0; n < periods && !in_aborting; n++) {
if (test_type == TEST_PINK_NOISE)
- generate_pink_noise(frames, channel, period_size);
+ do_generate(frames, channel, period_size, generate_pink_noise, &pink);
else if (test_type == TEST_PATTERN)
- generate_pattern(frames, channel, period_size, &pattern);
+ do_generate(frames, channel, period_size, generate_pattern, &pattern);
else
- generate_sine(frames, channel, period_size, &phase);
+ do_generate(frames, channel, period_size, generate_sine, &sine);
if ((err = write_buffer(handle, frames, period_size)) < 0)
return err;
@@ -1265,14 +1174,13 @@ int main(int argc, char *argv[]) {
}
frames = malloc(snd_pcm_frames_to_bytes(handle, period_size));
- if (test_type == TEST_PINK_NOISE)
- initialize_pink_noise(&pink, 16);
-
if (frames == NULL) {
fprintf(stderr, _("No enough memory\n"));
prg_exit(EXIT_FAILURE);
}
+ init_loop();
+
if (speaker==0) {
if (test_type == TEST_WAV) {