From 4afc100924ee72572e808c4a77fe185fabddf962 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 19 May 2015 21:18:07 +0200 Subject: [PATCH] Move audio_data out of global struct to prevent threading issues --- Makefile.common | 1 - audio/audio_driver.c | 430 ++++++++++++++++++++++++++++++++++++------ audio/audio_driver.h | 24 +++ audio/audio_monitor.c | 57 ------ audio/drivers/pulse.c | 4 +- command_event.c | 13 +- configuration.c | 5 +- driver.c | 7 +- griffin/griffin.c | 1 - libretro_version_1.c | 203 +------------------- runloop.c | 28 +-- runloop.h | 30 --- settings.c | 4 +- 13 files changed, 417 insertions(+), 390 deletions(-) delete mode 100644 audio/audio_monitor.c diff --git a/Makefile.common b/Makefile.common index 7698913e11..44c0fa795f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -111,7 +111,6 @@ OBJ += frontend/frontend.o \ file_path_special.o \ hash.o \ audio/audio_driver.o \ - audio/audio_monitor.o \ input/input_driver.o \ input/input_hid_driver.o \ gfx/video_driver.o \ diff --git a/audio/audio_driver.c b/audio/audio_driver.c index ae290140ad..2a634440f2 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -17,12 +17,47 @@ #include #include #include "audio_driver.h" +#include "audio_monitor.h" #include "audio_utils.h" #include "audio_thread_wrapper.h" #include "../driver.h" #include "../general.h" #include "../retroarch.h" #include "../runloop.h" +#include "../performance.h" +#include "../intl/intl.h" + +typedef struct audio_driver_input_data +{ + float *data; + + size_t data_ptr; + size_t chunk_size; + size_t nonblock_chunk_size; + size_t block_chunk_size; + + double src_ratio; + float in_rate; + + bool use_float; + + float *outsamples; + int16_t *conv_outsamples; + + int16_t *rewind_buf; + size_t rewind_ptr; + size_t rewind_size; + + rarch_dsp_filter_t *dsp; + + bool rate_control; + double orig_src_ratio; + size_t driver_buffer_size; + + float volume_gain; +} audio_driver_input_data_t; + +static audio_driver_input_data_t audio_data; static const audio_driver_t *audio_drivers[] = { #ifdef HAVE_ALSA @@ -107,7 +142,6 @@ static void compute_audio_buffer_statistics(void) unsigned low_water_count = 0, high_water_count = 0; unsigned samples = 0; runloop_t *runloop = rarch_main_get_ptr(); - global_t *global = global_get_ptr(); samples = min(runloop->measure_data.buffer_free_samples_count, AUDIO_BUFFER_FREE_SAMPLES_COUNT); @@ -127,11 +161,11 @@ static void compute_audio_buffer_statistics(void) } stddev = (unsigned)sqrt((double)accum_var / (samples - 2)); - avg_filled = 1.0f - (float)avg / global->audio_data.driver_buffer_size; - deviation = (float)stddev / global->audio_data.driver_buffer_size; + avg_filled = 1.0f - (float)avg / audio_data.driver_buffer_size; + deviation = (float)stddev / audio_data.driver_buffer_size; - low_water_size = global->audio_data.driver_buffer_size * 3 / 4; - high_water_size = global->audio_data.driver_buffer_size / 4; + low_water_size = audio_data.driver_buffer_size * 3 / 4; + high_water_size = audio_data.driver_buffer_size / 4; for (i = 1; i < samples; i++) { @@ -251,18 +285,17 @@ void find_audio_driver(void) void uninit_audio(void) { driver_t *driver = driver_get_ptr(); - global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); if (driver->audio_data && driver->audio) driver->audio->free(driver->audio_data); - free(global->audio_data.conv_outsamples); - global->audio_data.conv_outsamples = NULL; - global->audio_data.data_ptr = 0; + free(audio_data.conv_outsamples); + audio_data.conv_outsamples = NULL; + audio_data.data_ptr = 0; - free(global->audio_data.rewind_buf); - global->audio_data.rewind_buf = NULL; + free(audio_data.rewind_buf); + audio_data.rewind_buf = NULL; if (!settings->audio.enable) { @@ -273,11 +306,11 @@ void uninit_audio(void) rarch_resampler_freep(&driver->resampler, &driver->resampler_data); - free(global->audio_data.data); - global->audio_data.data = NULL; + free(audio_data.data); + audio_data.data = NULL; - free(global->audio_data.outsamples); - global->audio_data.outsamples = NULL; + free(audio_data.outsamples); + audio_data.outsamples = NULL; event_command(EVENT_CMD_DSP_FILTER_DEINIT); @@ -303,25 +336,25 @@ void init_audio(void) settings->slowmotion_ratio; /* Used for recording even if audio isn't enabled. */ - rarch_assert(global->audio_data.conv_outsamples = + rarch_assert(audio_data.conv_outsamples = (int16_t*)malloc(outsamples_max * sizeof(int16_t))); - if (!global->audio_data.conv_outsamples) + if (!audio_data.conv_outsamples) goto error; - global->audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; - global->audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; - global->audio_data.chunk_size = global->audio_data.block_chunk_size; + audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; + audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; + audio_data.chunk_size = audio_data.block_chunk_size; /* Needs to be able to hold full content of a full max_bufsamples * in addition to its own. */ - rarch_assert(global->audio_data.rewind_buf = (int16_t*) + rarch_assert(audio_data.rewind_buf = (int16_t*) malloc(max_bufsamples * sizeof(int16_t))); - if (!global->audio_data.rewind_buf) + if (!audio_data.rewind_buf) goto error; - global->audio_data.rewind_size = max_bufsamples; + audio_data.rewind_size = max_bufsamples; if (!settings->audio.enable) { @@ -357,55 +390,53 @@ void init_audio(void) driver->audio_active = false; } - global->audio_data.use_float = false; + audio_data.use_float = false; if (driver->audio_active && driver->audio->use_float(driver->audio_data)) - global->audio_data.use_float = true; + audio_data.use_float = true; if (!settings->audio.sync && driver->audio_active) { event_command(EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE); - global->audio_data.chunk_size = - global->audio_data.nonblock_chunk_size; + audio_data.chunk_size = audio_data.nonblock_chunk_size; } - if (global->audio_data.in_rate <= 0.0f) + if (audio_data.in_rate <= 0.0f) { /* Should never happen. */ RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", - global->audio_data.in_rate, settings->audio.out_rate); - global->audio_data.in_rate = settings->audio.out_rate; + audio_data.in_rate, settings->audio.out_rate); + audio_data.in_rate = settings->audio.out_rate; } - global->audio_data.orig_src_ratio = - global->audio_data.src_ratio = - (double)settings->audio.out_rate / global->audio_data.in_rate; + audio_data.orig_src_ratio = audio_data.src_ratio = + (double)settings->audio.out_rate / audio_data.in_rate; if (!rarch_resampler_realloc(&driver->resampler_data, &driver->resampler, - settings->audio.resampler, global->audio_data.orig_src_ratio)) + settings->audio.resampler, audio_data.orig_src_ratio)) { RARCH_ERR("Failed to initialize resampler \"%s\".\n", settings->audio.resampler); driver->audio_active = false; } - rarch_assert(global->audio_data.data = (float*) + rarch_assert(audio_data.data = (float*) malloc(max_bufsamples * sizeof(float))); - if (!global->audio_data.data) + if (!audio_data.data) goto error; - global->audio_data.data_ptr = 0; + audio_data.data_ptr = 0; rarch_assert(settings->audio.out_rate < - global->audio_data.in_rate * AUDIO_MAX_RATIO); - rarch_assert(global->audio_data.outsamples = (float*) + audio_data.in_rate * AUDIO_MAX_RATIO); + rarch_assert(audio_data.outsamples = (float*) malloc(outsamples_max * sizeof(float))); - if (!global->audio_data.outsamples) + if (!audio_data.outsamples) goto error; - global->audio_data.rate_control = false; + audio_data.rate_control = false; if (!global->system.audio_callback.callback && driver->audio_active && settings->audio.rate_control) { @@ -413,9 +444,9 @@ void init_audio(void) * and buffer_size to be implemented. */ if (driver->audio->buffer_size) { - global->audio_data.driver_buffer_size = + audio_data.driver_buffer_size = driver->audio->buffer_size(driver->audio_data); - global->audio_data.rate_control = true; + audio_data.rate_control = true; } else RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); @@ -435,18 +466,18 @@ void init_audio(void) return; error: - if (global->audio_data.conv_outsamples) - free(global->audio_data.conv_outsamples); - global->audio_data.conv_outsamples = NULL; - if (global->audio_data.data) - free(global->audio_data.data); - global->audio_data.data = NULL; - if (global->audio_data.rewind_buf) - free(global->audio_data.rewind_buf); - global->audio_data.rewind_buf = NULL; - if (global->audio_data.outsamples) - free(global->audio_data.outsamples); - global->audio_data.outsamples = NULL; + if (audio_data.conv_outsamples) + free(audio_data.conv_outsamples); + audio_data.conv_outsamples = NULL; + if (audio_data.data) + free(audio_data.data); + audio_data.data = NULL; + if (audio_data.rewind_buf) + free(audio_data.rewind_buf); + audio_data.rewind_buf = NULL; + if (audio_data.outsamples) + free(audio_data.outsamples); + audio_data.outsamples = NULL; } bool audio_driver_mute_toggle(void) @@ -486,11 +517,10 @@ static int audio_driver_write_avail(void) void audio_driver_readjust_input_rate(void) { runloop_t *runloop = rarch_main_get_ptr(); - global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); unsigned write_idx = runloop->measure_data.buffer_free_samples_count++ & (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1); - int half_size = global->audio_data.driver_buffer_size / 2; + int half_size = audio_data.driver_buffer_size / 2; int avail = audio_driver_write_avail(); int delta_mid = avail - half_size; double direction = (double)delta_mid / half_size; @@ -498,15 +528,15 @@ void audio_driver_readjust_input_rate(void) #if 0 RARCH_LOG_OUTPUT("Audio buffer is %u%% full\n", - (unsigned)(100 - (avail * 100) / global->audio_data.driver_buffer_size)); + (unsigned)(100 - (avail * 100) / audio_data.driver_buffer_size)); #endif runloop->measure_data.buffer_free_samples[write_idx] = avail; - global->audio_data.src_ratio = global->audio_data.orig_src_ratio * adjust; + audio_data.src_ratio = audio_data.orig_src_ratio * adjust; #if 0 RARCH_LOG_OUTPUT("New rate: %lf, Orig rate: %lf\n", - global->audio_data.src_ratio, global->audio_data.orig_src_ratio); + audio_data.src_ratio, audio_data.orig_src_ratio); #endif } @@ -543,6 +573,17 @@ void audio_driver_set_nonblock_state(bool toggle) audio->set_nonblock_state(driver->audio_data, toggle); } +void audio_driver_set_nonblocking_state(bool enable) +{ + driver_t *driver = driver_get_ptr(); + settings_t *settings = config_get_ptr(); + if (driver->audio_active && driver->audio_data) + audio_driver_set_nonblock_state(settings->audio.sync ? enable : true); + + audio_data.chunk_size = enable ? audio_data.nonblock_chunk_size : + audio_data.block_chunk_size; +} + ssize_t audio_driver_write(const void *buf, size_t size) { driver_t *driver = driver_get_ptr(); @@ -550,3 +591,272 @@ ssize_t audio_driver_write(const void *buf, size_t size) return audio->write(driver->audio_data, buf, size); } + +/** + * audio_driver_flush: + * @data : pointer to audio buffer. + * @right : amount of samples to write. + * + * Writes audio samples to audio driver. Will first + * perform DSP processing (if enabled) and resampling. + * + * Returns: true (1) if audio samples were written to the audio + * driver, false (0) in case of an error. + **/ +bool audio_driver_flush(const int16_t *data, size_t samples) +{ + const void *output_data = NULL; + unsigned output_frames = 0; + size_t output_size = sizeof(float); + struct resampler_data src_data = {0}; + struct rarch_dsp_data dsp_data = {0}; + runloop_t *runloop = rarch_main_get_ptr(); + driver_t *driver = driver_get_ptr(); + global_t *global = global_get_ptr(); + settings_t *settings = config_get_ptr(); + + if (driver->recording_data) + { + struct ffemu_audio_data ffemu_data = {0}; + ffemu_data.data = data; + ffemu_data.frames = samples / 2; + + if (driver->recording && driver->recording->push_audio) + driver->recording->push_audio(driver->recording_data, &ffemu_data); + } + + if (runloop->is_paused || settings->audio.mute_enable) + return true; + if (!driver->audio_active || !audio_data.data) + return false; + + RARCH_PERFORMANCE_INIT(audio_convert_s16); + RARCH_PERFORMANCE_START(audio_convert_s16); + audio_convert_s16_to_float(audio_data.data, data, samples, + audio_data.volume_gain); + RARCH_PERFORMANCE_STOP(audio_convert_s16); + + src_data.data_in = audio_data.data; + src_data.input_frames = samples >> 1; + + dsp_data.input = audio_data.data; + dsp_data.input_frames = samples >> 1; + + if (audio_data.dsp) + { + RARCH_PERFORMANCE_INIT(audio_dsp); + RARCH_PERFORMANCE_START(audio_dsp); + rarch_dsp_filter_process(audio_data.dsp, &dsp_data); + RARCH_PERFORMANCE_STOP(audio_dsp); + + if (dsp_data.output) + { + src_data.data_in = dsp_data.output; + src_data.input_frames = dsp_data.output_frames; + } + } + + src_data.data_out = audio_data.outsamples; + + if (audio_data.rate_control) + audio_driver_readjust_input_rate(); + + src_data.ratio = audio_data.src_ratio; + if (runloop->is_slowmotion) + src_data.ratio *= settings->slowmotion_ratio; + + RARCH_PERFORMANCE_INIT(resampler_proc); + RARCH_PERFORMANCE_START(resampler_proc); + rarch_resampler_process(driver->resampler, + driver->resampler_data, &src_data); + RARCH_PERFORMANCE_STOP(resampler_proc); + + output_data = audio_data.outsamples; + output_frames = src_data.output_frames; + + if (!audio_data.use_float) + { + RARCH_PERFORMANCE_INIT(audio_convert_float); + RARCH_PERFORMANCE_START(audio_convert_float); + audio_convert_float_to_s16(audio_data.conv_outsamples, + (const float*)output_data, output_frames * 2); + RARCH_PERFORMANCE_STOP(audio_convert_float); + + output_data = audio_data.conv_outsamples; + output_size = sizeof(int16_t); + } + + if (audio_driver_write(output_data, output_frames * output_size * 2) < 0) + { + RARCH_ERR(RETRO_LOG_AUDIO_WRITE_FAILED); + + driver->audio_active = false; + return false; + } + + return true; +} + +/** + * audio_driver_sample: + * @left : value of the left audio channel. + * @right : value of the right audio channel. + * + * Audio sample render callback function. + **/ +void audio_driver_sample(int16_t left, int16_t right) +{ + audio_data.conv_outsamples[audio_data.data_ptr++] = left; + audio_data.conv_outsamples[audio_data.data_ptr++] = right; + + if (audio_data.data_ptr < audio_data.chunk_size) + return; + + audio_driver_flush(audio_data.conv_outsamples, audio_data.data_ptr); + + audio_data.data_ptr = 0; +} + +/** + * audio_driver_sample_batch: + * @data : pointer to audio buffer. + * @frames : amount of audio frames to push. + * + * Batched audio sample render callback function. + * + * Returns: amount of frames sampled. Will be equal to @frames + * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2). + **/ +size_t audio_driver_sample_batch(const int16_t *data, size_t frames) +{ + if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1)) + frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1; + + audio_driver_flush(data, frames << 1); + + return frames; +} + +/** + * audio_driver_sample_rewind: + * @left : value of the left audio channel. + * @right : value of the right audio channel. + * + * Audio sample render callback function (rewind version). This callback + * function will be used instead of audio_driver_sample when rewinding is activated. + **/ +void audio_driver_sample_rewind(int16_t left, int16_t right) +{ + audio_data.rewind_buf[--audio_data.rewind_ptr] = right; + audio_data.rewind_buf[--audio_data.rewind_ptr] = left; +} + +/** + * audio_driver_sample_batch_rewind: + * @data : pointer to audio buffer. + * @frames : amount of audio frames to push. + * + * Batched audio sample render callback function (rewind version). This callback + * function will be used instead of audio_driver_sample_batch when rewinding is activated. + * + * Returns: amount of frames sampled. Will be equal to @frames + * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2). + **/ +size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames) +{ + size_t i; + size_t samples = frames << 1; + + for (i = 0; i < samples; i++) + audio_data.rewind_buf[--audio_data.rewind_ptr] = data[i]; + + return frames; +} + +void audio_driver_set_volume_gain(float gain) +{ + audio_data.volume_gain = gain; +} + +void audio_driver_dsp_filter_free(void) +{ + if (audio_data.dsp) + rarch_dsp_filter_free(audio_data.dsp); + audio_data.dsp = NULL; +} + +void audio_driver_dsp_filter_init(const char *device) +{ + audio_data.dsp = rarch_dsp_filter_new(device, audio_data.in_rate); + if (!audio_data.dsp) + RARCH_ERR("[DSP]: Failed to initialize DSP filter \"%s\".\n", device); +} + +void audio_driver_setup_rewind(void) +{ + unsigned i; + + /* Push audio ready to be played. */ + audio_data.rewind_ptr = audio_data.rewind_size; + + for (i = 0; i < audio_data.data_ptr; i += 2) + { + audio_data.rewind_buf[--audio_data.rewind_ptr] = + audio_data.conv_outsamples[i + 1]; + + audio_data.rewind_buf[--audio_data.rewind_ptr] = + audio_data.conv_outsamples[i + 0]; + } + + audio_data.data_ptr = 0; +} + +void audio_driver_frame_is_reverse(void) +{ + /* We just rewound. Flush rewind audio buffer. */ + audio_driver_flush(audio_data.rewind_buf + audio_data.rewind_ptr, + audio_data.rewind_size - audio_data.rewind_ptr); +} + +void audio_monitor_adjust_system_rates(void) +{ + float timing_skew; + global_t *global = global_get_ptr(); + const struct retro_system_timing *info = + (const struct retro_system_timing*)&global->system.av_info.timing; + settings_t *settings = config_get_ptr(); + + if (info->sample_rate <= 0.0) + return; + + timing_skew = fabs(1.0f - info->fps / + settings->video.refresh_rate); + audio_data.in_rate = info->sample_rate; + + if (timing_skew <= settings->audio.max_timing_skew) + audio_data.in_rate *= (settings->video.refresh_rate / info->fps); + + RARCH_LOG("Set audio input rate to: %.2f Hz.\n", + audio_data.in_rate); +} + +/** + * audio_monitor_set_refresh_rate: + * + * Sets audio monitor refresh rate to new value. + **/ +void audio_monitor_set_refresh_rate(void) +{ + settings_t *settings = config_get_ptr(); + + double new_src_ratio = (double)settings->audio.out_rate / + audio_data.in_rate; + + audio_data.orig_src_ratio = new_src_ratio; + audio_data.src_ratio = new_src_ratio; +} + +void audio_driver_set_buffer_size(size_t bufsize) +{ + audio_data.driver_buffer_size = bufsize; +} diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 0d2365bf47..9aacc77f26 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -128,6 +128,8 @@ bool audio_driver_stop(void); void audio_driver_set_nonblock_state(bool toggle); +void audio_driver_set_nonblocking_state(bool enable); + /** * config_get_audio_driver_options: * @@ -145,6 +147,28 @@ void init_audio(void); ssize_t audio_driver_write(const void *buf, size_t size); +bool audio_driver_flush(const int16_t *data, size_t samples); + +void audio_driver_sample(int16_t left, int16_t right); + +size_t audio_driver_sample_batch(const int16_t *data, size_t frames); + +void audio_driver_sample_rewind(int16_t left, int16_t right); + +size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames); + +void audio_driver_set_volume_gain(float gain); + +void audio_driver_dsp_filter_free(void); + +void audio_driver_dsp_filter_init(const char *device); + +void audio_driver_setup_rewind(void); + +void audio_driver_frame_is_reverse(void); + +void audio_driver_set_buffer_size(size_t bufsize); + #ifdef __cplusplus } #endif diff --git a/audio/audio_monitor.c b/audio/audio_monitor.c deleted file mode 100644 index cadaf02112..0000000000 --- a/audio/audio_monitor.c +++ /dev/null @@ -1,57 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2015 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include "audio_monitor.h" -#include "../general.h" - -void audio_monitor_adjust_system_rates(void) -{ - float timing_skew; - global_t *global = global_get_ptr(); - const struct retro_system_timing *info = - (const struct retro_system_timing*)&global->system.av_info.timing; - settings_t *settings = config_get_ptr(); - - if (info->sample_rate <= 0.0) - return; - - timing_skew = fabs(1.0f - info->fps / - settings->video.refresh_rate); - global->audio_data.in_rate = info->sample_rate; - - if (timing_skew <= settings->audio.max_timing_skew) - global->audio_data.in_rate *= (settings->video.refresh_rate / info->fps); - - RARCH_LOG("Set audio input rate to: %.2f Hz.\n", - global->audio_data.in_rate); -} - -/** - * audio_monitor_set_refresh_rate: - * - * Sets audio monitor refresh rate to new value. - **/ -void audio_monitor_set_refresh_rate(void) -{ - settings_t *settings = config_get_ptr(); - global_t *global = global_get_ptr(); - - double new_src_ratio = (double)settings->audio.out_rate / - global->audio_data.in_rate; - - global->audio_data.orig_src_ratio = new_src_ratio; - global->audio_data.src_ratio = new_src_ratio; -} diff --git a/audio/drivers/pulse.c b/audio/drivers/pulse.c index 83095e3cd5..e2c4b0215a 100644 --- a/audio/drivers/pulse.c +++ b/audio/drivers/pulse.c @@ -316,11 +316,11 @@ static size_t pulse_write_avail(void *data) { size_t length; pa_t *pa = (pa_t*)data; - global_t *global = global_get_ptr(); pa_threaded_mainloop_lock(pa->mainloop); length = pa_stream_writable_size(pa->stream); - global->audio_data.driver_buffer_size = pa->buffer_size; /* Can change spuriously. */ + + audio_driver_set_buffer_size(pa->buffer_size); /* Can change spuriously. */ pa_threaded_mainloop_unlock(pa->mainloop); return length; } diff --git a/command_event.c b/command_event.c index 1f09407239..2f96201f87 100644 --- a/command_event.c +++ b/command_event.c @@ -419,7 +419,7 @@ static void event_set_volume(float gain) rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); - global->audio_data.volume_gain = db_to_gain(settings->audio.volume); + audio_driver_set_volume_gain(db_to_gain(settings->audio.volume)); } /** @@ -1223,20 +1223,13 @@ bool event_command(enum event_command cmd) if (!global) break; - if (global->audio_data.dsp) - rarch_dsp_filter_free(global->audio_data.dsp); - global->audio_data.dsp = NULL; + audio_driver_dsp_filter_free(); break; case EVENT_CMD_DSP_FILTER_INIT: event_command(EVENT_CMD_DSP_FILTER_DEINIT); if (!*settings->audio.dsp_plugin) break; - - global->audio_data.dsp = rarch_dsp_filter_new( - settings->audio.dsp_plugin, global->audio_data.in_rate); - if (!global->audio_data.dsp) - RARCH_ERR("[DSP]: Failed to initialize DSP filter \"%s\".\n", - settings->audio.dsp_plugin); + audio_driver_dsp_filter_init(settings->audio.dsp_plugin); break; case EVENT_CMD_GPU_RECORD_DEINIT: if (!global) diff --git a/configuration.c b/configuration.c index 511947a1e1..92ebbf5ea1 100644 --- a/configuration.c +++ b/configuration.c @@ -519,7 +519,8 @@ static void config_set_defaults(void) settings->audio.rate_control_delta = rate_control_delta; settings->audio.max_timing_skew = max_timing_skew; settings->audio.volume = audio_volume; - global->audio_data.volume_gain = db_to_gain(settings->audio.volume); + + audio_driver_set_volume_gain(db_to_gain(settings->audio.volume)); settings->rewind_enable = rewind_enable; settings->rewind_buffer_size = rewind_buffer_size; @@ -1378,7 +1379,7 @@ static bool config_load_file(const char *path, bool set_defaults) CONFIG_GET_FLOAT_BASE(conf, settings, audio.max_timing_skew, "audio_max_timing_skew"); CONFIG_GET_FLOAT_BASE(conf, settings, audio.volume, "audio_volume"); CONFIG_GET_STRING_BASE(conf, settings, audio.resampler, "audio_resampler"); - global->audio_data.volume_gain = db_to_gain(settings->audio.volume); + audio_driver_set_volume_gain(db_to_gain(settings->audio.volume)); CONFIG_GET_STRING_BASE(conf, settings, camera.device, "camera_device"); CONFIG_GET_BOOL_BASE(conf, settings, camera.allow, "camera_allow"); diff --git a/driver.c b/driver.c index 7f6e8e2a3c..f85fb5e9b5 100644 --- a/driver.c +++ b/driver.c @@ -295,12 +295,7 @@ void driver_set_nonblock_state(bool enable) video_driver_set_nonblock_state(video_nonblock); } - if (driver->audio_active && driver->audio_data) - audio_driver_set_nonblock_state(settings->audio.sync ? enable : true); - - global->audio_data.chunk_size = enable ? - global->audio_data.nonblock_chunk_size : - global->audio_data.block_chunk_size; + audio_driver_set_nonblocking_state(enable); } /** diff --git a/griffin/griffin.c b/griffin/griffin.c index 92662852b0..495f63c3a7 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -506,7 +506,6 @@ DRIVERS #include "../gfx/video_viewport.c" #include "../input/input_driver.c" #include "../audio/audio_driver.c" -#include "../audio/audio_monitor.c" #include "../camera/camera_driver.c" #include "../location/location_driver.c" #include "../menu/menu_driver.c" diff --git a/libretro_version_1.c b/libretro_version_1.c index 31da19a18b..f68ad6ef92 100644 --- a/libretro_version_1.c +++ b/libretro_version_1.c @@ -32,6 +32,7 @@ #include "performance.h" #include "input/keyboard_line.h" #include "input/input_remapping.h" +#include "audio/audio_driver.h" #include "audio/audio_utils.h" #include "retroarch_logger.h" #include "record/record_driver.h" @@ -166,192 +167,6 @@ static void video_frame(const void *data, unsigned width, driver->video_active = false; } -/** - * retro_flush_audio: - * @data : pointer to audio buffer. - * @right : amount of samples to write. - * - * Writes audio samples to audio driver. Will first - * perform DSP processing (if enabled) and resampling. - * - * Returns: true (1) if audio samples were written to the audio - * driver, false (0) in case of an error. - **/ -bool retro_flush_audio(const int16_t *data, size_t samples) -{ - const void *output_data = NULL; - unsigned output_frames = 0; - size_t output_size = sizeof(float); - struct resampler_data src_data = {0}; - struct rarch_dsp_data dsp_data = {0}; - runloop_t *runloop = rarch_main_get_ptr(); - driver_t *driver = driver_get_ptr(); - global_t *global = global_get_ptr(); - settings_t *settings = config_get_ptr(); - - if (driver->recording_data) - { - struct ffemu_audio_data ffemu_data = {0}; - ffemu_data.data = data; - ffemu_data.frames = samples / 2; - - if (driver->recording && driver->recording->push_audio) - driver->recording->push_audio(driver->recording_data, &ffemu_data); - } - - if (runloop->is_paused || settings->audio.mute_enable) - return true; - if (!driver->audio_active || !global->audio_data.data) - return false; - - RARCH_PERFORMANCE_INIT(audio_convert_s16); - RARCH_PERFORMANCE_START(audio_convert_s16); - audio_convert_s16_to_float(global->audio_data.data, data, samples, - global->audio_data.volume_gain); - RARCH_PERFORMANCE_STOP(audio_convert_s16); - - src_data.data_in = global->audio_data.data; - src_data.input_frames = samples >> 1; - - dsp_data.input = global->audio_data.data; - dsp_data.input_frames = samples >> 1; - - if (global->audio_data.dsp) - { - RARCH_PERFORMANCE_INIT(audio_dsp); - RARCH_PERFORMANCE_START(audio_dsp); - rarch_dsp_filter_process(global->audio_data.dsp, &dsp_data); - RARCH_PERFORMANCE_STOP(audio_dsp); - - if (dsp_data.output) - { - src_data.data_in = dsp_data.output; - src_data.input_frames = dsp_data.output_frames; - } - } - - src_data.data_out = global->audio_data.outsamples; - - if (global->audio_data.rate_control) - audio_driver_readjust_input_rate(); - - src_data.ratio = global->audio_data.src_ratio; - if (runloop->is_slowmotion) - src_data.ratio *= settings->slowmotion_ratio; - - RARCH_PERFORMANCE_INIT(resampler_proc); - RARCH_PERFORMANCE_START(resampler_proc); - rarch_resampler_process(driver->resampler, - driver->resampler_data, &src_data); - RARCH_PERFORMANCE_STOP(resampler_proc); - - output_data = global->audio_data.outsamples; - output_frames = src_data.output_frames; - - if (!global->audio_data.use_float) - { - RARCH_PERFORMANCE_INIT(audio_convert_float); - RARCH_PERFORMANCE_START(audio_convert_float); - audio_convert_float_to_s16(global->audio_data.conv_outsamples, - (const float*)output_data, output_frames * 2); - RARCH_PERFORMANCE_STOP(audio_convert_float); - - output_data = global->audio_data.conv_outsamples; - output_size = sizeof(int16_t); - } - - if (audio_driver_write(output_data, output_frames * output_size * 2) < 0) - { - RARCH_ERR(RETRO_LOG_AUDIO_WRITE_FAILED); - - driver->audio_active = false; - return false; - } - - return true; -} - -/** - * audio_sample: - * @left : value of the left audio channel. - * @right : value of the right audio channel. - * - * Audio sample render callback function. - **/ -static void audio_sample(int16_t left, int16_t right) -{ - global_t *global = global_get_ptr(); - - global->audio_data.conv_outsamples[global->audio_data.data_ptr++] = left; - global->audio_data.conv_outsamples[global->audio_data.data_ptr++] = right; - - if (global->audio_data.data_ptr < global->audio_data.chunk_size) - return; - - retro_flush_audio(global->audio_data.conv_outsamples, global->audio_data.data_ptr); - - global->audio_data.data_ptr = 0; -} - -/** - * audio_sample_batch: - * @data : pointer to audio buffer. - * @frames : amount of audio frames to push. - * - * Batched audio sample render callback function. - * - * Returns: amount of frames sampled. Will be equal to @frames - * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2). - **/ -static size_t audio_sample_batch(const int16_t *data, size_t frames) -{ - if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1)) - frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1; - - retro_flush_audio(data, frames << 1); - - return frames; -} - -/** - * audio_sample_rewind: - * @left : value of the left audio channel. - * @right : value of the right audio channel. - * - * Audio sample render callback function (rewind version). This callback - * function will be used instead of audio_sample when rewinding is activated. - **/ -static void audio_sample_rewind(int16_t left, int16_t right) -{ - global_t *global = global_get_ptr(); - - global->audio_data.rewind_buf[--global->audio_data.rewind_ptr] = right; - global->audio_data.rewind_buf[--global->audio_data.rewind_ptr] = left; -} - -/** - * audio_sample_batch_rewind: - * @data : pointer to audio buffer. - * @frames : amount of audio frames to push. - * - * Batched audio sample render callback function (rewind version). This callback - * function will be used instead of audio_sample_batch when rewinding is activated. - * - * Returns: amount of frames sampled. Will be equal to @frames - * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2). - **/ -static size_t audio_sample_batch_rewind(const int16_t *data, size_t frames) -{ - size_t i; - size_t samples = frames << 1; - global_t *global = global_get_ptr(); - - for (i = 0; i < samples; i++) - global->audio_data.rewind_buf[--global->audio_data.rewind_ptr] = data[i]; - - return frames; -} - /** * input_apply_turbo: * @port : user number @@ -666,8 +481,8 @@ void retro_set_default_callbacks(void *data) return; cbs->frame_cb = video_frame; - cbs->sample_cb = audio_sample; - cbs->sample_batch_cb = audio_sample_batch; + cbs->sample_cb = audio_driver_sample; + cbs->sample_batch_cb = audio_driver_sample_batch; cbs->state_cb = input_state; cbs->poll_cb = input_poll; } @@ -692,8 +507,8 @@ void retro_init_libretro_cbs(void *data) (void)global; pretro_set_video_refresh(video_frame); - pretro_set_audio_sample(audio_sample); - pretro_set_audio_sample_batch(audio_sample_batch); + pretro_set_audio_sample(audio_driver_sample); + pretro_set_audio_sample_batch(audio_driver_sample_batch); pretro_set_input_state(input_state); pretro_set_input_poll(input_poll); @@ -732,12 +547,12 @@ void retro_set_rewind_callbacks(void) if (global->rewind.frame_is_reverse) { - pretro_set_audio_sample(audio_sample_rewind); - pretro_set_audio_sample_batch(audio_sample_batch_rewind); + pretro_set_audio_sample(audio_driver_sample_rewind); + pretro_set_audio_sample_batch(audio_driver_sample_batch_rewind); } else { - pretro_set_audio_sample(audio_sample); - pretro_set_audio_sample_batch(audio_sample_batch); + pretro_set_audio_sample(audio_driver_sample); + pretro_set_audio_sample_batch(audio_driver_sample_batch); } } diff --git a/runloop.c b/runloop.c index 6637e2440b..b26b06816e 100644 --- a/runloop.c +++ b/runloop.c @@ -141,26 +141,6 @@ static void check_stateslots(bool pressed_increase, bool pressed_decrease) RARCH_LOG("%s\n", msg); } -static INLINE void setup_rewind_audio(void) -{ - unsigned i; - global_t *global = global_get_ptr(); - - /* Push audio ready to be played. */ - global->audio_data.rewind_ptr = global->audio_data.rewind_size; - - for (i = 0; i < global->audio_data.data_ptr; i += 2) - { - global->audio_data.rewind_buf[--global->audio_data.rewind_ptr] = - global->audio_data.conv_outsamples[i + 1]; - - global->audio_data.rewind_buf[--global->audio_data.rewind_ptr] = - global->audio_data.conv_outsamples[i + 0]; - } - - global->audio_data.data_ptr = 0; -} - /** * check_rewind: * @pressed : was rewind key pressed or held? @@ -174,11 +154,7 @@ static void check_rewind(bool pressed) if (global->rewind.frame_is_reverse) { - /* We just rewound. Flush rewind audio buffer. */ - retro_flush_audio(global->audio_data.rewind_buf - + global->audio_data.rewind_ptr, - global->audio_data.rewind_size - global->audio_data.rewind_ptr); - + audio_driver_frame_is_reverse(); global->rewind.frame_is_reverse = false; } @@ -199,7 +175,7 @@ static void check_rewind(bool pressed) if (state_manager_pop(global->rewind.state, &buf)) { global->rewind.frame_is_reverse = true; - setup_rewind_audio(); + audio_driver_setup_rewind(); rarch_main_msg_queue_push(RETRO_MSG_REWINDING, 0, runloop->is_paused ? 1 : 30, true); diff --git a/runloop.h b/runloop.h index 2d74ab2a60..c47e6f75bb 100644 --- a/runloop.h +++ b/runloop.h @@ -205,36 +205,6 @@ typedef struct global unsigned num_ports; } system; - struct - { - float *data; - - size_t data_ptr; - size_t chunk_size; - size_t nonblock_chunk_size; - size_t block_chunk_size; - - double src_ratio; - float in_rate; - - bool use_float; - - float *outsamples; - int16_t *conv_outsamples; - - int16_t *rewind_buf; - size_t rewind_ptr; - size_t rewind_size; - - rarch_dsp_filter_t *dsp; - - bool rate_control; - double orig_src_ratio; - size_t driver_buffer_size; - - float volume_gain; - } audio_data; - struct { unsigned width; diff --git a/settings.c b/settings.c index fff09845df..dad715a227 100644 --- a/settings.c +++ b/settings.c @@ -3016,7 +3016,9 @@ static void general_write_handler(void *data) } } else if (!strcmp(setting->name, "audio_volume")) - global->audio_data.volume_gain = db_to_gain(*setting->value.fraction); + { + audio_driver_set_volume_gain(db_to_gain(*setting->value.fraction)); + } else if (!strcmp(setting->name, "audio_latency")) rarch_cmd = EVENT_CMD_AUDIO_REINIT; else if (!strcmp(setting->name, "audio_rate_control_delta"))