diff --git a/Audio/Chain/ConverterNode.m b/Audio/Chain/ConverterNode.m index eddf818c8..6d5b87846 100644 --- a/Audio/Chain/ConverterNode.m +++ b/Audio/Chain/ConverterNode.m @@ -902,7 +902,7 @@ static float db_to_scale(float db) } if (resampler && resampler_data) { - resampler->free(resampler_data); + resampler->free(resampler, resampler_data); resampler = NULL; resampler_data = NULL; } diff --git a/ThirdParty/RetroArch/libretro-common/audio/resampler/audio_resampler.c b/ThirdParty/RetroArch/libretro-common/audio/resampler/audio_resampler.c index 599fab7b4..6e4baba48 100644 --- a/ThirdParty/RetroArch/libretro-common/audio/resampler/audio_resampler.c +++ b/ThirdParty/RetroArch/libretro-common/audio/resampler/audio_resampler.c @@ -34,9 +34,9 @@ static void resampler_null_process(void *a, struct resampler_data *b) { } static size_t resampler_null_latency(void *a) { return 0; } -static void resampler_null_free(void *a) { } -static void *resampler_null_init(const struct resampler_config *a, double b, - enum resampler_quality c, size_t d, resampler_simd_mask_t e) { return (void*)0; } +static void resampler_null_free(const retro_resampler_t *a, void *b) { } +static void *resampler_null_init(const struct resampler_config *a, const retro_resampler_t **b, + double c, enum resampler_quality d, size_t e, resampler_simd_mask_t f) { return (void*)0; } retro_resampler_t null_resampler = { resampler_null_init, @@ -189,7 +189,7 @@ static bool resampler_append_plugs(void **re, resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get(); if (*backend) - *re = (*backend)->init(&resampler_config, bw_ratio, quality, channels, mask); + *re = (*backend)->init(&resampler_config, backend, bw_ratio, quality, channels, mask); if (!*re) return false; @@ -244,7 +244,7 @@ bool retro_resampler_realloc(void **re, const retro_resampler_t **backend, double bw_ratio) { if (*re && *backend) - (*backend)->free(*re); + (*backend)->free(*backend, *re); *re = NULL; *backend = find_resampler_driver(ident); diff --git a/ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c b/ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c index 32f59854e..0a6136ddd 100644 --- a/ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c +++ b/ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c @@ -781,7 +781,7 @@ static size_t resampler_sinc_latency(void *data) return resamp->taps / 2; } -static void resampler_sinc_free(void *data) +static void resampler_sinc_free(const retro_resampler_t *resampler, void *data) { rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)data; if (resamp) { @@ -789,6 +789,9 @@ static void resampler_sinc_free(void *data) free(resamp->buffer); } free(resamp); + if (resampler && resampler != &sinc_resampler) { + free((void*)resampler); + } } static void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp, @@ -908,8 +911,8 @@ static void sinc_init_table_lanczos( } static void *resampler_sinc_new(const struct resampler_config *config, - double bandwidth_mod, enum resampler_quality quality, - size_t channels, resampler_simd_mask_t mask) + const retro_resampler_t **_resampler, double bandwidth_mod, + enum resampler_quality quality, size_t channels, resampler_simd_mask_t mask) { double cutoff = 0.0; size_t phase_elems = 0; @@ -920,10 +923,24 @@ static void *resampler_sinc_new(const struct resampler_config *config, enum sinc_window window_type = SINC_WINDOW_NONE; rarch_sinc_resampler_t *re = (rarch_sinc_resampler_t*) calloc(1, sizeof(*re)); + + retro_resampler_t *resampler = (retro_resampler_t*)*_resampler; if (!re) return NULL; + if (resampler == &sinc_resampler) + { + resampler = malloc(sizeof(*resampler)); + if (!resampler) + { + free(re); + return NULL; + } + memcpy(resampler, *_resampler, sizeof(*resampler)); + *_resampler = (const retro_resampler_t*)resampler; + } + switch (quality) { case RESAMPLER_QUALITY_LOWEST: @@ -1032,39 +1049,39 @@ static void *resampler_sinc_new(const struct resampler_config *config, goto error; } - sinc_resampler.process = resampler_sinc_process_c; + resampler->process = resampler_sinc_process_c; if (window_type == SINC_WINDOW_KAISER) - sinc_resampler.process = resampler_sinc_process_c_kaiser; + resampler->process = resampler_sinc_process_c_kaiser; if (mask & RESAMPLER_SIMD_AVX && enable_avx) { #if defined(__AVX__) - sinc_resampler.process = resampler_sinc_process_avx; + resampler->process = resampler_sinc_process_avx; if (window_type == SINC_WINDOW_KAISER) - sinc_resampler.process = resampler_sinc_process_avx_kaiser; + resampler->process = resampler_sinc_process_avx_kaiser; #endif } else if (mask & RESAMPLER_SIMD_SSE) { #if defined(__SSE__) - sinc_resampler.process = resampler_sinc_process_sse; + resampler->process = resampler_sinc_process_sse; if (window_type == SINC_WINDOW_KAISER) - sinc_resampler.process = resampler_sinc_process_sse_kaiser; + resampler->process = resampler_sinc_process_sse_kaiser; #endif } else if (mask & RESAMPLER_SIMD_NEON) { #if (defined(__ARM_NEON__) || defined(HAVE_NEON)) - sinc_resampler.process = resampler_sinc_process_neon; + resampler->process = resampler_sinc_process_neon; if (window_type == SINC_WINDOW_KAISER) - sinc_resampler.process = resampler_sinc_process_neon_kaiser; + resampler->process = resampler_sinc_process_neon_kaiser; #endif } return re; error: - resampler_sinc_free(re); + resampler_sinc_free(resampler, re); return NULL; } diff --git a/ThirdParty/RetroArch/libretro-common/include/audio/audio_resampler.h b/ThirdParty/RetroArch/libretro-common/include/audio/audio_resampler.h index 605b6512f..9d1872509 100644 --- a/ThirdParty/RetroArch/libretro-common/include/audio/audio_resampler.h +++ b/ThirdParty/RetroArch/libretro-common/include/audio/audio_resampler.h @@ -115,21 +115,31 @@ struct resampler_config resampler_config_free_t free; }; +/* NEW: Init takes a pointer to a pointer to a retro_resampler struct, and + * fills it out with an altered version of the static structure. This is so + * other threads don't clobber the process pointer in each other's instances + * when selecting different resampler modes. + * + * Only the init function needs it on input, and the free function cleans up + * after it. The process and latency functions shouldn't need it. */ + +typedef struct retro_resampler retro_resampler_t; + /* Bandwidth factor. Will be < 1.0 for downsampling, > 1.0 for upsampling. * Corresponds to expected resampling ratio. */ typedef void *(*resampler_init_t)(const struct resampler_config *config, - double bandwidth_mod, enum resampler_quality quality, - size_t channels, resampler_simd_mask_t mask); + const retro_resampler_t **resampler, double bandwidth_mod, + enum resampler_quality quality, size_t channels, resampler_simd_mask_t mask); -/* Frees the handle. */ -typedef void (*resampler_free_t)(void *data); +/* Frees the handle, and if duped by above, the resampler */ +typedef void (*resampler_free_t)(const retro_resampler_t *resampler, void *data); /* Processes input data. */ typedef void (*resampler_process_t)(void *_data, struct resampler_data *data); typedef size_t (*resampler_latency_t)(void *_data); -typedef struct retro_resampler +struct retro_resampler { resampler_init_t init; resampler_process_t process; @@ -145,7 +155,7 @@ typedef struct retro_resampler /* Computer-friendly short version of ident. * Lower case, no spaces and special characters, etc. */ const char *short_ident; -} retro_resampler_t; +}; typedef struct audio_frame_float {