]> git.alsa-project.org Git - alsa-utils.git/commitdiff
speaker-test: Refactor the tone-generator codes
authorTakashi Iwai <tiwai@suse.de>
Mon, 5 Mar 2018 15:10:42 +0000 (16:10 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 5 Mar 2018 15:13:41 +0000 (16:13 +0100)
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>
speaker-test/speaker-test.c

index 46b05897ecc8660e76e533c98da0b8b2df1eb5e7..65ab52337a36260a7796999ebe47202af7b9eef0 100644 (file)
@@ -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) {