aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--curses/Makefile.am6
-rw-r--r--curses/configure.ac6
-rw-r--r--curses/main.c125
3 files changed, 118 insertions, 19 deletions
diff --git a/curses/Makefile.am b/curses/Makefile.am
index 92f981f..586f76d 100644
--- a/curses/Makefile.am
+++ b/curses/Makefile.am
@@ -14,6 +14,6 @@ fmpc_SOURCES=main.c \
$(LIBOPNA_SOURCES) \
$(FMDRIVER_SOURCES)
-fmpc_CFLAGS=-Wall -Wextra -pedantic \
- -I.. $(PORTAUDIO_CFLAGS) $(CURSES_CFLAGS)
-fmpc_LDADD=$(PORTAUDIO_LIBS) $(CURSES_LIBS) $(LIBICONV)
+fmpc_CFLAGS=-Wall -Wextra -pedantic-errors \
+ -I.. $(PORTAUDIO_CFLAGS) $(CURSES_CFLAGS) $(SAMPLERATE_CFLAGS)
+fmpc_LDADD=$(PORTAUDIO_LIBS) $(CURSES_LIBS) $(LIBICONV) $(SAMPLERATE_LIBS)
diff --git a/curses/configure.ac b/curses/configure.ac
index d4623ea..c397e03 100644
--- a/curses/configure.ac
+++ b/curses/configure.ac
@@ -1,8 +1,14 @@
AC_INIT([fmplayer], [0.1.0])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+AM_SILENT_RULES([yes])
AC_PROG_CC_C99
PKG_CHECK_MODULES([PORTAUDIO], [portaudio-2.0])
+AC_ARG_WITH([samplerate], AS_HELP_STRING([--with-samplerate], [Use libsamplerate and output at native samplerate (needed on NetBSD)]))
+AS_IF([test "x$with_samplerate" = "xyes"], [
+ PKG_CHECK_MODULES([SAMPLERATE], [samplerate])
+ AC_DEFINE([HAVE_SAMPLERATE])
+])
AX_WITH_CURSES
AM_ICONV
diff --git a/curses/main.c b/curses/main.c
index 1b97584..73fea89 100644
--- a/curses/main.c
+++ b/curses/main.c
@@ -9,19 +9,61 @@
#include <portaudio.h>
#include <stdlib.h>
#include <locale.h>
+#include <langinfo.h>
#include <iconv.h>
#include <errno.h>
+#ifdef HAVE_SAMPLERATE
+#include <samplerate.h>
+#endif
static uint8_t g_data[0x10000];
-
enum {
SRATE = 55467,
};
+#ifdef HAVE_SAMPLERATE
+
+struct {
+ double src_ratio;
+} g;
+
+enum {
+ READFRAMES = 256,
+};
+
+static long src_cb(void *cb_data, float **data) {
+ static float buf_f[READFRAMES*2];
+ static int16_t buf_i[READFRAMES*2];
+ struct opna_timer *timer = (struct opna_timer *)cb_data;
+ memset(buf_i, 0, sizeof(buf_i));
+ opna_timer_mix(timer, buf_i, READFRAMES);
+ src_short_to_float_array(buf_i, buf_f, READFRAMES*2);
+ *data = buf_f;
+ return READFRAMES;
+}
+
+static int pastream_cb_src(const void *inptr, void *outptr,
+ unsigned long frames,
+ const PaStreamCallbackTimeInfo *timeinfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userdata) {
+ (void)inptr;
+ (void)timeinfo;
+ (void)statusFlags;
+ SRC_STATE *src = (SRC_STATE *)userdata;
+ src_callback_read(src, g.src_ratio, frames, (float *)outptr);
+ return paContinue;
+}
+
+#else // HAVE_SAMPLERATE
+
static int pastream_cb(const void *inptr, void *outptr, unsigned long frames,
const PaStreamCallbackTimeInfo *timeinfo,
PaStreamCallbackFlags statusFlags,
void *userdata) {
+ (void)inptr;
+ (void)timeinfo;
+ (void)statusFlags;
struct opna_timer *timer = (struct opna_timer *)userdata;
int16_t *buf = (int16_t *)outptr;
memset(outptr, 0, sizeof(int16_t)*frames*2);
@@ -29,6 +71,7 @@ static int pastream_cb(const void *inptr, void *outptr, unsigned long frames,
return paContinue;
}
+#endif // HAVE_SAMPLERATE
static void opna_writereg_libopna(struct fmdriver_work *work, unsigned addr, unsigned data) {
struct opna_timer *timer = (struct opna_timer *)work->opna;
@@ -416,14 +459,18 @@ int main(int argc, char **argv) {
fprintf(stderr, "cannot seek to end\n");
return 1;
}
- long filelen = ftell(file);
- if (fseek(file, 0, SEEK_SET) != 0) {
- fprintf(stderr, "cannot seek to beginning\n");
- return 1;
- }
- if ((filelen < 0) || (filelen > 0xffff)) {
- fprintf(stderr, "invalid file length: %ld\n", filelen);
- return 1;
+ size_t filelen;
+ {
+ long filelen_t = ftell(file);
+ if (fseek(file, 0, SEEK_SET) != 0) {
+ fprintf(stderr, "cannot seek to beginning\n");
+ return 1;
+ }
+ if ((filelen_t < 0) || (filelen_t > 0xffff)) {
+ fprintf(stderr, "invalid file length: %ld\n", filelen_t);
+ return 1;
+ }
+ filelen = filelen_t;
}
if (fread(g_data, 1, filelen, file) != filelen) {
fprintf(stderr, "cannot read file\n");
@@ -456,14 +503,60 @@ int main(int argc, char **argv) {
bool pvi_loaded = loadpvi(&work, &fmp, argv[1]);
bool ppz_loaded = loadppzpvi(&work, &fmp, argv[1]);
- PaError pe;
+ PaDeviceIndex pi = Pa_GetDefaultOutputDevice();
+ if (pi == paNoDevice) {
+ fprintf(stderr, "no default output device\n");
+ return 1;
+ }
PaStream *ps;
- pe = Pa_OpenDefaultStream(&ps, 0, 2, paInt16, SRATE, 0,
- pastream_cb, &timer);
- if (pe != paNoError) {
- fprintf(stderr, "cannot open audio device\n");
+ PaError pe;
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(pi);
+ if (!pdi) {
+ fprintf(stderr, "cannot get device default samplerate\n");
return 1;
}
+#ifdef HAVE_SAMPLERATE
+ {
+ double outrate = pdi->defaultSampleRate;
+ double ratio = outrate / SRATE;
+ int e;
+ SRC_STATE *src = src_callback_new(src_cb, SRC_SINC_BEST_QUALITY, 2,
+ &e, &timer);
+ if (!src) {
+ fprintf(stderr, "cannot open samplerate converter\n");
+ return 1;
+ }
+ g.src_ratio = ratio;
+ PaStreamParameters psp;
+ psp.device = pi;
+ psp.channelCount = 2;
+ psp.sampleFormat = paFloat32;
+ psp.suggestedLatency = pdi->defaultLowOutputLatency;
+ psp.hostApiSpecificStreamInfo = 0;
+ pe = Pa_OpenStream(&ps, 0, &psp, outrate, 0, 0, &pastream_cb_src, src);
+ if (pe != paNoError) {
+ fprintf(stderr, "cannot open audio device\n");
+ return 1;
+ }
+ }
+#else // HAVE_SAMPLERATE
+
+ {
+ PaStreamParameters psp;
+ psp.device = pi;
+ psp.channelCount = 2;
+ psp.sampleFormat = paInt16;
+ psp.suggestedLatency = pdi->defaultLowOutputLatency;
+ psp.hostApiSpecificStreamInfo = 0;
+ pe = Pa_OpenStream(&ps, 0, &psp, SRATE, 0, 0, &pastream_cb, &timer);
+ if (pe != paNoError) {
+ fprintf(stderr, "cannot open audio device\n");
+ return 1;
+ }
+ }
+
+#endif // HAVE_SAMPLERATE
+
Pa_StartStream(ps);
setlocale(LC_CTYPE, "");
@@ -496,10 +589,10 @@ int main(int argc, char **argv) {
};
char titlebuf[TBUFLEN+1] = {0};
for (int l = 0; l < 3; l++) {
- iconv_t cd = iconv_open("//IGNORE", "CP932");
+ iconv_t cd = iconv_open(nl_langinfo(CODESET), "CP932");
if (cd != (iconv_t)-1) {
char titlebufcrlf[TBUFLEN+1] = {0};
- const char *in = work.comment[l];
+ ICONV_CONST char *in = (char *)work.comment[l];
size_t inleft = strlen(in)+1;
char *out = titlebufcrlf;
size_t outleft = TBUFLEN;