Linux ALSA音频PCM播放编程

使用ALSA播放两个频率的单音,并使用GNU Radio中的Audio Source和FFT来观测声音的频谱。

  1 #include <alsa/asoundlib.h>
  2 #include <math.h>
  3 #include <inttypes.h>
  4 
  5 int main(int argc, char **argv)
  6 {
  7     long loops;
  8     snd_pcm_t *handle;
  9     snd_pcm_hw_params_t *params;
 10     snd_pcm_uframes_t frames;
 11     unsigned int val;
 12     int rc;
 13     int size;
 14     int dir;
 15     char *buffer;
 16 
 17     /* Open PCM device for playback. */
 18     rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
 19     if (rc < 0) {
 20         fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
 21         exit(1);
 22     }
 23 
 24     /* Allocate a hardware parameters object. */
 25     snd_pcm_hw_params_alloca(&params);
 26 
 27     /* Fill it in with default values. */
 28     snd_pcm_hw_params_any(handle, params);
 29 
 30     /* Interleaved mode */
 31     snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
 32     /* Signed 16-bit format */
 33     snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16);
 34     /* Two channels (stereo) */
 35     snd_pcm_hw_params_set_channels(handle, params, 2);
 36     /* 16000 samples/second sampling rate */
 37     val = 16000;
 38     snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
 39     /* Set period size to 32 frames. */
 40     frames = 32;
 41     snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
 42 
 43     /* Write the parameters to the driver */
 44     rc = snd_pcm_hw_params(handle, params);
 45     if (rc < 0) {
 46         fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
 47         exit(1);
 48     }
 49 
 50     /* Use a buffer large enough to hold one period */
 51     snd_pcm_hw_params_get_period_size(params, &frames, &dir);
 52 
 53     size = frames * 2 * 2; /* 2 bytes/sample, 2 channels */
 54 
 55     buffer = (char *) malloc(size);
 56     if(buffer == NULL) {
 57         fprintf(stderr, "Not enough Memory!\n");
 58         exit(1);
 59     }
 60 
 61     /* We want to loop for 15 seconds */
 62     snd_pcm_hw_params_get_period_time(params, &val, &dir);
 63 
 64     /* 15 seconds in microseconds divided by period time */
 65     loops = 15000000 / val;
 66 
 67     for (size_t i = 0; i < size; i += 4) {
 68         // Generate a 500Hz tone
 69         *((int16_t *)(buffer + i)) = (uint16_t)(16384.0*sin(i*2.0*M_PI/size));
 70         *((int16_t *)(buffer + i + 2)) = (uint16_t)(16384.0*sin(i*2.0*M_PI/size));
 71         // Generate a 2kHz tone
 72         *((int16_t *)(buffer + i)) += (uint16_t)(16384.0*sin(i*8.0*M_PI/size));
 73         *((int16_t *)(buffer + i + 2)) += (uint16_t)(16384.0*sin(i*8.0*M_PI/size));
 74     }
 75 
 76     while (loops > 0) {
 77         loops--;
 78         //rc = read(0, buffer, size);
 79         //if (rc == 0) {
 80         //    fprintf(stderr, "end of file on input\n");
 81         //    break;
 82         //} else if (rc != size) {
 83         //    fprintf(stderr, "short read: read %d bytes\n", rc);
 84         //}
 85 
 86         rc = snd_pcm_writei(handle, buffer, frames);
 87         if (rc == -EPIPE) {
 88             /* EPIPE means underrun */
 89             fprintf(stderr, "underrun occurred\n");
 90             snd_pcm_prepare(handle);
 91         } else if (rc < 0) {
 92             fprintf(stderr,"error from writei: %s\n", snd_strerror(rc));
 93         } else if (rc != (int)frames) {
 94             fprintf(stderr,"short write, write %d frames\n", rc);
 95         }
 96     }
 97     snd_pcm_drop(handle);
 98     snd_pcm_drain(handle);
 99     snd_pcm_close(handle);
100     free(buffer);
101     return 0;
102 }

 

 

posted @ 2017-10-22 11:51  BH5HSV  阅读(10124)  评论(0编辑  收藏  举报