diff --git a/src/Makefile.am b/src/Makefile.am index 47207f1..f2c79a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,8 +5,13 @@ INCLUDES = $(DEPS_CFLAGS) bin_PROGRAMS = minimodem tscope +SIMPLEAUDIO_SRC=\ + simpleaudio.c \ + simpleaudio-pulse.c \ + simpleaudio-sndfile.c + minimodem_LDADD = $(DEPS_LIBS) -minimodem_SOURCES = minimodem.c tscope_print.c +minimodem_SOURCES = minimodem.c tscope_print.c $(SIMPLEAUDIO_SRC) tscope_LDADD = $(DEPS_LIBS) tscope_SOURCES = tscope.c tscope_print.c diff --git a/src/Makefile.in b/src/Makefile.in index 93b2750..f4e3f28 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -45,7 +45,10 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) -am_minimodem_OBJECTS = minimodem.$(OBJEXT) tscope_print.$(OBJEXT) +am__objects_1 = simpleaudio.$(OBJEXT) simpleaudio-pulse.$(OBJEXT) \ + simpleaudio-sndfile.$(OBJEXT) +am_minimodem_OBJECTS = minimodem.$(OBJEXT) tscope_print.$(OBJEXT) \ + $(am__objects_1) minimodem_OBJECTS = $(am_minimodem_OBJECTS) am__DEPENDENCIES_1 = minimodem_DEPENDENCIES = $(am__DEPENDENCIES_1) @@ -155,8 +158,13 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CFLAGS = -Wall -Werror INCLUDES = $(DEPS_CFLAGS) +SIMPLEAUDIO_SRC = \ + simpleaudio.c \ + simpleaudio-pulse.c \ + simpleaudio-sndfile.c + minimodem_LDADD = $(DEPS_LIBS) -minimodem_SOURCES = minimodem.c tscope_print.c +minimodem_SOURCES = minimodem.c tscope_print.c $(SIMPLEAUDIO_SRC) tscope_LDADD = $(DEPS_LIBS) tscope_SOURCES = tscope.c tscope_print.c all: all-am @@ -244,6 +252,9 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minimodem.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio-pulse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio-sndfile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleaudio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tscope.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tscope_print.Po@am__quote@ diff --git a/src/simpleaudio-pulse.c b/src/simpleaudio-pulse.c new file mode 100644 index 0000000..f677d14 --- /dev/null +++ b/src/simpleaudio-pulse.c @@ -0,0 +1,90 @@ + +#include +#include +#include + +#include +#include +#include + +#include "simpleaudio.h" +#include "simpleaudio_internal.h" + + +/* + * pulseaudio[pa_simple] backend for simpleaudio + */ + + +static size_t +sa_pulse_read( simpleaudio *sa, float *buf, size_t nframes ) +{ + int error; + pa_simple *s = (pa_simple *)sa->backend_handle; + size_t nbytes = nframes * sa->backend_framesize; + int n; + if ((n = pa_simple_read(s, buf, nbytes, &error)) < 0) { + fprintf(stderr, "pa_simple_read: %s\n", pa_strerror(error)); + return -1; + } + return n; +} + + +static void +sa_pulse_close( simpleaudio *sa ) +{ + pa_simple_free(sa->backend_handle); +} + + +static const struct simpleaudio_backend simpleaudio_backend_pulse = { + sa_pulse_read, + sa_pulse_close, +}; + +simpleaudio * +simpleaudio_open_source_pulseaudio( + // unsigned int rate, unsigned int channels, + char *app_name, char *stream_name ) +{ + int error; + + // FIXME - use source for something + // just take the default pulseaudio source for now + + /* The sample type to use */ + pa_sample_spec ss = { + .format = PA_SAMPLE_FLOAT32, + // .rate = rate, + .rate = 48000, + // .channels = channels, + .channels = 1, + }; + + /* Create the recording stream */ + pa_simple *s; + s = pa_simple_new(NULL, app_name, PA_STREAM_RECORD, NULL, stream_name, + &ss, NULL, NULL, &error); + if ( !s ) { + fprintf(stderr, "pa_simple_new: %s\n", pa_strerror(error)); + return NULL; + } + + simpleaudio *sa = malloc(sizeof(simpleaudio)); + if ( !sa ) { + perror("malloc"); + pa_simple_free(s); + return NULL; + } + sa->rate = ss.rate; + sa->channels = ss.channels; + sa->backend = &simpleaudio_backend_pulse; + sa->backend_handle = s; + sa->backend_framesize = pa_frame_size(&ss); + + assert( sa->backend_framesize == ss.channels * sizeof(float) ); + + return sa; +} + diff --git a/src/simpleaudio-sndfile.c b/src/simpleaudio-sndfile.c new file mode 100644 index 0000000..a2a304f --- /dev/null +++ b/src/simpleaudio-sndfile.c @@ -0,0 +1,74 @@ + +#include +#include +#include + +#include + +#include "simpleaudio.h" +#include "simpleaudio_internal.h" + + +/* + * sndfile backend for simpleaudio + */ + + +static size_t +sa_sndfile_read( simpleaudio *sa, float *buf, size_t nframes ) +{ + SNDFILE *s = (SNDFILE *)sa->backend_handle; + int n; + if ((n = sf_readf_float(s, buf, nframes)) < 0) { + fprintf(stderr, "sf_read_float: "); + sf_perror(s); + return -1; + } +//fprintf(stderr, "sf_read_float: nframes=%ld n=%d\n", nframes, n); + return n; +} + + +static void +sa_sndfile_close( simpleaudio *sa ) +{ + sf_close(sa->backend_handle); +} + + +static const struct simpleaudio_backend simpleaudio_backend_pulse = { + sa_sndfile_read, + sa_sndfile_close, +}; + +simpleaudio * +simpleaudio_open_source_sndfile(char *path) +{ + SF_INFO sfinfo = { + .format = 0 + }; + + /* Create the recording stream */ + SNDFILE *s; + s = sf_open(path, SFM_READ, &sfinfo); + if ( !s ) { + fprintf(stderr, "%s: ", path); + sf_perror(s); + return NULL; + } + + simpleaudio *sa = malloc(sizeof(simpleaudio)); + if ( !sa ) { + perror("malloc"); + sf_close(s); + return NULL; + } + sa->rate = sfinfo.samplerate; + sa->channels = sfinfo.channels; + sa->backend = &simpleaudio_backend_pulse; + sa->backend_handle = s; + sa->backend_framesize = sa->channels * sizeof(float); + + return sa; +} + diff --git a/src/simpleaudio.c b/src/simpleaudio.c new file mode 100644 index 0000000..6fa31ca --- /dev/null +++ b/src/simpleaudio.c @@ -0,0 +1,28 @@ +#include "simpleaudio.h" +#include "simpleaudio_internal.h" +#include "malloc.h" + +unsigned int +simpleaudio_get_rate( simpleaudio *sa ) +{ + return sa->rate; +} + +unsigned int +simpleaudio_get_channels( simpleaudio *sa ) +{ + return sa->channels; +} + +size_t +simpleaudio_read( simpleaudio *sa, float *buf, size_t nframes ) +{ + return sa->backend->simpleaudio_read(sa, buf, nframes); +} + +void +simpleaudio_close( simpleaudio *sa ) +{ + sa->backend->simpleaudio_close(sa); + free(sa); +} diff --git a/src/simpleaudio.h b/src/simpleaudio.h new file mode 100644 index 0000000..a46c19c --- /dev/null +++ b/src/simpleaudio.h @@ -0,0 +1,40 @@ +#ifndef SIMPLEAUDIO_H +#define SIMPLEAUDIO_H + +#include + +struct simpleaudio; +typedef struct simpleaudio simpleaudio; + +/* + * simpleaudio_open_source_XXXX() routines which return a (simpleaudio *) + * are provided by the separate backend modules. + * + */ + +simpleaudio * +simpleaudio_open_source_pulseaudio( + // unsigned int rate, unsigned int channels, + char *app_name, char *stream_name ); + +simpleaudio * +simpleaudio_open_source_sndfile(char *path); + +/* + * common simpleaudio_ API routines available to any backend: + */ + +unsigned int +simpleaudio_get_rate( simpleaudio *sa ); + +unsigned int +simpleaudio_get_channels( simpleaudio *sa ); + +size_t +simpleaudio_read( simpleaudio *sa, float *buf, size_t nframes ); + +void +simpleaudio_close( simpleaudio *sa ); + + +#endif diff --git a/src/simpleaudio_internal.h b/src/simpleaudio_internal.h new file mode 100644 index 0000000..8750522 --- /dev/null +++ b/src/simpleaudio_internal.h @@ -0,0 +1,31 @@ +#ifndef SIMPLEAUDIO_INTERNAL_H +#define SIMPLEAUDIO_INTERNAL_H + + +#include "simpleaudio.h" + +/* + * Backend modules must provide an "open" routine which returns a + * (simpleaudio *) to the caller. + */ + +struct simpleaudio_backend; +typedef struct simpleaudio_backend simpleaudio_backend; + +struct simpleaudio { + const struct simpleaudio_backend *backend; + unsigned int rate; + unsigned int channels; + void * backend_handle; + unsigned int backend_framesize; +}; + +struct simpleaudio_backend { + size_t + (*simpleaudio_read)( simpleaudio *sa, float *buf, size_t nframes ); + void + (*simpleaudio_close)( simpleaudio *sa ); +}; + + +#endif