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>
This commit is contained in:
Takashi Iwai 2018-03-05 16:10:42 +01:00
parent 66b31f2451
commit 9bc4964572

View file

@ -101,7 +101,6 @@ static unsigned int nperiods = 4; /* number of periods
static double freq = 440.0; /* sinusoidal wave frequency in Hz */ 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 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 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 buffer_size;
static snd_pcm_uframes_t period_size; static snd_pcm_uframes_t period_size;
static const char *given_test_wav_file = NULL; static const char *given_test_wav_file = NULL;
@ -289,12 +288,15 @@ static const int supported_formats[] = {
-1 -1
}; };
static void generate_sine(uint8_t *frames, int channel, int count, double *_phase) { typedef union {
double phase = *_phase; float f;
double max_phase = 1.0 / freq; int32_t i;
double step = 1.0 / (double)rate; } value_t;
double res;
float fres; static void do_generate(uint8_t *frames, int channel, int count,
value_t (*generate)(void *), void *arg)
{
value_t res;
int chn; int chn;
int32_t ires; int32_t ires;
int8_t *samp8 = (int8_t*) frames; int8_t *samp8 = (int8_t*) frames;
@ -304,134 +306,30 @@ static void generate_sine(uint8_t *frames, int channel, int count, double *_phas
while (count-- > 0) { while (count-- > 0) {
for(chn=0;chn<channels;chn++) { for(chn=0;chn<channels;chn++) {
if (chn==channel) {
res = generate(arg);
} else {
res.i = 0;
}
switch (format) { switch (format) {
case SND_PCM_FORMAT_S8: case SND_PCM_FORMAT_S8:
if (chn==channel) { *samp8++ = res.i >> 24;
res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
ires = res;
*samp8++ = ires >> 24;
} else {
*samp8++ = 0;
}
break; break;
case SND_PCM_FORMAT_S16_LE: case SND_PCM_FORMAT_S16_LE:
if (chn==channel) { *samp16++ = LE_SHORT(res.i >> 16);
res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
ires = res;
*samp16++ = LE_SHORT(ires >> 16);
} else {
*samp16++ = 0;
}
break; break;
case SND_PCM_FORMAT_S16_BE: case SND_PCM_FORMAT_S16_BE:
if (chn==channel) { *samp16++ = BE_SHORT(res.i >> 16);
res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
ires = res;
*samp16++ = BE_SHORT(ires >> 16);
} else {
*samp16++ = 0;
}
break; break;
case SND_PCM_FORMAT_FLOAT_LE: case SND_PCM_FORMAT_FLOAT_LE:
if (chn==channel) { *samp_f++ = res.f;
res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale;
fres = res;
*samp_f++ = fres;
} else {
*samp_f++ = 0.0;
}
break; break;
case SND_PCM_FORMAT_S32_LE: case SND_PCM_FORMAT_S32_LE:
if (chn==channel) { *samp32++ = LE_INT(res.i);
res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
ires = res;
*samp32++ = LE_INT(ires);
} else {
*samp32++ = 0;
}
break; break;
case SND_PCM_FORMAT_S32_BE: case SND_PCM_FORMAT_S32_BE:
if (chn==channel) { *samp32++ = BE_INT(res.i);
res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
ires = res;
*samp32++ = BE_INT(ires);
} else {
*samp32++ = 0;
}
break;
default:
;
}
}
phase += step;
if (phase >= max_phase)
phase -= max_phase;
}
*_phase = phase;
}
/* 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 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; break;
default: default:
; ;
@ -440,69 +338,63 @@ static void generate_pink_noise( uint8_t *frames, int channel, int count) {
} }
} }
/*
* 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;
}
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;
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 * useful for tests
*/ */
static void generate_pattern(uint8_t *frames, int channel, int count, int *_pattern) { static value_t generate_pattern(void *arg)
int pattern = *_pattern; {
int chn; value_t res;
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) { res.i = *(int *)arg;
for(chn=0;chn<channels;chn++,pattern++) { *(int *)arg = res.i + 1;
switch (format) { if (format != SND_PCM_FORMAT_FLOAT_LE)
case SND_PCM_FORMAT_S8: res.f = (float)res.i / (float)INT32_MAX;
if (chn==channel) { return res;
*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:
;
}
}
}
*_pattern = pattern;
} }
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) { 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; 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) static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *frames)
{ {
double phase = 0;
int pattern = 0;
int err, n; int err, n;
fflush(stdout); 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++) { for(n = 0; n < periods && !in_aborting; n++) {
if (test_type == TEST_PINK_NOISE) 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) else if (test_type == TEST_PATTERN)
generate_pattern(frames, channel, period_size, &pattern); do_generate(frames, channel, period_size, generate_pattern, &pattern);
else 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) if ((err = write_buffer(handle, frames, period_size)) < 0)
return err; return err;
@ -1265,14 +1174,13 @@ int main(int argc, char *argv[]) {
} }
frames = malloc(snd_pcm_frames_to_bytes(handle, period_size)); frames = malloc(snd_pcm_frames_to_bytes(handle, period_size));
if (test_type == TEST_PINK_NOISE)
initialize_pink_noise(&pink, 16);
if (frames == NULL) { if (frames == NULL) {
fprintf(stderr, _("No enough memory\n")); fprintf(stderr, _("No enough memory\n"));
prg_exit(EXIT_FAILURE); prg_exit(EXIT_FAILURE);
} }
init_loop();
if (speaker==0) { if (speaker==0) {
if (test_type == TEST_WAV) { if (test_type == TEST_WAV) {