/*-*- Mode: C; c-file-style: "linux"; indent-tabs-mode: nil; c-basic-offset: 8 -*-*/ #include #include #include static float *generate_signal(unsigned n_samples, double amplitude, double frequency) { float *r; unsigned i; if (!(r = malloc(n_samples * sizeof(float)))) return NULL; for (i = 0; i < n_samples; i++) r[i] = amplitude * sin(((double) i*frequency*M_PI*2)/(double) n_samples); return r; } static float *generate_silence(unsigned n_samples) { float *r; if (!(r = calloc(n_samples, sizeof(float)))) return NULL; return r; } static snd_pcm_t *open_device(const char *name, snd_pcm_stream_t stream, unsigned rate) { snd_pcm_t *d; int r; snd_pcm_hw_params_t *hw; snd_pcm_hw_params_alloca(&hw); if ((r = snd_pcm_open(&d, name, stream, 0)) < 0) { fprintf(stderr, "Cannot open audio device %s: %s\n", name, snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_any(d, hw)) < 0) { fprintf(stderr, "Cannot initialize hardware parameters: %s\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_set_access(d, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf(stderr, "Cannot set access type (%s)\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_set_format(d, hw, SND_PCM_FORMAT_FLOAT_LE)) < 0) { fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_set_rate(d, hw, rate, 0)) < 0) { fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_set_channels(d, hw, 2)) < 0) { fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params(d, hw)) < 0) { fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(r)); goto finish; } return d; finish: if (d) snd_pcm_close(d); return NULL; } static double compute_level(const float *buffer, float *sum, unsigned n_samples, unsigned iteration) { unsigned i; double max = 0.0; for (i = 0; i < n_samples; i++) { sum[i] += buffer[i]; if (sum[i] > max) max = sum[i]; } return max / (double) iteration; } int main(int argc, char *argv[]) { int ret = 1; snd_pcm_sframes_t n; float *signal = NULL, *silence = NULL, *buffer = NULL, *sum = NULL; snd_pcm_t *input = NULL, *output = NULL; unsigned rate = 44100; unsigned skip_input = 0, skip_output = 0; double frequency = 440.0, amplitude = 0.5; unsigned iteration; if (argc < 2) { fprintf(stderr, "Need to specify device.\n"); goto finish; } if (!(output = open_device(argv[1], SND_PCM_STREAM_PLAYBACK, rate))) goto finish; if (!(input = open_device(argv[1], SND_PCM_STREAM_CAPTURE, rate))) goto finish; if (!(silence = generate_silence(rate))) { fprintf(stderr, "Failed to generate silence.\n"); goto finish; } if (!(signal = generate_signal(rate, amplitude, frequency))) { fprintf(stderr, "Failed to generate signal.\n"); goto finish; } if (!(buffer = malloc(rate * sizeof(float)))) { fprintf(stderr, "Failed to allocate buffer.\n"); goto finish; } if (!(sum = calloc(rate, sizeof(float)))) { fprintf(stderr, "Failed to allocate sum buffer.\n"); goto finish; } for (iteration = 1;; iteration ++) { if ((n = snd_pcm_writei(output, silence + skip_input, rate - skip_input)) < 0) { fprintf(stderr, "Cannot write samples: %s\n", snd_strerror(n)); goto finish; } skip_input += n; if (skip_input == rate) skip_input = 0; if ((n = snd_pcm_readi(output, buffer + skip_output, rate - skip_output)) < 0) { fprintf(stderr, "Cannot read samples: %s\n", snd_strerror(n)); goto finish; } skip_output += n; if (skip_output == rate) { double level; skip_output = 0; level = compute_level(buffer, sum, rate, iteration); fprintf(stderr, "Iteration %u, level is %g.\n", iteration, level); } } ret = 0; finish: if (input) snd_pcm_close(input); if (output) snd_pcm_close(output); free(signal); free(silence); free(buffer); free(sum); return ret; }