diff options
-rw-r--r-- | curses/Makefile.am | 6 | ||||
-rw-r--r-- | curses/configure.ac | 6 | ||||
-rw-r--r-- | curses/main.c | 125 |
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; |