X-Git-Url: https://git.sesse.net/?p=pitch;a=blobdiff_plain;f=linux_audio.cpp;h=c07e6bb289a543419d608063796ada457157c66c;hp=b76909e7588fa2048bfa6b7ba8bf2e0abb257847;hb=a500a1c540da51bdb686bdb9657b354c4238bcb2;hpb=14e6df5b242c72acc44cf8f68a56ee35dd5c43cf diff --git a/linux_audio.cpp b/linux_audio.cpp index b76909e..c07e6bb 100644 --- a/linux_audio.cpp +++ b/linux_audio.cpp @@ -6,58 +6,102 @@ #include #include #include - +#include #include "linux_audio.h" -int get_dsp_fd(int sample_rate, int fft_length, int overlap) +snd_pcm_t *get_dsp_handle(int sample_rate) { - int fd = open("/dev/dsp", O_RDWR); - if (fd == -1) { - perror("/dev/dsp"); + int err; + snd_pcm_t *handle; + snd_pcm_hw_params_t *hw_params; + + if ((err = snd_pcm_open(&handle, "plughw:0,0", SND_PCM_STREAM_CAPTURE, 0)) < 0) { + fprintf(stderr, "cannot open audio device plughw:0,0: %s\n", + snd_strerror(err)); exit(1); } - - ioctl(3, SNDCTL_DSP_RESET, 0); - - int fmt = AFMT_S16_LE; // FIXME - ioctl(fd, SNDCTL_DSP_SETFMT, &fmt); - int chan = 1; - ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &chan); - - int rate = sample_rate; - ioctl(fd, SOUND_PCM_WRITE_RATE, &rate); + if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { + fprintf(stderr, "cannot allocate hardware parameter structure: %s\n", + snd_strerror(err)); + exit(1); + } - int max_fragments = 2; - int frag_shift = ffs(fft_length / overlap) - 1; - int fragments = (max_fragments << 16) | frag_shift; - ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragments); - - ioctl(3, SNDCTL_DSP_SYNC, 0); - - return fd; + if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) { + fprintf(stderr, "cannot initialize hardware parameter structure: %s\n", + snd_strerror(err)); + exit(1); + } + + if ((err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf(stderr, "cannot set access type: %s\n", + snd_strerror(err)); + exit(1); + } + + if ((err = snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { // FIXME + fprintf(stderr, "cannot set sample format: %s\n", + snd_strerror(err)); + exit(1); + } + + if ((err = snd_pcm_hw_params_set_rate(handle, hw_params, sample_rate, 0)) < 0) { + fprintf(stderr, "cannot set sample rate: %s\n", + snd_strerror(err)); + exit(1); + } + + if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, 1)) < 0) { + fprintf(stderr, "cannot set channel count: %s\n", + snd_strerror(err)); + exit(1); + } + + if ((err = snd_pcm_hw_params(handle, hw_params)) < 0) { + fprintf(stderr, "cannot set parameters: %s\n", + snd_strerror(err)); + exit(1); + } + + snd_pcm_hw_params_free(hw_params); + + if ((err = snd_pcm_prepare(handle)) < 0) { + fprintf(stderr, "cannot prepare audio interface for use: %s\n", + snd_strerror(err)); + exit(1); + } + + return handle; } #if 1 -void read_chunk(int fd, short *in, unsigned num_samples) +void read_chunk(snd_pcm_t *handle, short *in, unsigned num_samples) { int ret; + int samples_left = num_samples; - ret = read(fd, in, num_samples * sizeof(short)); - if (ret == 0) { - printf("EOF\n"); - exit(0); - } - - if (ret != int(num_samples * sizeof(short))) { - // blah - perror("read"); - exit(1); + while (samples_left > 0) { + ret = snd_pcm_readi(handle, in, samples_left); + if (ret == 0) { + printf("EOF\n"); + exit(0); + } + if (ret == -EPIPE) { + fprintf(stderr, "ALSA underrun\n"); + snd_pcm_prepare(handle); + continue; + } + if (ret < 0) { + fprintf(stderr, "snd_pcm_readi: %s\n", snd_strerror(ret)); + exit(1); + } + in += ret; + samples_left -= ret; } } #else // make a pure 440hz sine for testing -void read_chunk(int fd, short *in, unsigned num_samples) +void read_chunk(snd_pcm_t *handle, short *in, unsigned num_samples) { static double theta = 0.0; for (unsigned i = 0; i < num_samples; ++i) {