commit 70dc06dc013ce4da8ab30f835bc81fefbbe6d78d
parent a861ac2a0fe727e66b1504c188f539959dd5b72e
Author: sin <sin@2f30.org>
Date: Tue, 30 Dec 2014 17:00:57 +0000
Add initial implementation of resampler
Diffstat:
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);