From 820b124165a16dbed0b043f940256e1dbe62b646 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 6 Feb 2011 13:29:48 +0100 Subject: [PATCH] Add hermite resampler core :) SRC is disabled by default. --- Makefile | 2 ++ README.md | 2 +- config.def.h | 4 ++-- driver.c | 20 ++++++++++++++---- general.h | 9 +++++++- qb/config.libs.sh | 1 - qb/config.params.sh | 1 + settings.c | 5 +++++ ssnes.c | 51 +++++++++++++++++++++++++++++++++++---------- 9 files changed, 75 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 1a8dc2f4ee..a8df69c716 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ endif ifeq ($(HAVE_SRC), 1) LIBS += $(SRC_LIBS) DEFINES += $(SRC_CFLAGS) +else + OBJ += audio/hermite.o endif ifeq ($(HAVE_CONFIGFILE), 1) diff --git a/README.md b/README.md index 817a89767f..f8b33753ed 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ SSNES requires these libraries to build: - [libsnes](http://byuu.org/bsnes/) - SDL - - libsamplerate SSNES can utilize these libraries if enabled: - nvidia-cg-toolkit - libxml2 (bSNES XML shaders) - libfreetype2 (TTF font rendering on screen) + - libsamplerate SSNES needs at least one of these audio driver libraries: diff --git a/config.def.h b/config.def.h index 760a089aed..95b104ca19 100644 --- a/config.def.h +++ b/config.def.h @@ -38,8 +38,6 @@ #ifdef HAVE_SRC #include -#else -#error HAVE_SRC is not defined! #endif @@ -144,7 +142,9 @@ static const int out_latency = 64; static const bool audio_sync = true; // Defines the quality (and cpu reqirements) of samplerate conversion. +#ifdef HAVE_SRC #define SAMPLERATE_QUALITY SRC_LINEAR +#endif // Enables use of rewind. This will incur some memory footprint depending on the save state buffer. // This rewind only works when using bSNES core atm. diff --git a/driver.c b/driver.c index 1b20000d0d..ccd59e8cd5 100644 --- a/driver.c +++ b/driver.c @@ -166,10 +166,16 @@ void init_audio(void) else g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size; +#ifdef HAVE_SRC int err; - g_extern.source = src_new(g_settings.audio.src_quality, 2, &err); - if (!g_extern.source) + g_extern.audio_data.source = src_new(g_settings.audio.src_quality, 2, &err); + if (!g_extern.audio_data.source) g_extern.audio_active = false; +#else + g_extern.audio_data.source = hermite_new(); + if (!g_extern.audio_data.source) + g_extern.audio_active = false; +#endif size_t max_bufsamples = g_extern.audio_data.block_chunk_size > g_extern.audio_data.nonblock_chunk_size ? g_extern.audio_data.block_chunk_size : g_extern.audio_data.nonblock_chunk_size; @@ -192,8 +198,14 @@ void uninit_audio(void) if ( driver.audio_data && driver.audio ) driver.audio->free(driver.audio_data); - if ( g_extern.source ) - src_delete(g_extern.source); + if ( g_extern.audio_data.source ) + { +#ifdef HAVE_SRC + src_delete(g_extern.audio_data.source); +#else + hermite_free(g_extern.audio_data.source); +#endif + } free(g_extern.audio_data.data); g_extern.audio_data.data = NULL; free(g_extern.audio_data.outsamples); g_extern.audio_data.outsamples = NULL; diff --git a/general.h b/general.h index fc3d453653..c118507756 100644 --- a/general.h +++ b/general.h @@ -33,6 +33,8 @@ #ifdef HAVE_SRC #include +#else +#include "audio/hermite.h" #endif @@ -106,7 +108,6 @@ enum ssnes_game_type struct global { bool verbose; - SRC_STATE *source; bool audio_active; bool video_active; @@ -140,6 +141,12 @@ struct global struct { +#ifdef HAVE_SRC + SRC_STATE *source; +#else + hermite_resampler_t *source; +#endif + float *data; size_t data_ptr; size_t chunk_size; diff --git a/qb/config.libs.sh b/qb/config.libs.sh index c3de3d0248..ef796c4d45 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -46,7 +46,6 @@ if [ $HAVE_FFMPEG != no ]; then fi check_pkgconf SRC samplerate -check_critical SRC "Cannot find libsamplerate." check_lib DYNAMIC -ldl dlopen diff --git a/qb/config.params.sh b/qb/config.params.sh index 92d64654fe..8572094d29 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -11,6 +11,7 @@ add_command_line_enable DYNAMIC "Enable dynamic loading of libsnes library." no add_command_line_string LIBSNES "libsnes library used" "-lsnes" add_command_line_enable FFMPEG "Enable FFmpeg recording support" no add_command_line_enable FILTER "Enable CPU filter support" no +add_command_line_enable SRC "Enable libsamplerate support" no add_command_line_enable CONFIGFILE "Disable support for config file" yes add_command_line_enable CG "Enable Cg shader support" auto add_command_line_enable XML "Enable bSNES-style XML shader support" auto diff --git a/settings.c b/settings.c index af031c72b5..d93c0f8392 100644 --- a/settings.c +++ b/settings.c @@ -122,7 +122,10 @@ static void set_defaults(void) strncpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device)); g_settings.audio.latency = out_latency; g_settings.audio.sync = audio_sync; + +#ifdef HAVE_SRC g_settings.audio.src_quality = SAMPLERATE_QUALITY; +#endif g_settings.rewind_enable = rewind_enable; g_settings.rewind_buffer_size = rewind_buffer_size; @@ -300,6 +303,7 @@ static void parse_config_file(void) CONFIG_GET_INT(audio.latency, "audio_latency"); CONFIG_GET_BOOL(audio.sync, "audio_sync"); +#ifdef HAVE_SRC if (config_get_int(conf, "audio_src_quality", &tmp_int)) { int quals[] = { SRC_ZERO_ORDER_HOLD, SRC_LINEAR, SRC_SINC_FASTEST, @@ -308,6 +312,7 @@ static void parse_config_file(void) if (tmp_int > 0 && tmp_int < 6) g_settings.audio.src_quality = quals[tmp_int]; } +#endif CONFIG_GET_STRING(video.driver, "video_driver"); CONFIG_GET_STRING(audio.driver, "audio_driver"); diff --git a/ssnes.c b/ssnes.c index f4287d33ca..6f50e0e88b 100644 --- a/ssnes.c +++ b/ssnes.c @@ -179,8 +179,8 @@ static void audio_sample(uint16_t left, uint16_t right) } #endif - g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(*(int16_t*)&left)/0x8000; - g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(*(int16_t*)&right)/0x8000; + g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(int16_t)left/0x8000; + g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(int16_t)right/0x8000; if (g_extern.audio_data.data_ptr >= g_extern.audio_data.chunk_size) { @@ -188,20 +188,37 @@ static void audio_sample(uint16_t left, uint16_t right) if (g_extern.frame_is_reverse) // Disable fucked up audio when rewinding... memset(g_extern.audio_data.data, 0, g_extern.audio_data.chunk_size * sizeof(float)); - SRC_DATA src_data; +#ifdef HAVE_SRC + SRC_DATA src_data = { + .data_in = g_extern.audio_data.data, + .data_out = g_extern.audio_data.outsamples, + .input_frames = g_extern.audio_data.chunk_size / 2, + .output_frames = g_extern.audio_data.chunk_size * 8, + .end_of_input = 0, + .src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate, + }; +#else + struct hermite_data re_data = { + .in_data = g_extern.audio_data.data, + .out_data = g_extern.audio_data.outsamples, + .in_frames = g_extern.audio_data.chunk_size / 2, + .ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate, + }; +#endif - src_data.data_in = g_extern.audio_data.data; - src_data.data_out = g_extern.audio_data.outsamples; - src_data.input_frames = g_extern.audio_data.chunk_size / 2; - src_data.output_frames = g_extern.audio_data.chunk_size * 8; - src_data.end_of_input = 0; - src_data.src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate; - - src_process(g_extern.source, &src_data); +#ifdef HAVE_SRC + src_process(g_extern.audio_data.source, &src_data); +#else + size_t output_frames_gen = hermite_process(g_extern.audio_data.source, &re_data); +#endif if (g_extern.audio_data.use_float) { +#ifdef HAVE_SRC if (driver.audio->write(driver.audio_data, g_extern.audio_data.outsamples, src_data.output_frames_gen * sizeof(float) * 2) < 0) +#else + if (driver.audio->write(driver.audio_data, g_extern.audio_data.outsamples, output_frames_gen * sizeof(float) * 2) < 0) +#endif { fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n"); g_extern.audio_active = false; @@ -209,9 +226,21 @@ static void audio_sample(uint16_t left, uint16_t right) } else { +#ifdef HAVE_SRC src_float_to_short_array(g_extern.audio_data.outsamples, g_extern.audio_data.conv_outsamples, src_data.output_frames_gen * 2); +#else + for (unsigned i = 0; i < output_frames_gen * 2; i++) + { + int32_t val = g_extern.audio_data.outsamples[i] * 0x8000; + g_extern.audio_data.conv_outsamples[i] = (val > 0x7FFF) ? 0x7FFF : (val < -0x8000 ? -0x8000 : (int16_t)val); + } +#endif +#ifdef HAVE_SRC if (driver.audio->write(driver.audio_data, g_extern.audio_data.conv_outsamples, src_data.output_frames_gen * sizeof(int16_t) * 2) < 0) +#else + if (driver.audio->write(driver.audio_data, g_extern.audio_data.conv_outsamples, output_frames_gen * sizeof(int16_t) * 2) < 0) +#endif { fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n"); g_extern.audio_active = false;