From abee20b74fec255942d42656047e371979ef0fcf Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 13 Oct 2013 13:48:36 +0200 Subject: [PATCH] Port from OSS to ALSA, as OSS is pretty much dying these days. --- Makefile | 4 +- glpitch.cpp | 4 +- linux_audio.cpp | 109 ++++++++++++++++++++++++++++++++---------------- linux_audio.h | 6 ++- pitch.cpp | 5 +-- 5 files changed, 84 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index 3ba2c2f..93f89c7 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,9 @@ clean: $(RM) pitch glpitch pitch.o glpitch.o pitchdetector.o linux_audio.o pitch: pitch.o pitchdetector.o linux_audio.o - $(CXX) -o pitch pitch.o pitchdetector.o linux_audio.o -lfftw3 + $(CXX) -o pitch pitch.o pitchdetector.o linux_audio.o -lfftw3 -lasound glpitch: glpitch.o pitchdetector.o linux_audio.o - $(CXX) -o glpitch glpitch.o pitchdetector.o linux_audio.o $(shell sdl-config --libs) -lfftw3 -lGL + $(CXX) -o glpitch glpitch.o pitchdetector.o linux_audio.o $(shell sdl-config --libs) -lfftw3 -lGL -lasound .PHONY: clean diff --git a/glpitch.cpp b/glpitch.cpp index f494bc7..a168d79 100644 --- a/glpitch.cpp +++ b/glpitch.cpp @@ -52,7 +52,7 @@ double find_display_pos(double freq) int main(void) { PitchDetector pd(SAMPLE_RATE, FFT_LENGTH, PAD_FACTOR, OVERLAP); - int fd = get_dsp_fd(SAMPLE_RATE, FFT_LENGTH, OVERLAP); + snd_pcm_t *pcm = get_dsp_handle(SAMPLE_RATE); SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); @@ -77,7 +77,7 @@ int main(void) } short buf[FFT_LENGTH / PAD_FACTOR / OVERLAP]; - read_chunk(fd, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP); + read_chunk(pcm, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP); std::pair peak = pd.detect_pitch(buf); glMatrixMode(GL_PROJECTION); diff --git a/linux_audio.cpp b/linux_audio.cpp index b76909e..8b0d756 100644 --- a/linux_audio.cpp +++ b/linux_audio.cpp @@ -6,58 +6,97 @@ #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 == -1) { + perror("read"); + 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) { diff --git a/linux_audio.h b/linux_audio.h index e26da3d..5c1b044 100644 --- a/linux_audio.h +++ b/linux_audio.h @@ -1,8 +1,10 @@ #ifndef _LINUX_AUDIO_H #define _LINUX_AUDIO_H 1 -int get_dsp_fd(int sample_rate, int fft_length, int overlap); -void read_chunk(int fd, short *in, unsigned num_samples); +#include + +snd_pcm_t *get_dsp_handle(int sample_rate); +void read_chunk(snd_pcm_t *handle, short *in, unsigned num_samples); void write_sine(int dsp_fd, double freq, unsigned num_samples, unsigned sample_rate); #endif /* !defined(_LINUX_AUDIO_H) */ diff --git a/pitch.cpp b/pitch.cpp index 6ec6155..421c2f2 100644 --- a/pitch.cpp +++ b/pitch.cpp @@ -9,16 +9,15 @@ #include "pitchdetector.h" void print_spectrogram(double freq, double amp); -void write_sine(int dsp_fd, double freq, unsigned num_samples); int main() { PitchDetector pd(SAMPLE_RATE, FFT_LENGTH, PAD_FACTOR, OVERLAP); - int fd = get_dsp_fd(SAMPLE_RATE, FFT_LENGTH, OVERLAP); + snd_pcm_t *pcm = get_dsp_handle(SAMPLE_RATE); for ( ;; ) { short buf[FFT_LENGTH / PAD_FACTOR / OVERLAP]; - read_chunk(fd, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP); + read_chunk(pcm, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP); std::pair peak = pd.detect_pitch(buf); if (peak.first < 50.0 || peak.second - log10(FFT_LENGTH) < 0.0) { -- 2.39.2