2
votes

I am trying to record sound and play it in a C program. just like using those terminal lines:

arecord -D plughw:0 -r 16000 sample.wav

for record, and later on

aplay sample.wav

to play the sound.

I used this code:

/*


This example reads from the default PCM device
and writes to standard output for 5 seconds of data.


*/


/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API


#include <alsa/asoundlib.h>


int main() {
  long loops;
  int rc;
  int size;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int dir;
  snd_pcm_uframes_t frames;
  char *buffer;


  /* Open PCM device for recording (capture). */
  rc = snd_pcm_open(&handle, "default",
                    SND_PCM_STREAM_CAPTURE, 0);
  if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s\n",
            snd_strerror(rc));
    exit(1);
  }


  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);


  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);


  /* Set the desired hardware parameters. */


  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);


  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);                                 


  /* Two channels (stereo) */
  snd_pcm_hw_params_set_channels(handle, params, 2);                                 


  /* 44100 bits/second sampling rate (CD quality) */
  val = 44100;                                                     
  snd_pcm_hw_params_set_rate_near(handle, params,
                                  &val, &dir);


  /* Set period size to 32 frames. */
  frames = 32;
  snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);


  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
  }


  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params,
                                      &frames, &dir);
  size = frames * 4; /* 2 bytes/sample, 2 channels */
  buffer = (char *) malloc(size);


  /* We want to loop for 5 seconds */
  snd_pcm_hw_params_get_period_time(params,
                                         &val, &dir);
  loops = 5000000 / val;


  while (loops > 0) {
    loops--;
    rc = snd_pcm_readi(handle, buffer, frames);
    if (rc == -EPIPE) {
      /* EPIPE means overrun */
      fprintf(stderr, "overrun occurred\n");
      snd_pcm_prepare(handle);
    } else if (rc < 0) {
      fprintf(stderr,
              "error from read: %s\n",
              snd_strerror(rc));
    } else if (rc != (int)frames) {
      fprintf(stderr, "short read, read %d frames\n", rc);
    }
    rc = write(1, buffer, size);
    if (rc != size)
      fprintf(stderr,
              "short write: wrote %d bytes\n", rc);
  }


  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  free(buffer);


  return 0;
}

I compile this file this way:

gcc -o recorder -lasound recorder.c

and run it:

./recorder < sample.wav

if I try to play this with "aplay sample.wav" it's making a terrible noisy sound. but if I use "aplay -t raw -f S16_LE -c2 -r44100 sample.wav" it works good.

what I do wrong and if there is an easy way to capture audio and play it on Raspberry Pi?

Thank You for Your time.

1

1 Answers

1
votes

Its just a basic thing, when you are trying aplay sample.wav" "aplay" will look for wave header and its not there in your file. So its playing with some other format (Sampling frequency,Channels, etc ..). That why your audio become noisy.

But in aplay -t raw -f S16_LE -c2 -r44100 sample.wav you are providing all information needed and its working fine.