mirror of
https://github.com/libretro/RetroArch
synced 2025-03-15 13:21:29 +00:00
Make resamplers more modular.
This commit is contained in:
parent
5b57e99b89
commit
d33d2e9f0c
4
Makefile
4
Makefile
@ -27,6 +27,8 @@ OBJ = retroarch.o \
|
||||
gfx/image.o \
|
||||
gfx/fonts/fonts.o \
|
||||
gfx/fonts/bitmapfont.o \
|
||||
audio/hermite.o \
|
||||
audio/resampler.o \
|
||||
performance.o
|
||||
|
||||
JOYCONFIG_OBJ = tools/retroarch-joyconfig.o \
|
||||
@ -298,8 +300,6 @@ ifeq ($(HAVE_SINC), 1)
|
||||
ifeq ($(HAVE_NEON),1)
|
||||
OBJ += audio/sinc_neon.o
|
||||
endif
|
||||
else
|
||||
OBJ += audio/hermite.o
|
||||
endif
|
||||
OBJ += audio/utils.o
|
||||
ifeq ($(HAVE_NEON),1)
|
||||
|
@ -30,6 +30,8 @@ OBJ = retroarch.o \
|
||||
gfx/fonts/fonts.o \
|
||||
gfx/fonts/bitmapfont.o \
|
||||
gfx/image.o \
|
||||
audio/hermite.o \
|
||||
audio/resampler.o \
|
||||
performance.o
|
||||
|
||||
JOBJ := conf/config_file.o \
|
||||
@ -208,8 +210,7 @@ endif
|
||||
|
||||
ifeq ($(HAVE_SINC), 1)
|
||||
OBJ += audio/sinc.o
|
||||
else
|
||||
OBJ += audio/hermite.o
|
||||
DEFINES += -DHAVE_SINC
|
||||
endif
|
||||
|
||||
ifneq ($(V), 1)
|
||||
|
@ -27,11 +27,11 @@
|
||||
|
||||
#define CHANNELS 2
|
||||
|
||||
struct rarch_resampler
|
||||
typedef struct rarch_hermite_resampler
|
||||
{
|
||||
float chan_data[CHANNELS][4];
|
||||
double r_frac;
|
||||
};
|
||||
} rarch_hermite_resampler_t;
|
||||
|
||||
static inline float hermite_kernel(float mu1, float a, float b, float c, float d)
|
||||
{
|
||||
@ -51,16 +51,17 @@ static inline float hermite_kernel(float mu1, float a, float b, float c, float d
|
||||
return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
|
||||
}
|
||||
|
||||
rarch_resampler_t *resampler_new(void)
|
||||
void *resampler_hermite_new(void)
|
||||
{
|
||||
#ifndef RESAMPLER_TEST
|
||||
RARCH_LOG("Hermite resampler [C]\n");
|
||||
#endif
|
||||
return (rarch_resampler_t*)calloc(1, sizeof(rarch_resampler_t));
|
||||
return calloc(1, sizeof(rarch_hermite_resampler_t));
|
||||
}
|
||||
|
||||
void resampler_process(rarch_resampler_t *re, struct resampler_data *data)
|
||||
static void resampler_hermite_process(void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_hermite_resampler_t *re = (rarch_hermite_resampler_t*)re_;
|
||||
double r_step = 1.0 / data->ratio;
|
||||
size_t processed_out = 0;
|
||||
|
||||
@ -101,8 +102,15 @@ void resampler_process(rarch_resampler_t *re, struct resampler_data *data)
|
||||
data->output_frames = processed_out;
|
||||
}
|
||||
|
||||
void resampler_free(rarch_resampler_t *re)
|
||||
static void resampler_hermite_free(void *re)
|
||||
{
|
||||
free(re);
|
||||
}
|
||||
|
||||
const rarch_resampler_t hermite_resampler = {
|
||||
resampler_hermite_new,
|
||||
resampler_hermite_process,
|
||||
resampler_hermite_free,
|
||||
"hermite",
|
||||
};
|
||||
|
||||
|
@ -24,13 +24,13 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "../boolean.h"
|
||||
|
||||
// M_PI is left out of ISO C99 :(
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
|
||||
typedef struct rarch_resampler rarch_resampler_t;
|
||||
typedef float sample_t;
|
||||
|
||||
struct resampler_data
|
||||
@ -44,9 +44,33 @@ struct resampler_data
|
||||
double ratio;
|
||||
};
|
||||
|
||||
rarch_resampler_t *resampler_new(void);
|
||||
void resampler_process(rarch_resampler_t *re, struct resampler_data *data);
|
||||
void resampler_free(rarch_resampler_t *re);
|
||||
typedef struct rarch_resampler
|
||||
{
|
||||
void *(*init)(void);
|
||||
void (*process)(void *re, struct resampler_data *data);
|
||||
void (*free)(void *re);
|
||||
const char *ident;
|
||||
} rarch_resampler_t;
|
||||
|
||||
extern const rarch_resampler_t hermite_resampler;
|
||||
extern const rarch_resampler_t sinc_resampler;
|
||||
|
||||
// Reallocs resampler. Will free previous handle before allocating a new one.
|
||||
// If ident is NULL, first resampler will be used.
|
||||
bool rarch_resampler_realloc(void **re, const rarch_resampler_t **backend, const char *ident);
|
||||
|
||||
// Convenience macros.
|
||||
// freep makes sure to set handles to NULL to avoid double-free in rarch_resampler_realloc.
|
||||
#define rarch_resampler_freep(backend, handle) do { \
|
||||
if (*(backend) && *(handle)) \
|
||||
(*backend)->free(*handle); \
|
||||
*backend = NULL; \
|
||||
*handle = NULL; \
|
||||
} while(0)
|
||||
|
||||
#define rarch_resampler_process(backend, handle, data) do { \
|
||||
(backend)->process(handle, data); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
|
35
audio/sinc.c
35
audio/sinc.c
@ -62,7 +62,7 @@
|
||||
#define TAPS (SIDELOBES * 2)
|
||||
#define CUTOFF 0.98
|
||||
|
||||
struct rarch_resampler
|
||||
typedef struct rarch_sinc_resampler
|
||||
{
|
||||
sample_t phase_table[1 << PHASE_BITS][TAPS];
|
||||
sample_t buffer_l[2 * TAPS];
|
||||
@ -70,7 +70,7 @@ struct rarch_resampler
|
||||
|
||||
unsigned ptr;
|
||||
uint32_t time;
|
||||
};
|
||||
} rarch_sinc_resampler_t;
|
||||
|
||||
static inline double sinc(double val)
|
||||
{
|
||||
@ -85,7 +85,7 @@ static inline double lanzcos(double index)
|
||||
return sinc(index);
|
||||
}
|
||||
|
||||
static void init_sinc_table(rarch_resampler_t *resamp)
|
||||
static void init_sinc_table(rarch_sinc_resampler_t *resamp)
|
||||
{
|
||||
// Sinc phases: [..., p + 3, p + 2, p + 1, p + 0, p - 1, p - 2, p - 3, p - 4, ...]
|
||||
for (int i = 0; i < (1 << PHASE_BITS); i++)
|
||||
@ -121,7 +121,7 @@ static void aligned_free__(void *ptr)
|
||||
free(p[-1]);
|
||||
}
|
||||
|
||||
static inline void process_sinc_C(rarch_resampler_t *resamp, float *out_buffer)
|
||||
static inline void process_sinc_C(rarch_sinc_resampler_t *resamp, float *out_buffer)
|
||||
{
|
||||
float sum_l = 0.0f;
|
||||
float sum_r = 0.0f;
|
||||
@ -144,7 +144,7 @@ static inline void process_sinc_C(rarch_resampler_t *resamp, float *out_buffer)
|
||||
|
||||
#if defined(__AVX__) && ENABLE_AVX
|
||||
#define process_sinc_func process_sinc
|
||||
static void process_sinc(rarch_resampler_t *resamp, float *out_buffer)
|
||||
static void process_sinc(rarch_sinc_resampler_t *resamp, float *out_buffer)
|
||||
{
|
||||
__m256 sum_l = _mm256_setzero_ps();
|
||||
__m256 sum_r = _mm256_setzero_ps();
|
||||
@ -180,7 +180,7 @@ static void process_sinc(rarch_resampler_t *resamp, float *out_buffer)
|
||||
}
|
||||
#elif defined(__SSE__)
|
||||
#define process_sinc_func process_sinc
|
||||
static void process_sinc(rarch_resampler_t *resamp, float *out_buffer)
|
||||
static void process_sinc(rarch_sinc_resampler_t *resamp, float *out_buffer)
|
||||
{
|
||||
__m128 sum_l = _mm_setzero_ps();
|
||||
__m128 sum_r = _mm_setzero_ps();
|
||||
@ -230,10 +230,10 @@ static void process_sinc(rarch_resampler_t *resamp, float *out_buffer)
|
||||
|
||||
// Need to make this function pointer as Android doesn't have built-in targets
|
||||
// for NEON and plain ARMv7a.
|
||||
static void (*process_sinc_func)(rarch_resampler_t *resamp, float *out_buffer);
|
||||
static void (*process_sinc_func)(rarch_sinc_resampler_t *resamp, float *out_buffer);
|
||||
|
||||
void process_sinc_neon_asm(float *out, const float *left, const float *right, const float *coeff);
|
||||
static void process_sinc_neon(rarch_resampler_t *resamp, float *out_buffer)
|
||||
static void process_sinc_neon(rarch_sinc_resampler_t *resamp, float *out_buffer)
|
||||
{
|
||||
const float *buffer_l = resamp->buffer_l + resamp->ptr;
|
||||
const float *buffer_r = resamp->buffer_r + resamp->ptr;
|
||||
@ -247,8 +247,10 @@ static void process_sinc_neon(rarch_resampler_t *resamp, float *out_buffer)
|
||||
#define process_sinc_func process_sinc_C
|
||||
#endif
|
||||
|
||||
void resampler_process(rarch_resampler_t *re, struct resampler_data *data)
|
||||
static void resampler_sinc_process(void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_sinc_resampler_t *re = (rarch_sinc_resampler_t*)re_;
|
||||
|
||||
// If data->ratio is < 1, we are downsampling.
|
||||
// The sinc table is not set up for this, as it always assumes upsampling.
|
||||
// Downsampling will work, but with some added noise due to aliasing might be present.
|
||||
@ -283,14 +285,14 @@ void resampler_process(rarch_resampler_t *re, struct resampler_data *data)
|
||||
data->output_frames = out_frames;
|
||||
}
|
||||
|
||||
void resampler_free(rarch_resampler_t *re)
|
||||
static void resampler_sinc_free(void *re)
|
||||
{
|
||||
aligned_free__(re);
|
||||
}
|
||||
|
||||
rarch_resampler_t *resampler_new(void)
|
||||
static void *resampler_sinc_new(void)
|
||||
{
|
||||
rarch_resampler_t *re = (rarch_resampler_t*)aligned_alloc__(1024, sizeof(*re));
|
||||
rarch_sinc_resampler_t *re = (rarch_sinc_resampler_t*)aligned_alloc__(128, sizeof(*re));
|
||||
if (!re)
|
||||
return NULL;
|
||||
|
||||
@ -311,6 +313,15 @@ rarch_resampler_t *resampler_new(void)
|
||||
RARCH_LOG("Sinc resampler [C]\n");
|
||||
#endif
|
||||
|
||||
RARCH_LOG("SINC params (%u phase bits, %u taps).\n", PHASE_BITS, TAPS);
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
const rarch_resampler_t sinc_resampler = {
|
||||
resampler_sinc_new,
|
||||
resampler_sinc_process,
|
||||
resampler_sinc_free,
|
||||
"sinc",
|
||||
};
|
||||
|
||||
|
@ -275,13 +275,13 @@ FIFO BUFFER
|
||||
#include "../../fifo_buffer.c"
|
||||
|
||||
/*============================================================
|
||||
AUDIO HERMITE
|
||||
AUDIO RESAMPLER
|
||||
============================================================ */
|
||||
#include "../../audio/resampler.c"
|
||||
#ifdef HAVE_SINC
|
||||
#include "../../audio/sinc.c"
|
||||
#else
|
||||
#include "../../audio/hermite.c"
|
||||
#endif
|
||||
#include "../../audio/hermite.c"
|
||||
|
||||
/*============================================================
|
||||
RSOUND
|
||||
|
12
driver.c
12
driver.c
@ -22,6 +22,7 @@
|
||||
#include <math.h>
|
||||
#include "compat/posix_string.h"
|
||||
#include "audio/utils.h"
|
||||
#include "audio/resampler.h"
|
||||
|
||||
#ifdef HAVE_X11
|
||||
#include "gfx/context/x11_common.h"
|
||||
@ -405,9 +406,13 @@ void init_audio(void)
|
||||
g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size;
|
||||
}
|
||||
|
||||
g_extern.audio_data.source = resampler_new();
|
||||
if (!g_extern.audio_data.source)
|
||||
const char *resampler = *g_settings.audio.resampler ? g_settings.audio.resampler : NULL;
|
||||
if (!rarch_resampler_realloc(&g_extern.audio_data.resampler_data, &g_extern.audio_data.resampler,
|
||||
resampler))
|
||||
{
|
||||
RARCH_ERR("Failed to initialize resampler \"%s\".\n", resampler ? resampler : "(default)");
|
||||
g_extern.audio_active = false;
|
||||
}
|
||||
|
||||
rarch_assert(g_extern.audio_data.data = (float*)malloc(max_bufsamples * sizeof(float)));
|
||||
|
||||
@ -536,8 +541,7 @@ void uninit_audio(void)
|
||||
if (driver.audio_data && driver.audio)
|
||||
driver.audio->free(driver.audio_data);
|
||||
|
||||
if (g_extern.audio_data.source)
|
||||
resampler_free(g_extern.audio_data.source);
|
||||
rarch_resampler_freep(&g_extern.audio_data.resampler, &g_extern.audio_data.resampler_data);
|
||||
|
||||
free(g_extern.audio_data.data);
|
||||
g_extern.audio_data.data = NULL;
|
||||
|
@ -217,6 +217,8 @@ struct settings
|
||||
bool rate_control;
|
||||
float rate_control_delta;
|
||||
float volume; // dB scale
|
||||
|
||||
char resampler[32];
|
||||
} audio;
|
||||
|
||||
struct
|
||||
@ -373,7 +375,8 @@ struct global
|
||||
|
||||
struct
|
||||
{
|
||||
rarch_resampler_t *source;
|
||||
void *resampler_data;
|
||||
const rarch_resampler_t *resampler;
|
||||
|
||||
float *data;
|
||||
|
||||
|
@ -99,7 +99,9 @@ struct ff_audio_info
|
||||
// Most lossy audio codecs only support certain sampling rates.
|
||||
// Could use libswresample, but it doesn't support floating point ratios. :(
|
||||
// Use either S16 or (planar) float for simplicity.
|
||||
rarch_resampler_t *resampler;
|
||||
const rarch_resampler_t *resampler;
|
||||
void *resampler_data;
|
||||
|
||||
bool use_float;
|
||||
bool is_planar;
|
||||
unsigned sample_size;
|
||||
@ -277,7 +279,9 @@ static bool ffemu_init_audio(ffemu_t *handle)
|
||||
audio->codec->sample_rate = params->sample_rate;
|
||||
audio->codec->time_base = av_d2q(1.0 / params->sample_rate, 1000000);
|
||||
|
||||
audio->resampler = resampler_new();
|
||||
rarch_resampler_realloc(&audio->resampler_data,
|
||||
&audio->resampler,
|
||||
*g_settings.audio.resampler ? g_settings.audio.resampler : NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -683,8 +687,8 @@ void ffemu_free(ffemu_t *handle)
|
||||
if (handle->config.audio_opts)
|
||||
av_dict_free(&handle->config.audio_opts);
|
||||
|
||||
if (handle->audio.resampler)
|
||||
resampler_free(handle->audio.resampler);
|
||||
rarch_resampler_freep(&handle->audio.resampler,
|
||||
&handle->audio.resampler_data);
|
||||
|
||||
av_free(handle->audio.float_conv);
|
||||
av_free(handle->audio.resample_out);
|
||||
@ -1023,7 +1027,7 @@ static void ffemu_audio_resample(ffemu_t *handle, struct ffemu_audio_data *data)
|
||||
info.input_frames = data->frames;
|
||||
info.ratio = handle->audio.ratio;
|
||||
|
||||
resampler_process(handle->audio.resampler, &info);
|
||||
rarch_resampler_process(handle->audio.resampler, handle->audio.resampler_data, &info);
|
||||
data->data = handle->audio.resample_out;
|
||||
data->frames = info.output_frames;
|
||||
|
||||
|
@ -402,7 +402,8 @@ static bool audio_flush(const int16_t *data, size_t samples)
|
||||
|
||||
RARCH_PERFORMANCE_INIT(resampler_proc);
|
||||
RARCH_PERFORMANCE_START(resampler_proc);
|
||||
resampler_process(g_extern.audio_data.source, &src_data);
|
||||
rarch_resampler_process(g_extern.audio_data.resampler,
|
||||
g_extern.audio_data.resampler_data, &src_data);
|
||||
RARCH_PERFORMANCE_STOP(resampler_proc);
|
||||
|
||||
output_data = g_extern.audio_data.outsamples;
|
||||
|
@ -159,6 +159,10 @@
|
||||
# Audio output samplerate.
|
||||
# audio_out_rate = 48000
|
||||
|
||||
# Which resampler to use. "sinc" and "hermite" are currently implemented.
|
||||
# Default will use "sinc" if compiled in.
|
||||
# audio_resampler =
|
||||
|
||||
# When altering audio_in_rate on-the-fly, define by how much each time.
|
||||
# audio_rate_step = 0.25
|
||||
|
||||
|
@ -641,6 +641,7 @@ bool config_load_file(const char *path)
|
||||
CONFIG_GET_BOOL(audio.rate_control, "audio_rate_control");
|
||||
CONFIG_GET_FLOAT(audio.rate_control_delta, "audio_rate_control_delta");
|
||||
CONFIG_GET_FLOAT(audio.volume, "audio_volume");
|
||||
CONFIG_GET_STRING(audio.resampler, "audio_resampler");
|
||||
|
||||
CONFIG_GET_STRING(video.driver, "video_driver");
|
||||
CONFIG_GET_STRING(audio.driver, "audio_driver");
|
||||
|
Loading…
x
Reference in New Issue
Block a user