Port from OSS to ALSA, as OSS is pretty much dying these days.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 13 Oct 2013 11:48:36 +0000 (13:48 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 13 Oct 2013 11:48:36 +0000 (13:48 +0200)
Makefile
glpitch.cpp
linux_audio.cpp
linux_audio.h
pitch.cpp

index 3ba2c2f..93f89c7 100644 (file)
--- 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
index f494bc7..a168d79 100644 (file)
@@ -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<double, double> peak = pd.detect_pitch(buf);
 
                glMatrixMode(GL_PROJECTION);
index b76909e..8b0d756 100644 (file)
@@ -6,58 +6,97 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <linux/soundcard.h>
-
+#include <alsa/asoundlib.h>
 #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) {
index e26da3d..5c1b044 100644 (file)
@@ -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 <alsa/asoundlib.h>
+
+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) */
index 6ec6155..421c2f2 100644 (file)
--- 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<double, double> peak = pd.detect_pitch(buf);
 
                if (peak.first < 50.0 || peak.second - log10(FFT_LENGTH) < 0.0) {