sad

simple audio daemon
git clone git://git.2f30.org/sad
Log | Files | Refs | LICENSE

commit 70dc06dc013ce4da8ab30f835bc81fefbbe6d78d
parent a861ac2a0fe727e66b1504c188f539959dd5b72e
Author: sin <sin@2f30.org>
Date:   Tue, 30 Dec 2014 17:00:57 +0000

Add initial implementation of resampler

Diffstat:
MMakefile | 2+-
Mconfig.def.h | 8++++----
Mlibrary.c | 4++++
Mmp3.c | 2++
Moutput.c | 178++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msad.h | 3+--
Mvorbis.c | 2++
Mwav.c | 2++
8 files changed, 137 insertions(+), 64 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,7 @@ MANPREFIX = $(PREFIX)/man CFLAGS = -I/usr/local/include LDFLAGS = -L /usr/local/lib -LDLIBS = -lsndfile -lmpg123 -lsndio -lasound -lvorbisfile +LDLIBS = -lsndfile -lmpg123 -lsndio -lasound -lvorbisfile -lsoxr OBJ =\ alsa.o\ diff --git a/config.def.h b/config.def.h @@ -1,5 +1,5 @@ -Outputdesc Outputdescs[] = { - { "sndio", 16, 44100, 2, 1, 0, &sndiooutput }, - { "alsa" , 16, 44100, 2, 1, 0, &alsaoutput }, - { "fifo", 16, 44100, 2, 1, 0, &fifooutput }, +Outputdesc outputdescs[] = { + { "sndio", 16, 44100, 2, 0, 0, &sndiooutput, NULL, -1 }, + { "alsa" , 16, 44100, 2, 1, 0, &alsaoutput, NULL, -1 }, + { "fifo", 16, 44100, 2, 0, 0, &fifooutput, NULL, -1 }, }; diff --git a/library.c b/library.c @@ -7,6 +7,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include "sad.h" @@ -19,6 +20,9 @@ addlibrary(const char *path) Decoder *d; Song *s; + if (access(path, F_OK) < 0) + return NULL; + s = findsong(path); if (s) return s; diff --git a/mp3.c b/mp3.c @@ -44,6 +44,8 @@ mp3open(const char *name) goto err0; } + initresamplers(rate); + return 0; err0: mpg123_close(hdl); diff --git a/output.c b/output.c @@ -3,8 +3,10 @@ #include <err.h> #include <limits.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <strings.h> +#include <soxr.h> #include "sad.h" @@ -16,34 +18,74 @@ typedef struct { int enabled; int active; Output *output; + soxr_t resampler; + int inrate; } Outputdesc; #include "config.h" +static int +initresampler(Outputdesc *desc, int inrate) +{ + soxr_quality_spec_t quality; + soxr_io_spec_t iospec; + int i; + + /* TODO: resampling quality should be configurable in config.h */ + quality = soxr_quality_spec(SOXR_VHQ, 0); + iospec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); + if (desc->resampler) + soxr_delete(desc->resampler); + + desc->resampler = soxr_create(inrate, desc->rate, + desc->channels, + NULL, + &iospec, + &quality, + NULL); + if (!desc->resampler) { + warnx("soxr_create: failed to initialize resampler"); + return -1; + } + + desc->inrate = inrate; + return 0; +} + int -openoutput(const char *name) +initresamplers(int inrate) { Outputdesc *desc; - int i; + int i, r = 0; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; - if (strcmp(desc->name, name)) + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; + if (!desc->enabled) continue; - if (desc->active) - return 0; - if (desc->output->open(desc->bits, - desc->rate, - desc->channels) < 0) { - desc->active = 0; - return -1; - } else { - printf("Opened %s output\n", desc->name); - desc->active = 1; - return 0; - } + if (initresampler(desc, inrate) < 0) + r = -1; } - return -1; + return r; +} + +static int +openoutput(Outputdesc *desc) +{ + int i; + + if (desc->active) + return 0; + + if (desc->output->open(desc->bits, + desc->rate, + desc->channels) < 0) { + desc->active = 0; + return -1; + } + + printf("Opened %s output\n", desc->name); + desc->active = 1; + return 0; } int @@ -52,38 +94,32 @@ openoutputs(void) Outputdesc *desc; int i, r = 0; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; if (!desc->enabled) continue; - if (openoutput(desc->name) < 0) + if (openoutput(desc) < 0) r = -1; } return r; } -int -closeoutput(const char *name) +static int +closeoutput(Outputdesc *desc) { - Outputdesc *desc; int i; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; - if (strcmp(desc->name, name)) - continue; - if (!desc->active) - return 0; - if (desc->output->close() < 0) { - desc->active = 1; - return -1; - } else { - printf("Closed %s output\n", desc->name); - desc->active = 0; - return 0; - } + if (!desc->active) + return 0; + + if (desc->output->close() < 0) { + desc->active = 1; + return -1; } - return -1; + + printf("Closed %s output\n", desc->name); + desc->active = 0; + return 0; } int @@ -92,28 +128,56 @@ closeoutputs(void) Outputdesc *desc; int i, r = 0; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; if (!desc->enabled) continue; - if (closeoutput(desc->name) < 0) + if (closeoutput(desc) < 0) r = -1; } return r; } int -playoutput(void *buf, size_t nbytes) +playoutput(void *inbuf, size_t nbytes) { Outputdesc *desc; - int i, r = 0; - - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; + soxr_error_t e; + size_t inframes, outframes; + size_t framesize; + size_t idone, odone; + void *outbuf; + float ratio; + int i, r = 0; + + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; if (!desc->active) continue; - if (desc->output->play(buf, nbytes) < 0) - r = -1; + if (desc->inrate == desc->rate) { + if (desc->output->play(inbuf, nbytes) <0) + r = -1; + } else { + framesize = (desc->bits + 7) / 8 * desc->channels; + inframes = nbytes / framesize; + ratio = (float)desc->rate / desc->inrate; + outframes = inframes * ratio + 1; + outbuf = malloc(outframes * framesize); + if (!outbuf) + err(1, "malloc"); + + e = soxr_process(desc->resampler, inbuf, inframes, + &idone, outbuf, outframes, + &odone); + if (e) { + warnx("soxr_process: failed"); + free(outbuf); + continue; + } + if (desc->output->play(outbuf, odone * framesize) < 0) + r = -1; + free(outbuf); + } } return r; } @@ -124,8 +188,8 @@ setvol(int vol) Outputdesc *desc; int i, r = 0; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; if (!desc->active) continue; if (desc->output->vol(vol) < 0) @@ -140,13 +204,13 @@ enableoutput(const char *name) Outputdesc *desc; int i, r; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; if (strcmp(desc->name, name)) continue; if (desc->active) return -1; - if (openoutput(desc->name) < 0) { + if (openoutput(desc) < 0) { desc->enabled = 0; return -1; } else { @@ -163,13 +227,13 @@ disableoutput(const char *name) Outputdesc *desc; int i; - for (i = 0; i < LEN(Outputdescs); i++) { - desc = &Outputdescs[i]; + for (i = 0; i < LEN(outputdescs); i++) { + desc = &outputdescs[i]; if (strcmp(desc->name, name)) continue; if (!desc->active) return -1; - if (closeoutput(desc->name) < 0) { + if (closeoutput(desc) < 0) { desc->enabled = 1; return -1; } else { diff --git a/sad.h b/sad.h @@ -123,9 +123,8 @@ int initdecoders(void); Decoder *matchdecoder(const char *); /* output.c */ -int openoutput(const char *); +int initresamplers(int); int openoutputs(void); -int closeoutput(const char *); int closeoutputs(void); int enableoutput(const char *); int disableoutput(const char *); diff --git a/vorbis.c b/vorbis.c @@ -34,6 +34,8 @@ vorbisopen(const char *name) goto err0; } + initresamplers(vi->rate); + return 0; err0: diff --git a/wav.c b/wav.c @@ -51,6 +51,8 @@ wavopen(const char *name) goto err0; } + initresamplers(sfinfo.samplerate); + return 0; err0: sf_close(sf);