diff --git a/Makefile.common b/Makefile.common
index 8a262bfe53..d5a2c05663 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -306,6 +306,7 @@ OBJ += \
$(LIBRETRO_COMM_DIR)/file/file_path_io.o \
file_path_special.o \
$(LIBRETRO_COMM_DIR)/hash/lrc_hash.o \
+ audio/audio_driver.o \
input/input_driver.o \
input/common/input_hid_common.o \
led/led_driver.o \
diff --git a/audio/audio_driver.c b/audio/audio_driver.c
new file mode 100644
index 0000000000..0ecac81e4b
--- /dev/null
+++ b/audio/audio_driver.c
@@ -0,0 +1,1789 @@
+/**
+ * RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2017 - 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 Foundation, 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
+
+#include "audio_driver.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_AUDIOMIXER
+#include
+#include "../tasks/task_audio_mixer.h"
+#endif
+#ifdef HAVE_DSP_FILTER
+#include
+#endif
+#include
+
+#ifdef HAVE_THREADS
+#include "audio_thread_wrapper.h"
+#endif
+
+#ifdef HAVE_MENU
+#include "../menu/menu_driver.h"
+#endif
+
+#include "../configuration.h"
+#include "../driver.h"
+#include "../frontend/frontend_driver.h"
+#include "../retroarch.h"
+#include "../list_special.h"
+#include "../file_path_special.h"
+#include "../tasks/task_content.h"
+#include "../verbosity.h"
+
+#define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac|wav"
+
+ /* Converts decibels to voltage gain. returns voltage gain value. */
+#define DB_TO_GAIN(db) (powf(10.0f, (db) / 20.0f))
+
+audio_driver_t audio_null = {
+ NULL, /* init */
+ NULL, /* write */
+ NULL, /* stop */
+ NULL, /* start */
+ NULL, /* alive */
+ NULL, /* set_nonblock_state */
+ NULL, /* free */
+ NULL, /* use_float */
+ "null",
+ NULL,
+ NULL,
+ NULL, /* write_avail */
+ NULL
+};
+
+audio_driver_t *audio_drivers[] = {
+#ifdef HAVE_ALSA
+ &audio_alsa,
+#if !defined(__QNX__) && defined(HAVE_THREADS)
+ &audio_alsathread,
+#endif
+#endif
+#ifdef HAVE_TINYALSA
+ &audio_tinyalsa,
+#endif
+#if defined(HAVE_AUDIOIO)
+ &audio_audioio,
+#endif
+#if defined(HAVE_OSS) || defined(HAVE_OSS_BSD)
+ &audio_oss,
+#endif
+#ifdef HAVE_RSOUND
+ &audio_rsound,
+#endif
+#ifdef HAVE_COREAUDIO
+ &audio_coreaudio,
+#endif
+#ifdef HAVE_COREAUDIO3
+ &audio_coreaudio3,
+#endif
+#ifdef HAVE_AL
+ &audio_openal,
+#endif
+#ifdef HAVE_SL
+ &audio_opensl,
+#endif
+#ifdef HAVE_ROAR
+ &audio_roar,
+#endif
+#ifdef HAVE_JACK
+ &audio_jack,
+#endif
+#if defined(HAVE_SDL) || defined(HAVE_SDL2)
+ &audio_sdl,
+#endif
+#ifdef HAVE_XAUDIO
+ &audio_xa,
+#endif
+#ifdef HAVE_DSOUND
+ &audio_dsound,
+#endif
+#ifdef HAVE_WASAPI
+ &audio_wasapi,
+#endif
+#ifdef HAVE_PULSE
+ &audio_pulse,
+#endif
+#if defined(__PSL1GHT__) || defined(__PS3__)
+ &audio_ps3,
+#endif
+#ifdef XENON
+ &audio_xenon360,
+#endif
+#ifdef GEKKO
+ &audio_gx,
+#endif
+#ifdef WIIU
+ &audio_ax,
+#endif
+#ifdef EMSCRIPTEN
+ &audio_rwebaudio,
+#endif
+#if defined(PSP) || defined(VITA) || defined(ORBIS)
+ &audio_psp,
+#endif
+#if defined(PS2)
+ &audio_ps2,
+#endif
+#ifdef _3DS
+ &audio_ctr_csnd,
+ &audio_ctr_dsp,
+#ifdef HAVE_THREADS
+ &audio_ctr_dsp_thread,
+#endif
+#endif
+#ifdef SWITCH
+ &audio_switch,
+ &audio_switch_thread,
+#ifdef HAVE_LIBNX
+ &audio_switch_libnx_audren,
+ &audio_switch_libnx_audren_thread,
+#endif
+#endif
+ &audio_null,
+ NULL,
+};
+
+static audio_driver_state_t audio_driver_st = {0}; /* double alignment */
+
+/**************************************/
+
+audio_driver_state_t *audio_state_get_ptr(void)
+{
+ return &audio_driver_st;
+}
+
+#ifdef HAVE_TRANSLATE
+/* TODO/FIXME - Doesn't currently work. Fix this. */
+bool audio_driver_is_ai_service_speech_running(void)
+{
+#ifdef HAVE_AUDIOMIXER
+ enum audio_mixer_state res = audio_driver_mixer_get_stream_state(10);
+ bool ret = (res == AUDIO_STREAM_STATE_NONE) || (res == AUDIO_STREAM_STATE_STOPPED);
+ if (!ret)
+ return true;
+#endif
+ return false;
+}
+#endif
+
+static enum resampler_quality audio_driver_get_resampler_quality(
+ settings_t *settings)
+{
+ if (settings)
+ return (enum resampler_quality)settings->uints.audio_resampler_quality;
+ return RESAMPLER_QUALITY_DONTCARE;
+}
+
+static bool audio_driver_free_devices_list(void)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if (
+ !audio_st->current_audio
+ || !audio_st->current_audio->device_list_free
+ || !audio_st->context_audio_data)
+ return false;
+ audio_st->current_audio->device_list_free(
+ audio_st->context_audio_data,
+ audio_st->devices_list);
+ audio_st->devices_list = NULL;
+ return true;
+}
+
+#ifdef DEBUG
+static void report_audio_buffer_statistics(void)
+{
+ audio_statistics_t audio_stats;
+ audio_stats.samples = 0;
+ audio_stats.average_buffer_saturation = 0.0f;
+ audio_stats.std_deviation_percentage = 0.0f;
+ audio_stats.close_to_underrun = 0.0f;
+ audio_stats.close_to_blocking = 0.0f;
+
+ if (!audio_compute_buffer_statistics(&audio_stats))
+ return;
+
+ RARCH_LOG("[Audio]: Average audio buffer saturation: %.2f %%,"
+ " standard deviation (percentage points): %.2f %%.\n"
+ "[Audio]: Amount of time spent close to underrun: %.2f %%."
+ " Close to blocking: %.2f %%.\n",
+ audio_stats.average_buffer_saturation,
+ audio_stats.std_deviation_percentage,
+ audio_stats.close_to_underrun,
+ audio_stats.close_to_blocking);
+}
+#endif
+
+static void audio_driver_deinit_resampler(void)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if (audio_st->resampler && audio_st->resampler_data)
+ audio_st->resampler->free(audio_st->resampler_data);
+ audio_st->resampler = NULL;
+ audio_st->resampler_data = NULL;
+ audio_st->resampler_ident[0] = '\0';
+ audio_st->resampler_quality = RESAMPLER_QUALITY_DONTCARE;
+}
+
+
+static bool audio_driver_deinit_internal(bool audio_enable)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if ( audio_st->current_audio
+ && audio_st->current_audio->free)
+ {
+ if (audio_st->context_audio_data)
+ audio_st->current_audio->free(audio_st->context_audio_data);
+ audio_st->context_audio_data = NULL;
+ }
+
+ if (audio_st->output_samples_conv_buf)
+ memalign_free(audio_st->output_samples_conv_buf);
+ audio_st->output_samples_conv_buf = NULL;
+
+ if (audio_st->input_data)
+ memalign_free(audio_st->input_data);
+
+ audio_st->input_data = NULL;
+ audio_st->data_ptr = 0;
+
+#ifdef HAVE_REWIND
+ if (audio_st->rewind_buf)
+ memalign_free(audio_st->rewind_buf);
+ audio_st->rewind_buf = NULL;
+ audio_st->rewind_size = 0;
+#endif
+
+ if (!audio_enable)
+ {
+ audio_st->active = false;
+ return false;
+ }
+
+ audio_driver_deinit_resampler();
+
+ if (audio_st->output_samples_buf)
+ memalign_free(audio_st->output_samples_buf);
+ audio_st->output_samples_buf = NULL;
+
+#ifdef HAVE_DSP_FILTER
+ audio_driver_dsp_filter_free();
+#endif
+#ifdef DEBUG
+ report_audio_buffer_statistics();
+#endif
+
+ return true;
+}
+
+#ifdef HAVE_AUDIOMIXER
+static void audio_driver_mixer_deinit(void)
+{
+ unsigned i;
+
+ audio_driver_st.mixer_active = false;
+
+ for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
+ {
+ audio_driver_mixer_stop_stream(i);
+ audio_driver_mixer_remove_stream(i);
+ }
+
+ audio_mixer_done();
+}
+#endif
+
+bool audio_driver_deinit(void *settings_data)
+{
+ settings_t *settings = (settings_t*)settings_data;
+#ifdef HAVE_AUDIOMIXER
+ audio_driver_mixer_deinit();
+#endif
+ audio_driver_free_devices_list();
+
+ return audio_driver_deinit_internal(
+ settings->bools.audio_enable);
+}
+
+bool audio_driver_find_driver(
+ void *settings_data,
+ const char *prefix,
+ bool verbosity_enabled)
+{
+ settings_t *settings = (settings_t*)settings_data;
+ int i = (int)driver_find_index(
+ "audio_driver",
+ settings->arrays.audio_driver);
+
+ if (i >= 0)
+ audio_driver_st.current_audio = (const audio_driver_t*)
+ audio_drivers[i];
+ else
+ {
+ const audio_driver_t *tmp = NULL;
+ if (verbosity_enabled)
+ {
+ unsigned d;
+ RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
+ settings->arrays.audio_driver);
+ RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
+ for (d = 0; audio_drivers[d]; d++)
+ {
+ if (audio_drivers[d])
+ RARCH_LOG_OUTPUT("\t%s\n", audio_drivers[d]->ident);
+ }
+ RARCH_WARN("Going to default to first %s...\n", prefix);
+ }
+
+ tmp = (const audio_driver_t*)audio_drivers[0];
+
+ if (!tmp)
+ return false;
+ audio_driver_st.current_audio = tmp;
+ }
+
+ return true;
+}
+
+void audio_driver_flush(
+ float slowmotion_ratio,
+ bool audio_fastforward_mute,
+ const int16_t *data, size_t samples,
+ bool is_slowmotion, bool is_fastmotion)
+{
+ struct resampler_data src_data;
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ float audio_volume_gain = (audio_st->mute_enable ||
+ (audio_fastforward_mute && is_fastmotion))
+ ? 0.0f
+ : audio_st->volume_gain;
+
+ src_data.data_out = NULL;
+ src_data.output_frames = 0;
+
+ convert_s16_to_float(audio_st->input_data, data, samples,
+ audio_volume_gain);
+
+ src_data.data_in = audio_st->input_data;
+ src_data.input_frames = samples >> 1;
+
+#ifdef HAVE_DSP_FILTER
+ if (audio_st->dsp)
+ {
+ struct retro_dsp_data dsp_data;
+
+ dsp_data.input = NULL;
+ dsp_data.input_frames = 0;
+ dsp_data.output = NULL;
+ dsp_data.output_frames = 0;
+
+ dsp_data.input = audio_st->input_data;
+ dsp_data.input_frames = (unsigned)(samples >> 1);
+
+ retro_dsp_filter_process(audio_st->dsp, &dsp_data);
+
+ if (dsp_data.output)
+ {
+ src_data.data_in = dsp_data.output;
+ src_data.input_frames = dsp_data.output_frames;
+ }
+ }
+#endif
+
+ src_data.data_out = audio_st->output_samples_buf;
+
+ if (audio_st->control)
+ {
+ /* Readjust the audio input rate. */
+ int half_size = (int)(audio_st->buffer_size / 2);
+
+ int avail =
+ (int)audio_st->current_audio->write_avail(
+ audio_st->context_audio_data);
+ int delta_mid = avail - half_size;
+ double direction = (double)delta_mid / half_size;
+ double adjust = 1.0 +
+ audio_st->rate_control_delta * direction;
+ unsigned write_idx =
+ audio_st->free_samples_count++ &
+ (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
+
+ audio_st->free_samples_buf[write_idx] = avail;
+ audio_st->source_ratio_current =
+ audio_st->source_ratio_original * adjust;
+
+#if 0
+ if (verbosity_is_enabled())
+ {
+ RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n",
+ (unsigned)(100 - (avail * 100) /
+ audio_st->buffer_size));
+ RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
+ audio_st->source_ratio_current,
+ audio_st->source_ratio_original);
+ }
+#endif
+ }
+
+ src_data.ratio = audio_st->source_ratio_current;
+
+ if (is_slowmotion)
+ src_data.ratio *= slowmotion_ratio;
+
+ /* Note: Ideally we would divide by the user-configured
+ * 'fastforward_ratio' when fast forward is enabled,
+ * but in practice this doesn't work:
+ * - 'fastforward_ratio' is only a limit. If the host
+ * cannot push frames fast enough, the actual ratio
+ * will be lower - and crackling will ensue
+ * - Most of the time 'fastforward_ratio' will be
+ * zero (unlimited)
+ * So what we would need to do is measure the time since
+ * the last audio flush operation, and calculate a 'real'
+ * fast-forward ratio - but this doesn't work either.
+ * The measurement is inaccurate and the frame-by-frame
+ * fluctuations are too large, so crackling is unavoidable.
+ * Since it's going to crackle anyway, there's no point
+ * trying to do anything. Just leave the ratio as-is,
+ * and hope for the best... */
+
+ audio_st->resampler->process(
+ audio_st->resampler_data, &src_data);
+
+#ifdef HAVE_AUDIOMIXER
+ if (audio_st->mixer_active)
+ {
+ bool override = true;
+ float mixer_gain = 0.0f;
+ bool audio_driver_mixer_mute_enable = audio_st->mixer_mute_enable;
+
+ if (!audio_driver_mixer_mute_enable)
+ {
+ if (audio_st->mixer_volume_gain == 1.0f)
+ override = false;
+ mixer_gain = audio_st->mixer_volume_gain;
+
+ }
+ audio_mixer_mix(audio_st->output_samples_buf,
+ src_data.output_frames, mixer_gain, override);
+ }
+#endif
+
+ {
+ const void *output_data = audio_st->output_samples_buf;
+ unsigned output_frames = (unsigned)src_data.output_frames;
+
+ if (audio_st->use_float)
+ output_frames *= sizeof(float);
+ else
+ {
+ convert_float_to_s16(audio_st->output_samples_conv_buf,
+ (const float*)output_data, output_frames * 2);
+
+ output_data = audio_st->output_samples_conv_buf;
+ output_frames *= sizeof(int16_t);
+ }
+
+ audio_st->current_audio->write(audio_st->context_audio_data,
+ output_data, output_frames * 2);
+ }
+}
+
+#ifdef HAVE_AUDIOMIXER
+audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i)
+{
+ if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
+ return NULL;
+ return &audio_driver_st.mixer_streams[i];
+}
+
+const char *audio_driver_mixer_get_stream_name(unsigned i)
+{
+ if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
+ return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
+ if (!string_is_empty(audio_driver_st.mixer_streams[i].name))
+ return audio_driver_st.mixer_streams[i].name;
+ return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
+}
+
+#endif
+
+bool audio_driver_init_internal(
+ void *settings_data,
+ bool audio_cb_inited)
+{
+ unsigned new_rate = 0;
+ float *samples_buf = NULL;
+ settings_t *settings = (settings_t*)settings_data;
+ size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
+ bool audio_enable = settings->bools.audio_enable;
+ bool audio_sync = settings->bools.audio_sync;
+ bool audio_rate_control = settings->bools.audio_rate_control;
+ float slowmotion_ratio = settings->floats.slowmotion_ratio;
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ unsigned audio_latency = (runloop_st->audio_latency > settings->uints.audio_latency) ?
+ runloop_st->audio_latency : settings->uints.audio_latency;
+#ifdef HAVE_REWIND
+ int16_t *rewind_buf = NULL;
+#endif
+ /* Accomodate rewind since at some point we might have two full buffers. */
+ size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO * slowmotion_ratio;
+ int16_t *conv_buf = (int16_t*)memalign_alloc(64, outsamples_max * sizeof(int16_t));
+ float *audio_buf = (float*)memalign_alloc(64, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
+ bool verbosity_enabled = verbosity_is_enabled();
+
+ convert_s16_to_float_init_simd();
+ convert_float_to_s16_init_simd();
+
+ /* Used for recording even if audio isn't enabled. */
+ retro_assert(conv_buf != NULL);
+ retro_assert(audio_buf != NULL);
+
+ if (!conv_buf || !audio_buf)
+ goto error;
+
+ memset(audio_buf, 0, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
+
+ audio_driver_st.input_data = audio_buf;
+ audio_driver_st.output_samples_conv_buf = conv_buf;
+ audio_driver_st.chunk_block_size = AUDIO_CHUNK_SIZE_BLOCKING;
+ audio_driver_st.chunk_nonblock_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
+ audio_driver_st.chunk_size = audio_driver_st.chunk_block_size;
+
+#ifdef HAVE_REWIND
+ /* Needs to be able to hold full content of a full max_bufsamples
+ * in addition to its own. */
+ rewind_buf = (int16_t*)memalign_alloc(64, max_bufsamples * sizeof(int16_t));
+ retro_assert(rewind_buf != NULL);
+
+ if (!rewind_buf)
+ goto error;
+
+ audio_driver_st.rewind_buf = rewind_buf;
+ audio_driver_st.rewind_size = max_bufsamples;
+#endif
+
+ if (!audio_enable)
+ {
+ audio_driver_st.active = false;
+ return false;
+ }
+
+ if (!(audio_driver_find_driver(settings,
+ "audio driver", verbosity_enabled)))
+ {
+ RARCH_ERR("Failed to initialize audio driver.\n");
+ return false;
+ }
+
+ if (!audio_driver_st.current_audio || !audio_driver_st.current_audio->init)
+ {
+ RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
+ audio_driver_st.active = false;
+ return false;
+ }
+
+#ifdef HAVE_THREADS
+ if (audio_cb_inited)
+ {
+ RARCH_LOG("[Audio]: Starting threaded audio driver ...\n");
+ if (!audio_init_thread(
+ &audio_driver_st.current_audio,
+ &audio_driver_st.context_audio_data,
+ *settings->arrays.audio_device
+ ? settings->arrays.audio_device : NULL,
+ settings->uints.audio_output_sample_rate, &new_rate,
+ audio_latency,
+ settings->uints.audio_block_frames,
+ audio_driver_st.current_audio))
+ {
+ RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
+ return false;
+ }
+ }
+ else
+#endif
+ {
+ audio_driver_st.context_audio_data =
+ audio_driver_st.current_audio->init(*settings->arrays.audio_device ?
+ settings->arrays.audio_device : NULL,
+ settings->uints.audio_output_sample_rate,
+ audio_latency,
+ settings->uints.audio_block_frames,
+ &new_rate);
+ }
+
+ if (new_rate != 0)
+ configuration_set_int(settings, settings->uints.audio_output_sample_rate, new_rate);
+
+ if (!audio_driver_st.context_audio_data)
+ {
+ RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
+ audio_driver_st.active = false;
+ }
+
+ audio_driver_st.use_float = false;
+ if ( audio_driver_st.active
+ && audio_driver_st.current_audio->use_float(
+ audio_driver_st.context_audio_data))
+ audio_driver_st.use_float = true;
+
+ if (!audio_sync && audio_driver_st.active)
+ {
+ if (audio_driver_st.active &&
+ audio_driver_st.context_audio_data)
+ audio_driver_st.current_audio->set_nonblock_state(
+ audio_driver_st.context_audio_data, true);
+
+ audio_driver_st.chunk_size =
+ audio_driver_st.chunk_nonblock_size;
+ }
+
+ if (audio_driver_st.input <= 0.0f)
+ {
+ /* Should never happen. */
+ RARCH_WARN("[Audio]: Input rate is invalid (%.3f Hz)."
+ " Using output rate (%u Hz).\n",
+ audio_driver_st.input, settings->uints.audio_output_sample_rate);
+
+ audio_driver_st.input = settings->uints.audio_output_sample_rate;
+ }
+
+ audio_driver_st.source_ratio_original =
+ audio_driver_st.source_ratio_current =
+ (double)settings->uints.audio_output_sample_rate / audio_driver_st.input;
+
+ if (!string_is_empty(settings->arrays.audio_resampler))
+ strlcpy(audio_driver_st.resampler_ident,
+ settings->arrays.audio_resampler,
+ sizeof(audio_driver_st.resampler_ident));
+ else
+ audio_driver_st.resampler_ident[0] = '\0';
+
+ audio_driver_st.resampler_quality =
+ audio_driver_get_resampler_quality(settings);
+
+ if (!retro_resampler_realloc(
+ &audio_driver_st.resampler_data,
+ &audio_driver_st.resampler,
+ audio_driver_st.resampler_ident,
+ audio_driver_st.resampler_quality,
+ audio_driver_st.source_ratio_original))
+ {
+ RARCH_ERR("Failed to initialize resampler \"%s\".\n",
+ audio_driver_st.resampler_ident);
+ audio_driver_st.active = false;
+ }
+
+ audio_driver_st.data_ptr = 0;
+
+ retro_assert(settings->uints.audio_output_sample_rate <
+ audio_driver_st.input * AUDIO_MAX_RATIO);
+
+ samples_buf = (float*)memalign_alloc(64, outsamples_max * sizeof(float));
+
+ retro_assert(samples_buf != NULL);
+
+ if (!samples_buf)
+ goto error;
+
+ audio_driver_st.output_samples_buf = (float*)samples_buf;
+ audio_driver_st.control = false;
+
+ if (
+ !audio_cb_inited
+ && audio_driver_st.active
+ && audio_rate_control
+ )
+ {
+ /* Audio rate control requires write_avail
+ * and buffer_size to be implemented. */
+ if (audio_driver_st.current_audio->buffer_size)
+ {
+ audio_driver_st.buffer_size =
+ audio_driver_st.current_audio->buffer_size(
+ audio_driver_st.context_audio_data);
+ audio_driver_st.control = true;
+ }
+ else
+ RARCH_WARN("[Audio]: Rate control was desired, but driver does not support needed features.\n");
+ }
+
+ command_event(CMD_EVENT_DSP_FILTER_INIT, NULL);
+
+ audio_driver_st.free_samples_count = 0;
+
+#ifdef HAVE_AUDIOMIXER
+ audio_mixer_init(settings->uints.audio_output_sample_rate);
+#endif
+
+ /* Threaded driver is initially stopped. */
+ if (
+ audio_driver_st.active
+ && audio_cb_inited
+ )
+ audio_driver_start(false);
+
+ return true;
+
+error:
+ return audio_driver_deinit(settings);
+}
+
+void audio_driver_sample(int16_t left, int16_t right)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ recording_state_t *recording_st = NULL;
+ runloop_state_t *runloop_st = NULL;
+ if (audio_st->suspended)
+ return;
+ audio_st->output_samples_conv_buf[audio_st->data_ptr++] = left;
+ audio_st->output_samples_conv_buf[audio_st->data_ptr++] = right;
+
+ if (audio_st->data_ptr < audio_st->chunk_size)
+ return;
+
+ runloop_st = runloop_state_get_ptr();
+ recording_st = recording_state_get_ptr();
+
+ if ( recording_st->data &&
+ recording_st->driver &&
+ recording_st->driver->push_audio)
+ {
+ struct record_audio_data ffemu_data;
+
+ ffemu_data.data = audio_st->output_samples_conv_buf;
+ ffemu_data.frames = audio_st->data_ptr / 2;
+
+ recording_st->driver->push_audio(recording_st->data, &ffemu_data);
+ }
+
+ if (!( runloop_st->paused
+ || !audio_st->active
+ || !audio_st->output_samples_buf))
+ audio_driver_flush(
+ config_get_ptr()->floats.slowmotion_ratio,
+ config_get_ptr()->bools.audio_fastforward_mute,
+ audio_st->output_samples_conv_buf,
+ audio_st->data_ptr,
+ runloop_st->slowmotion,
+ runloop_st->fastmotion);
+
+ audio_st->data_ptr = 0;
+}
+
+size_t audio_driver_sample_batch(const int16_t *data, size_t frames)
+{
+ recording_state_t *record_st = recording_state_get_ptr();
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+ audio_driver_state_t *audio_st = &audio_driver_st;
+
+ if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
+ frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
+ if (audio_st->suspended)
+ return frames;
+
+ if ( record_st->data
+ && record_st->driver
+ && record_st->driver->push_audio)
+ {
+ struct record_audio_data ffemu_data;
+
+ ffemu_data.data = data;
+ ffemu_data.frames = (frames << 1) / 2;
+
+ record_st->driver->push_audio(record_st->data, &ffemu_data);
+ }
+
+ if (!(
+ runloop_st->paused
+ || !audio_st->active
+ || !audio_st->output_samples_buf))
+ audio_driver_flush(
+ config_get_ptr()->floats.slowmotion_ratio,
+ config_get_ptr()->bools.audio_fastforward_mute,
+ data,
+ frames << 1,
+ runloop_st->slowmotion,
+ runloop_st->fastmotion);
+
+ return frames;
+}
+
+#ifdef HAVE_REWIND
+void audio_driver_sample_rewind(int16_t left, int16_t right)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if (audio_st->rewind_ptr == 0)
+ return;
+
+ audio_st->rewind_buf[--audio_st->rewind_ptr] = right;
+ audio_st->rewind_buf[--audio_st->rewind_ptr] = left;
+}
+
+size_t audio_driver_sample_batch_rewind(
+ const int16_t *data, size_t frames)
+{
+ size_t i;
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ size_t samples = frames << 1;
+
+ for (i = 0; i < samples; i++)
+ {
+ if (audio_st->rewind_ptr > 0)
+ audio_st->rewind_buf[--audio_st->rewind_ptr] = data[i];
+ }
+
+ return frames;
+}
+#endif
+
+#ifdef HAVE_DSP_FILTER
+void audio_driver_dsp_filter_free(void)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if (audio_st->dsp)
+ retro_dsp_filter_free(audio_st->dsp);
+ audio_st->dsp = NULL;
+}
+
+bool audio_driver_dsp_filter_init(const char *device)
+{
+ retro_dsp_filter_t *audio_driver_dsp = NULL;
+ struct string_list *plugs = NULL;
+#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
+ char basedir[PATH_MAX_LENGTH];
+ char ext_name[PATH_MAX_LENGTH];
+
+ basedir[0] = ext_name[0] = '\0';
+
+ fill_pathname_basedir(basedir, device, sizeof(basedir));
+
+ if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
+ return false;
+
+ plugs = dir_list_new(basedir, ext_name, false, true, false, false);
+ if (!plugs)
+ return false;
+#endif
+ audio_driver_dsp = retro_dsp_filter_new(
+ device, plugs, audio_driver_st.input);
+ if (!audio_driver_dsp)
+ return false;
+
+ audio_driver_st.dsp = audio_driver_dsp;
+
+ return true;
+}
+#endif
+
+void audio_driver_set_buffer_size(size_t bufsize)
+{
+ audio_driver_st.buffer_size = bufsize;
+}
+
+float audio_driver_monitor_adjust_system_rates(
+ double input_sample_rate,
+ double input_fps,
+ float video_refresh_rate,
+ unsigned video_swap_interval,
+ float audio_max_timing_skew)
+{
+ float inp_sample_rate = input_sample_rate;
+ const float target_video_sync_rate = video_refresh_rate
+ / video_swap_interval;
+ float timing_skew =
+ fabs(1.0f - input_fps / target_video_sync_rate);
+ if (timing_skew <= audio_max_timing_skew)
+ return (inp_sample_rate * target_video_sync_rate / input_fps);
+ return inp_sample_rate;
+}
+
+#ifdef HAVE_REWIND
+void audio_driver_setup_rewind(void)
+{
+ unsigned i;
+ audio_driver_state_t *audio_st = &audio_driver_st;
+
+ /* Push audio ready to be played. */
+ audio_st->rewind_ptr = audio_st->rewind_size;
+
+ for (i = 0; i < audio_st->data_ptr; i += 2)
+ {
+ if (audio_st->rewind_ptr > 0)
+ audio_st->rewind_buf[--audio_st->rewind_ptr] =
+ audio_st->output_samples_conv_buf[i + 1];
+
+ if (audio_st->rewind_ptr > 0)
+ audio_st->rewind_buf[--audio_st->rewind_ptr] =
+ audio_st->output_samples_conv_buf[i + 0];
+ }
+
+ audio_st->data_ptr = 0;
+}
+#endif
+
+bool audio_driver_get_devices_list(void **data)
+{
+ struct string_list**ptr = (struct string_list**)data;
+ if (!ptr)
+ return false;
+ *ptr = audio_driver_st.devices_list;
+ return true;
+}
+
+#ifdef HAVE_AUDIOMIXER
+bool audio_driver_mixer_extension_supported(const char *ext)
+{
+ unsigned i;
+ struct string_list str_list;
+ union string_list_elem_attr attr;
+ bool ret = false;
+
+ attr.i = 0;
+ if (!string_list_initialize(&str_list))
+ return false;
+
+#ifdef HAVE_STB_VORBIS
+ string_list_append(&str_list, "ogg", attr);
+#endif
+#ifdef HAVE_IBXM
+ string_list_append(&str_list, "mod", attr);
+ string_list_append(&str_list, "s3m", attr);
+ string_list_append(&str_list, "xm", attr);
+#endif
+#ifdef HAVE_DR_FLAC
+ string_list_append(&str_list, "flac", attr);
+#endif
+#ifdef HAVE_DR_MP3
+ string_list_append(&str_list, "mp3", attr);
+#endif
+ string_list_append(&str_list, "wav", attr);
+
+ for (i = 0; i < str_list.size; i++)
+ {
+ const char *str_ext = str_list.elems[i].data;
+ if (string_is_equal_noncase(str_ext, ext))
+ {
+ ret = true;
+ break;
+ }
+ }
+
+ string_list_deinitialize(&str_list);
+
+ return ret;
+}
+
+static int audio_mixer_find_index(
+ audio_mixer_sound_t *sound)
+{
+ unsigned i;
+
+ for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
+ {
+ audio_mixer_sound_t *handle = audio_driver_st.mixer_streams[i].handle;
+ if (handle == sound)
+ return i;
+ }
+ return -1;
+}
+
+static void audio_mixer_play_stop_cb(
+ audio_mixer_sound_t *sound, unsigned reason)
+{
+ int idx = audio_mixer_find_index(sound);
+
+ switch (reason)
+ {
+ case AUDIO_MIXER_SOUND_FINISHED:
+ audio_mixer_destroy(sound);
+
+ if (idx >= 0)
+ {
+ unsigned i = (unsigned)idx;
+
+ if (!string_is_empty(audio_driver_st.mixer_streams[i].name))
+ free(audio_driver_st.mixer_streams[i].name);
+
+ audio_driver_st.mixer_streams[i].name = NULL;
+ audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
+ audio_driver_st.mixer_streams[i].volume = 0.0f;
+ audio_driver_st.mixer_streams[i].buf = NULL;
+ audio_driver_st.mixer_streams[i].stop_cb = NULL;
+ audio_driver_st.mixer_streams[i].handle = NULL;
+ audio_driver_st.mixer_streams[i].voice = NULL;
+ }
+ break;
+ case AUDIO_MIXER_SOUND_STOPPED:
+ break;
+ case AUDIO_MIXER_SOUND_REPEATED:
+ break;
+ }
+}
+
+static void audio_mixer_menu_stop_cb(
+ audio_mixer_sound_t *sound, unsigned reason)
+{
+ int idx = audio_mixer_find_index(sound);
+
+ switch (reason)
+ {
+ case AUDIO_MIXER_SOUND_FINISHED:
+ if (idx >= 0)
+ {
+ unsigned i = (unsigned)idx;
+ audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
+ audio_driver_st.mixer_streams[i].volume = 0.0f;
+ }
+ break;
+ case AUDIO_MIXER_SOUND_STOPPED:
+ break;
+ case AUDIO_MIXER_SOUND_REPEATED:
+ break;
+ }
+}
+
+static void audio_mixer_play_stop_sequential_cb(
+ audio_mixer_sound_t *sound, unsigned reason)
+{
+ int idx = audio_mixer_find_index(sound);
+
+ switch (reason)
+ {
+ case AUDIO_MIXER_SOUND_FINISHED:
+ audio_mixer_destroy(sound);
+
+ if (idx >= 0)
+ {
+ unsigned i = (unsigned)idx;
+
+ if (!string_is_empty(audio_driver_st.mixer_streams[i].name))
+ free(audio_driver_st.mixer_streams[i].name);
+
+ if (i < AUDIO_MIXER_MAX_STREAMS)
+ audio_driver_st.mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER;
+ else
+ audio_driver_st.mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_SYSTEM;
+
+ audio_driver_st.mixer_streams[i].name = NULL;
+ audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
+ audio_driver_st.mixer_streams[i].volume = 0.0f;
+ audio_driver_st.mixer_streams[i].buf = NULL;
+ audio_driver_st.mixer_streams[i].stop_cb = NULL;
+ audio_driver_st.mixer_streams[i].handle = NULL;
+ audio_driver_st.mixer_streams[i].voice = NULL;
+
+ i++;
+
+ for (; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
+ {
+ if (audio_driver_st.mixer_streams[i].state
+ == AUDIO_STREAM_STATE_STOPPED)
+ {
+ audio_driver_mixer_play_stream_sequential(i);
+ break;
+ }
+ }
+ }
+ break;
+ case AUDIO_MIXER_SOUND_STOPPED:
+ break;
+ case AUDIO_MIXER_SOUND_REPEATED:
+ break;
+ }
+}
+
+static bool audio_driver_mixer_get_free_stream_slot(
+ unsigned *id, enum audio_mixer_stream_type type)
+{
+ unsigned i = AUDIO_MIXER_MAX_STREAMS;
+ unsigned count = AUDIO_MIXER_MAX_SYSTEM_STREAMS;
+
+ if (type == AUDIO_STREAM_TYPE_USER)
+ {
+ i = 0;
+ count = AUDIO_MIXER_MAX_STREAMS;
+ }
+
+ for (; i < count; i++)
+ {
+ if (audio_driver_st.mixer_streams[i].state == AUDIO_STREAM_STATE_NONE)
+ {
+ *id = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params)
+{
+ unsigned free_slot = 0;
+ audio_mixer_voice_t *voice = NULL;
+ audio_mixer_sound_t *handle = NULL;
+ audio_mixer_stop_cb_t stop_cb = audio_mixer_play_stop_cb;
+ bool looped = false;
+ void *buf = NULL;
+
+ if (params->stream_type == AUDIO_STREAM_TYPE_NONE)
+ return false;
+
+ switch (params->slot_selection_type)
+ {
+ case AUDIO_MIXER_SLOT_SELECTION_MANUAL:
+ free_slot = params->slot_selection_idx;
+
+ /* If we are using a manually specified
+ * slot, must free any existing stream
+ * before assigning the new one */
+ audio_driver_mixer_stop_stream(free_slot);
+ audio_driver_mixer_remove_stream(free_slot);
+
+ break;
+ case AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC:
+ default:
+ if (!audio_driver_mixer_get_free_stream_slot(
+ &free_slot, params->stream_type))
+ return false;
+ break;
+ }
+
+ if (params->state == AUDIO_STREAM_STATE_NONE)
+ return false;
+
+ buf = malloc(params->bufsize);
+
+ if (!buf)
+ return false;
+
+ memcpy(buf, params->buf, params->bufsize);
+
+ switch (params->type)
+ {
+ case AUDIO_MIXER_TYPE_WAV:
+ handle = audio_mixer_load_wav(buf, (int32_t)params->bufsize,
+ audio_driver_st.resampler_ident,
+ audio_driver_st.resampler_quality);
+ /* WAV is a special case - input buffer is not
+ * free()'d when sound playback is complete (it is
+ * converted to a PCM buffer, which is free()'d instead),
+ * so have to do it here */
+ free(buf);
+ buf = NULL;
+ break;
+ case AUDIO_MIXER_TYPE_OGG:
+ handle = audio_mixer_load_ogg(buf, (int32_t)params->bufsize);
+ break;
+ case AUDIO_MIXER_TYPE_MOD:
+ handle = audio_mixer_load_mod(buf, (int32_t)params->bufsize);
+ break;
+ case AUDIO_MIXER_TYPE_FLAC:
+#ifdef HAVE_DR_FLAC
+ handle = audio_mixer_load_flac(buf, (int32_t)params->bufsize);
+#endif
+ break;
+ case AUDIO_MIXER_TYPE_MP3:
+#ifdef HAVE_DR_MP3
+ handle = audio_mixer_load_mp3(buf, (int32_t)params->bufsize);
+#endif
+ break;
+ case AUDIO_MIXER_TYPE_NONE:
+ break;
+ }
+
+ if (!handle)
+ {
+ free(buf);
+ return false;
+ }
+
+ switch (params->state)
+ {
+ case AUDIO_STREAM_STATE_PLAYING_LOOPED:
+ looped = true;
+ voice = audio_mixer_play(handle, looped, params->volume,
+ audio_driver_st.resampler_ident,
+ audio_driver_st.resampler_quality, stop_cb);
+ break;
+ case AUDIO_STREAM_STATE_PLAYING:
+ voice = audio_mixer_play(handle, looped, params->volume,
+ audio_driver_st.resampler_ident,
+ audio_driver_st.resampler_quality, stop_cb);
+ break;
+ case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
+ stop_cb = audio_mixer_play_stop_sequential_cb;
+ voice = audio_mixer_play(handle, looped, params->volume,
+ audio_driver_st.resampler_ident,
+ audio_driver_st.resampler_quality, stop_cb);
+ break;
+ default:
+ break;
+ }
+
+ audio_driver_st.mixer_active = true;
+
+ audio_driver_st.mixer_streams[free_slot].name =
+ !string_is_empty(params->basename) ? strdup(params->basename) : NULL;
+ audio_driver_st.mixer_streams[free_slot].buf = buf;
+ audio_driver_st.mixer_streams[free_slot].handle = handle;
+ audio_driver_st.mixer_streams[free_slot].voice = voice;
+ audio_driver_st.mixer_streams[free_slot].stream_type = params->stream_type;
+ audio_driver_st.mixer_streams[free_slot].type = params->type;
+ audio_driver_st.mixer_streams[free_slot].state = params->state;
+ audio_driver_st.mixer_streams[free_slot].volume = params->volume;
+ audio_driver_st.mixer_streams[free_slot].stop_cb = stop_cb;
+
+ return true;
+}
+
+enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i)
+{
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return AUDIO_STREAM_STATE_NONE;
+
+ return audio_driver_st.mixer_streams[i].state;
+}
+
+static void audio_driver_mixer_play_stream_internal(
+ unsigned i, unsigned type)
+{
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return;
+
+ switch (audio_driver_st.mixer_streams[i].state)
+ {
+ case AUDIO_STREAM_STATE_STOPPED:
+ audio_driver_st.mixer_streams[i].voice =
+ audio_mixer_play(audio_driver_st.mixer_streams[i].handle,
+ (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false,
+ 1.0f, audio_driver_st.resampler_ident,
+ audio_driver_st.resampler_quality,
+ audio_driver_st.mixer_streams[i].stop_cb);
+ audio_driver_st.mixer_streams[i].state = (enum audio_mixer_state)type;
+ break;
+ case AUDIO_STREAM_STATE_PLAYING:
+ case AUDIO_STREAM_STATE_PLAYING_LOOPED:
+ case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
+ case AUDIO_STREAM_STATE_NONE:
+ break;
+ }
+}
+
+static void audio_driver_load_menu_bgm_callback(retro_task_t *task,
+ void *task_data, void *user_data, const char *error)
+{
+ bool contentless = false;
+ bool is_inited = false;
+
+ content_get_status(&contentless, &is_inited);
+
+ if (!is_inited)
+ audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
+}
+
+void audio_driver_load_system_sounds(void)
+{
+ char sounds_path[PATH_MAX_LENGTH];
+ char sounds_fallback_path[PATH_MAX_LENGTH];
+ char basename_noext[PATH_MAX_LENGTH];
+ settings_t *settings = config_get_ptr();
+ const char *dir_assets = settings->paths.directory_assets;
+ const bool audio_enable_menu = settings->bools.audio_enable_menu;
+ const bool audio_enable_menu_ok = audio_enable_menu && settings->bools.audio_enable_menu_ok;
+ const bool audio_enable_menu_cancel = audio_enable_menu && settings->bools.audio_enable_menu_cancel;
+ const bool audio_enable_menu_notice = audio_enable_menu && settings->bools.audio_enable_menu_notice;
+ const bool audio_enable_menu_bgm = audio_enable_menu && settings->bools.audio_enable_menu_bgm;
+ const bool audio_enable_cheevo_unlock = settings->bools.cheevos_unlock_sound_enable;
+ const char *path_ok = NULL;
+ const char *path_cancel = NULL;
+ const char *path_notice = NULL;
+ const char *path_bgm = NULL;
+ const char *path_cheevo_unlock = NULL;
+ struct string_list *list = NULL;
+ struct string_list *list_fallback = NULL;
+ unsigned i = 0;
+
+ if (!audio_enable_menu && !audio_enable_cheevo_unlock)
+ goto end;
+
+ sounds_path[0] = sounds_fallback_path[0] =
+ basename_noext[0] ='\0';
+
+ fill_pathname_join(
+ sounds_fallback_path,
+ dir_assets,
+ "sounds",
+ sizeof(sounds_fallback_path));
+
+ fill_pathname_application_special(
+ sounds_path,
+ sizeof(sounds_path),
+ APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS);
+
+ list = dir_list_new(sounds_path, MENU_SOUND_FORMATS, false, false, false, false);
+ list_fallback = dir_list_new(sounds_fallback_path, MENU_SOUND_FORMATS, false, false, false, false);
+
+ if (!list)
+ {
+ list = list_fallback;
+ list_fallback = NULL;
+ }
+
+ if (!list || list->size == 0)
+ goto end;
+
+ if (list_fallback && list_fallback->size > 0)
+ {
+ for (i = 0; i < list_fallback->size; i++)
+ {
+ if (list->size == 0 || !string_list_find_elem(list, list_fallback->elems[i].data))
+ {
+ union string_list_elem_attr attr = {0};
+ string_list_append(list, list_fallback->elems[i].data, attr);
+ }
+ }
+ }
+
+ for (i = 0; i < list->size; i++)
+ {
+ const char *path = list->elems[i].data;
+ const char *ext = path_get_extension(path);
+
+ if (audio_driver_mixer_extension_supported(ext))
+ {
+ basename_noext[0] = '\0';
+ fill_pathname_base_noext(basename_noext, path, sizeof(basename_noext));
+
+ if (string_is_equal_noncase(basename_noext, "ok"))
+ path_ok = path;
+ else if (string_is_equal_noncase(basename_noext, "cancel"))
+ path_cancel = path;
+ else if (string_is_equal_noncase(basename_noext, "notice"))
+ path_notice = path;
+ else if (string_is_equal_noncase(basename_noext, "bgm"))
+ path_bgm = path;
+ else if (string_is_equal_noncase(basename_noext, "unlock"))
+ path_cheevo_unlock = path;
+ }
+ }
+
+ if (path_ok && audio_enable_menu_ok)
+ task_push_audio_mixer_load(path_ok, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_OK);
+ if (path_cancel && audio_enable_menu_cancel)
+ task_push_audio_mixer_load(path_cancel, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_CANCEL);
+ if (path_notice && audio_enable_menu_notice)
+ task_push_audio_mixer_load(path_notice, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_NOTICE);
+ if (path_bgm && audio_enable_menu_bgm)
+ task_push_audio_mixer_load(path_bgm, audio_driver_load_menu_bgm_callback, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_BGM);
+ if (path_cheevo_unlock && audio_enable_cheevo_unlock)
+ task_push_audio_mixer_load(path_cheevo_unlock, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_ACHIEVEMENT_UNLOCK);
+
+end:
+ if (list)
+ string_list_free(list);
+ if (list_fallback)
+ string_list_free(list_fallback);
+}
+
+void audio_driver_mixer_play_stream(unsigned i)
+{
+ audio_driver_st.mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
+ audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING);
+}
+
+void audio_driver_mixer_play_menu_sound_looped(unsigned i)
+{
+ audio_driver_st.mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
+ audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
+}
+
+void audio_driver_mixer_play_menu_sound(unsigned i)
+{
+ audio_driver_st.mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
+ audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING);
+}
+
+void audio_driver_mixer_play_stream_looped(unsigned i)
+{
+ audio_driver_st.mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
+ audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
+}
+
+void audio_driver_mixer_play_stream_sequential(unsigned i)
+{
+ audio_driver_st.mixer_streams[i].stop_cb = audio_mixer_play_stop_sequential_cb;
+ audio_driver_mixer_play_stream_internal(i, AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL);
+}
+
+float audio_driver_mixer_get_stream_volume(unsigned i)
+{
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return 0.0f;
+
+ return audio_driver_st.mixer_streams[i].volume;
+}
+
+void audio_driver_mixer_set_stream_volume(unsigned i, float vol)
+{
+ audio_mixer_voice_t *voice = NULL;
+
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return;
+
+ audio_driver_st.mixer_streams[i].volume = vol;
+
+ voice =
+ audio_driver_st.mixer_streams[i].voice;
+
+ if (voice)
+ audio_mixer_voice_set_volume(voice, DB_TO_GAIN(vol));
+}
+
+void audio_driver_mixer_stop_stream(unsigned i)
+{
+ bool set_state = false;
+
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return;
+
+ switch (audio_driver_st.mixer_streams[i].state)
+ {
+ case AUDIO_STREAM_STATE_PLAYING:
+ case AUDIO_STREAM_STATE_PLAYING_LOOPED:
+ case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
+ set_state = true;
+ break;
+ case AUDIO_STREAM_STATE_STOPPED:
+ case AUDIO_STREAM_STATE_NONE:
+ break;
+ }
+
+ if (set_state)
+ {
+ audio_mixer_voice_t *voice = audio_driver_st.mixer_streams[i].voice;
+
+ if (voice)
+ audio_mixer_stop(voice);
+ audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
+ audio_driver_st.mixer_streams[i].volume = 1.0f;
+ }
+}
+
+void audio_driver_mixer_remove_stream(unsigned i)
+{
+ bool destroy = false;
+
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return;
+
+ switch (audio_driver_st.mixer_streams[i].state)
+ {
+ case AUDIO_STREAM_STATE_PLAYING:
+ case AUDIO_STREAM_STATE_PLAYING_LOOPED:
+ case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
+ audio_driver_mixer_stop_stream(i);
+ destroy = true;
+ break;
+ case AUDIO_STREAM_STATE_STOPPED:
+ destroy = true;
+ break;
+ case AUDIO_STREAM_STATE_NONE:
+ break;
+ }
+
+ if (destroy)
+ {
+ audio_mixer_sound_t *handle = audio_driver_st.mixer_streams[i].handle;
+ if (handle)
+ audio_mixer_destroy(handle);
+
+ if (!string_is_empty(audio_driver_st.mixer_streams[i].name))
+ free(audio_driver_st.mixer_streams[i].name);
+
+ audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
+ audio_driver_st.mixer_streams[i].stop_cb = NULL;
+ audio_driver_st.mixer_streams[i].volume = 0.0f;
+ audio_driver_st.mixer_streams[i].handle = NULL;
+ audio_driver_st.mixer_streams[i].voice = NULL;
+ audio_driver_st.mixer_streams[i].name = NULL;
+ }
+}
+
+bool audio_driver_mixer_toggle_mute(void)
+{
+ audio_driver_st.mixer_mute_enable =
+ !audio_driver_st.mixer_mute_enable;
+ return true;
+}
+#endif
+
+bool audio_driver_enable_callback(void)
+{
+ if (!audio_driver_st.callback.callback)
+ return false;
+ if (audio_driver_st.callback.set_state)
+ audio_driver_st.callback.set_state(true);
+ return true;
+}
+
+bool audio_driver_disable_callback(void)
+{
+ if (!audio_driver_st.callback.callback)
+ return false;
+
+ if (audio_driver_st.callback.set_state)
+ audio_driver_st.callback.set_state(false);
+ return true;
+}
+
+bool audio_driver_callback(void)
+{
+ settings_t *settings = config_get_ptr();
+ bool runloop_paused = runloop_state_get_ptr()->paused;
+#ifdef HAVE_MENU
+ bool core_paused = runloop_paused || (settings->bools.menu_pause_libretro && menu_state_get_ptr()->alive);
+#else
+ bool core_paused = runloop_paused;
+#endif
+
+ if (!audio_driver_st.callback.callback)
+ return false;
+
+ if (!core_paused && audio_driver_st.callback.callback)
+ audio_driver_st.callback.callback();
+
+ return true;
+}
+
+bool audio_driver_has_callback(void)
+{
+ return audio_driver_st.callback.callback;
+}
+
+static INLINE bool audio_driver_alive(void)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if ( audio_st->current_audio
+ && audio_st->current_audio->alive
+ && audio_st->context_audio_data)
+ return audio_st->current_audio->alive(audio_st->context_audio_data);
+ return false;
+}
+
+bool audio_driver_start(bool is_shutdown)
+{
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ if (
+ !audio_st->current_audio
+ || !audio_st->current_audio->start
+ || !audio_st->context_audio_data)
+ goto error;
+ if (!audio_st->current_audio->start(
+ audio_st->context_audio_data, is_shutdown))
+ goto error;
+
+ return true;
+
+error:
+ RARCH_ERR("%s\n",
+ msg_hash_to_str(MSG_FAILED_TO_START_AUDIO_DRIVER));
+ audio_driver_st.active = false;
+ return false;
+}
+
+bool audio_driver_stop(void)
+{
+ if ( !audio_driver_st.current_audio
+ || !audio_driver_st.current_audio->stop
+ || !audio_driver_st.context_audio_data
+ || !audio_driver_alive()
+ )
+ return false;
+ return audio_driver_st.current_audio->stop(
+ audio_driver_st.context_audio_data);
+}
+
+#ifdef HAVE_REWIND
+void audio_driver_frame_is_reverse(void)
+{
+ recording_state_t *recording_st = recording_state_get_ptr();
+ runloop_state_t *runloop_st = runloop_state_get_ptr();
+
+ /* We just rewound. Flush rewind audio buffer. */
+ if ( recording_st->data &&
+ recording_st->driver &&
+ recording_st->driver->push_audio)
+ {
+ struct record_audio_data ffemu_data;
+
+ ffemu_data.data = audio_driver_st.rewind_buf +
+ audio_driver_st.rewind_ptr;
+ ffemu_data.frames = (audio_driver_st.rewind_size -
+ audio_driver_st.rewind_ptr) / 2;
+
+ recording_st->driver->push_audio(
+ recording_st->data,
+ &ffemu_data);
+ }
+
+ if (!(
+ runloop_st->paused ||
+ !audio_driver_st.active ||
+ !audio_driver_st.output_samples_buf))
+ if (!audio_driver_st.suspended)
+ audio_driver_flush(
+ config_get_ptr()->floats.slowmotion_ratio,
+ config_get_ptr()->bools.audio_fastforward_mute,
+ audio_driver_st.rewind_buf +
+ audio_driver_st.rewind_ptr,
+ audio_driver_st.rewind_size -
+ audio_driver_st.rewind_ptr,
+ runloop_state_get_ptr()->slowmotion,
+ runloop_state_get_ptr()->fastmotion);
+}
+#endif
+
+void audio_set_float(enum audio_action action, float val)
+{
+ switch (action)
+ {
+ case AUDIO_ACTION_VOLUME_GAIN:
+ audio_driver_st.volume_gain = DB_TO_GAIN(val);
+ break;
+ case AUDIO_ACTION_MIXER_VOLUME_GAIN:
+#ifdef HAVE_AUDIOMIXER
+ audio_driver_st.mixer_volume_gain = DB_TO_GAIN(val);
+#endif
+ break;
+ case AUDIO_ACTION_RATE_CONTROL_DELTA:
+ audio_driver_st.rate_control_delta = val;
+ break;
+ case AUDIO_ACTION_NONE:
+ default:
+ break;
+ }
+}
+
+float *audio_get_float_ptr(enum audio_action action)
+{
+ switch (action)
+ {
+ case AUDIO_ACTION_RATE_CONTROL_DELTA:
+ return &audio_driver_st.rate_control_delta;
+ case AUDIO_ACTION_NONE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+bool *audio_get_bool_ptr(enum audio_action action)
+{
+ switch (action)
+ {
+ case AUDIO_ACTION_MIXER_MUTE_ENABLE:
+#ifdef HAVE_AUDIOMIXER
+ return &audio_driver_st.mixer_mute_enable;
+#else
+ break;
+#endif
+ case AUDIO_ACTION_MUTE_ENABLE:
+ return &audio_driver_st.mute_enable;
+ case AUDIO_ACTION_NONE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+bool audio_compute_buffer_statistics(audio_statistics_t *stats)
+{
+ unsigned i, low_water_size, high_water_size, avg, stddev;
+ uint64_t accum = 0;
+ uint64_t accum_var = 0;
+ unsigned low_water_count = 0;
+ unsigned high_water_count = 0;
+ audio_driver_state_t *audio_st = &audio_driver_st;
+ unsigned samples = MIN(
+ (unsigned)audio_st->free_samples_count,
+ AUDIO_BUFFER_FREE_SAMPLES_COUNT);
+
+ if (samples < 3)
+ return false;
+
+ stats->samples = (unsigned)
+ audio_st->free_samples_count;
+
+#ifdef WARPUP
+ /* uint64 to double not implemented, fair chance
+ * signed int64 to double doesn't exist either */
+ /* https://forums.libretro.com/t/unsupported-platform-help/13903/ */
+ (void)stddev;
+#elif defined(_MSC_VER) && _MSC_VER <= 1200
+ /* FIXME: error C2520: conversion from unsigned __int64
+ * to double not implemented, use signed __int64 */
+ (void)stddev;
+#else
+ for (i = 1; i < samples; i++)
+ accum += audio_st->free_samples_buf[i];
+
+ avg = (unsigned)accum / (samples - 1);
+
+ for (i = 1; i < samples; i++)
+ {
+ int diff = avg - audio_st->free_samples_buf[i];
+ accum_var += diff * diff;
+ }
+
+ stddev = (unsigned)
+ sqrt((double)accum_var / (samples - 2));
+
+ stats->average_buffer_saturation = (1.0f - (float)avg
+ / audio_st->buffer_size) * 100.0;
+ stats->std_deviation_percentage = ((float)stddev
+ / audio_st->buffer_size) * 100.0;
+#endif
+
+ low_water_size = (unsigned)(audio_st->buffer_size * 3 / 4);
+ high_water_size = (unsigned)(audio_st->buffer_size / 4);
+
+ for (i = 1; i < samples; i++)
+ {
+ if (audio_st->free_samples_buf[i] >= low_water_size)
+ low_water_count++;
+ else if (audio_st->free_samples_buf[i] <= high_water_size)
+ high_water_count++;
+ }
+
+ stats->close_to_underrun = (100.0f * low_water_count) / (samples - 1);
+ stats->close_to_blocking = (100.0f * high_water_count) / (samples - 1);
+
+ return true;
+}
diff --git a/audio/audio_driver.h b/audio/audio_driver.h
new file mode 100644
index 0000000000..44a5e75d69
--- /dev/null
+++ b/audio/audio_driver.h
@@ -0,0 +1,427 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2017 - 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 .
+ */
+
+#ifndef __AUDIO_DRIVER__H
+#define __AUDIO_DRIVER__H
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_DSP_FILTER
+#include
+#endif
+#ifdef HAVE_AUDIOMIXER
+#include
+#endif
+#include
+
+#include "audio_defines.h"
+
+#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
+
+RETRO_BEGIN_DECLS
+
+#ifdef HAVE_AUDIOMIXER
+typedef struct audio_mixer_stream
+{
+ audio_mixer_sound_t *handle;
+ audio_mixer_voice_t *voice;
+ audio_mixer_stop_cb_t stop_cb;
+ void *buf;
+ char *name;
+ size_t bufsize;
+ float volume;
+ enum audio_mixer_stream_type stream_type;
+ enum audio_mixer_type type;
+ enum audio_mixer_state state;
+} audio_mixer_stream_t;
+
+typedef struct audio_mixer_stream_params
+{
+ void *buf;
+ char *basename;
+ audio_mixer_stop_cb_t cb;
+ size_t bufsize;
+ unsigned slot_selection_idx;
+ float volume;
+ enum audio_mixer_slot_selection_type slot_selection_type;
+ enum audio_mixer_stream_type stream_type;
+ enum audio_mixer_type type;
+ enum audio_mixer_state state;
+} audio_mixer_stream_params_t;
+#endif
+
+typedef struct audio_driver
+{
+ /* Creates and initializes handle to audio driver.
+ *
+ * Returns: audio driver handle on success, otherwise NULL.
+ **/
+ void *(*init)(const char *device, unsigned rate,
+ unsigned latency, unsigned block_frames, unsigned *new_rate);
+
+ /*
+ * @data : Pointer to audio data handle.
+ * @buf : Audio buffer data.
+ * @size : Size of audio buffer.
+ *
+ * Write samples to audio driver.
+ *
+ * Write data in buffer to audio driver.
+ * A frame here is defined as one combined sample of left and right
+ * channels. (I.e. 44.1kHz, 16-bit stereo has 88.2k samples/s, and
+ * 44.1k frames/s.)
+ *
+ * Samples are interleaved in format LRLRLRLRLR ...
+ * If the driver returns true in use_float(), a floating point
+ * format will be used, with range [-1.0, 1.0].
+ * If not, signed 16-bit samples in native byte ordering will be used.
+ *
+ * This function returns the number of frames successfully written.
+ * If an error occurs, -1 should be returned.
+ * Note that non-blocking behavior that cannot write at this time
+ * should return 0 as returning -1 will terminate the driver.
+ *
+ * Unless said otherwise with set_nonblock_state(), all writes
+ * are blocking, and it should block till it has written all frames.
+ */
+ ssize_t (*write)(void *data, const void *buf, size_t size);
+
+ /* Temporarily pauses the audio driver. */
+ bool (*stop)(void *data);
+
+ /* Resumes audio driver from the paused state. */
+ bool (*start)(void *data, bool is_shutdown);
+
+ /* Is the audio driver currently running? */
+ bool (*alive)(void *data);
+
+ /* Should we care about blocking in audio thread? Fast forwarding.
+ *
+ * If state is true, nonblocking operation is assumed.
+ * This is typically used for fast-forwarding. If driver cannot
+ * implement nonblocking writes, this can be disregarded, but should
+ * log a message to stderr.
+ * */
+ void (*set_nonblock_state)(void *data, bool toggle);
+
+ /* Stops and frees driver data. */
+ void (*free)(void *data);
+
+ /* Defines if driver will take standard floating point samples,
+ * or int16_t samples.
+ *
+ * If true is returned, the audio driver is capable of using
+ * floating point data. This will likely increase performance as the
+ * resampler unit uses floating point. The sample range is
+ * [-1.0, 1.0].
+ * */
+ bool (*use_float)(void *data);
+
+ /* Human-readable identifier. */
+ const char *ident;
+
+ /* Optional. Get audio device list (allocates, caller has to free this) */
+ void *(*device_list_new)(void *data);
+
+ /* Optional. Frees audio device list */
+ void (*device_list_free)(void *data, void *data2);
+
+ /* Optional. */
+ size_t (*write_avail)(void *data);
+
+ size_t (*buffer_size)(void *data);
+} audio_driver_t;
+
+typedef struct
+{
+ double source_ratio_original;
+ double source_ratio_current;
+
+ uint64_t free_samples_count;
+
+ struct string_list *devices_list;
+ float *output_samples_buf;
+#ifdef HAVE_REWIND
+ int16_t *rewind_buf;
+#endif
+ int16_t *output_samples_conv_buf;
+#ifdef HAVE_DSP_FILTER
+ retro_dsp_filter_t *dsp;
+#endif
+ const retro_resampler_t *resampler;
+
+ void *resampler_data;
+ const audio_driver_t *current_audio;
+ void *context_audio_data;
+ float *input_data;
+#ifdef HAVE_AUDIOMIXER
+ struct audio_mixer_stream
+ mixer_streams[AUDIO_MIXER_MAX_SYSTEM_STREAMS];
+#endif
+ struct retro_audio_callback callback; /* ptr alignment */
+ /* ptr alignment */
+ size_t chunk_size;
+ size_t chunk_nonblock_size;
+ size_t chunk_block_size;
+
+#ifdef HAVE_REWIND
+ size_t rewind_ptr;
+ size_t rewind_size;
+#endif
+ size_t buffer_size;
+ size_t data_ptr;
+
+ unsigned free_samples_buf[
+ AUDIO_BUFFER_FREE_SAMPLES_COUNT];
+
+#ifdef HAVE_AUDIOMIXER
+ float mixer_volume_gain;
+#endif
+
+ float rate_control_delta;
+ float input;
+ float volume_gain;
+
+ enum resampler_quality resampler_quality;
+
+ char resampler_ident[64];
+
+ bool active;
+ bool control;
+ bool mute_enable;
+ bool use_float;
+ bool suspended;
+#ifdef HAVE_AUDIOMIXER
+ bool mixer_mute_enable;
+ bool mixer_active;
+#endif
+#ifdef HAVE_RUNAHEAD
+ bool hard_disable;
+#endif
+} audio_driver_state_t;
+
+bool audio_driver_enable_callback(void);
+
+bool audio_driver_disable_callback(void);
+
+bool audio_driver_mixer_extension_supported(const char *ext);
+
+void audio_driver_dsp_filter_free(void);
+
+bool audio_driver_dsp_filter_init(const char *device);
+
+void audio_driver_set_buffer_size(size_t bufsize);
+
+bool audio_driver_get_devices_list(void **ptr);
+
+void audio_driver_setup_rewind(void);
+
+bool audio_driver_callback(void);
+
+bool audio_driver_has_callback(void);
+
+void audio_driver_frame_is_reverse(void);
+
+void audio_set_float(enum audio_action action, float val);
+
+float *audio_get_float_ptr(enum audio_action action);
+
+bool *audio_get_bool_ptr(enum audio_action action);
+
+#ifdef HAVE_AUDIOMIXER
+audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i);
+
+bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params);
+
+void audio_driver_mixer_play_stream(unsigned i);
+
+void audio_driver_mixer_play_menu_sound(unsigned i);
+
+void audio_driver_mixer_play_menu_sound_looped(unsigned i);
+
+void audio_driver_mixer_play_stream_sequential(unsigned i);
+
+void audio_driver_mixer_play_stream_looped(unsigned i);
+
+void audio_driver_mixer_stop_stream(unsigned i);
+
+float audio_driver_mixer_get_stream_volume(unsigned i);
+
+void audio_driver_mixer_set_stream_volume(unsigned i, float vol);
+
+void audio_driver_mixer_remove_stream(unsigned i);
+
+enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i);
+
+const char *audio_driver_mixer_get_stream_name(unsigned i);
+
+void audio_driver_load_system_sounds(void);
+
+#endif
+
+bool audio_driver_start(bool is_shutdown);
+
+bool audio_driver_stop(void);
+
+#ifdef HAVE_TRANSLATE
+/* TODO/FIXME - Doesn't currently work. Fix this. */
+bool audio_driver_is_ai_service_speech_running(void);
+#endif
+
+extern audio_driver_t audio_rsound;
+extern audio_driver_t audio_audioio;
+extern audio_driver_t audio_oss;
+extern audio_driver_t audio_alsa;
+extern audio_driver_t audio_alsathread;
+extern audio_driver_t audio_tinyalsa;
+extern audio_driver_t audio_roar;
+extern audio_driver_t audio_openal;
+extern audio_driver_t audio_opensl;
+extern audio_driver_t audio_jack;
+extern audio_driver_t audio_sdl;
+extern audio_driver_t audio_xa;
+extern audio_driver_t audio_pulse;
+extern audio_driver_t audio_dsound;
+extern audio_driver_t audio_wasapi;
+extern audio_driver_t audio_coreaudio;
+extern audio_driver_t audio_coreaudio3;
+extern audio_driver_t audio_xenon360;
+extern audio_driver_t audio_ps3;
+extern audio_driver_t audio_gx;
+extern audio_driver_t audio_ax;
+extern audio_driver_t audio_psp;
+extern audio_driver_t audio_ps2;
+extern audio_driver_t audio_ctr_csnd;
+extern audio_driver_t audio_ctr_dsp;
+#ifdef HAVE_THREADS
+extern audio_driver_t audio_ctr_dsp_thread;
+#endif
+extern audio_driver_t audio_switch;
+extern audio_driver_t audio_switch_thread;
+extern audio_driver_t audio_switch_libnx_audren;
+extern audio_driver_t audio_switch_libnx_audren_thread;
+extern audio_driver_t audio_rwebaudio;
+
+audio_driver_state_t *audio_state_get_ptr(void);
+
+extern audio_driver_t *audio_drivers[];
+
+/**
+ * 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.
+ **/
+void audio_driver_flush(
+ float slowmotion_ratio,
+ bool audio_fastforward_mute,
+ const int16_t *data, size_t samples,
+ bool is_slowmotion, bool is_fastmotion);
+
+/**
+ * audio_compute_buffer_statistics:
+ *
+ * Computes audio buffer statistics.
+ *
+ **/
+bool audio_compute_buffer_statistics(audio_statistics_t *stats);
+
+float audio_driver_monitor_adjust_system_rates(
+ double input_sample_rate,
+ double input_fps,
+ float video_refresh_rate,
+ unsigned video_swap_interval,
+ float audio_max_timing_skew);
+
+bool audio_driver_init_internal(
+ void *settings_data,
+ bool audio_cb_inited);
+
+bool audio_driver_deinit(void *settings_data);
+
+bool audio_driver_find_driver(
+ void *settings_data,
+ const char *prefix,
+ bool verbosity_enabled);
+
+/**
+ * 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_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);
+
+#ifdef HAVE_REWIND
+/**
+ * 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_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);
+#endif
+
+RETRO_END_DECLS
+
+#endif /* __AUDIO_DRIVER__H */
diff --git a/audio/audio_thread_wrapper.c b/audio/audio_thread_wrapper.c
index a412bb0da5..964ddd29b9 100644
--- a/audio/audio_thread_wrapper.c
+++ b/audio/audio_thread_wrapper.c
@@ -21,6 +21,7 @@
#include
#include "audio_thread_wrapper.h"
+#include "audio_driver.h"
#include "../verbosity.h"
typedef struct audio_thread
diff --git a/audio/audio_thread_wrapper.h b/audio/audio_thread_wrapper.h
index 8ee8be2be0..11fee2d566 100644
--- a/audio/audio_thread_wrapper.h
+++ b/audio/audio_thread_wrapper.h
@@ -19,7 +19,7 @@
#include
-#include "../retroarch.h"
+#include "audio_driver.h"
/**
* audio_init_thread:
diff --git a/audio/drivers/alsa.c b/audio/drivers/alsa.c
index 8baee9fa74..8a60432484 100644
--- a/audio/drivers/alsa.c
+++ b/audio/drivers/alsa.c
@@ -21,7 +21,7 @@
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
typedef struct alsa
diff --git a/audio/drivers/alsa_qsa.c b/audio/drivers/alsa_qsa.c
index f168ceab90..f534a7a7c6 100644
--- a/audio/drivers/alsa_qsa.c
+++ b/audio/drivers/alsa_qsa.c
@@ -19,7 +19,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#define MAX_FRAG_SIZE 3072
#define DEFAULT_RATE 48000
diff --git a/audio/drivers/alsathread.c b/audio/drivers/alsathread.c
index 825e7492f7..1e239ef119 100644
--- a/audio/drivers/alsathread.c
+++ b/audio/drivers/alsathread.c
@@ -24,7 +24,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#define TRY_ALSA(x) if (x < 0) \
diff --git a/audio/drivers/audioio.c b/audio/drivers/audioio.c
index d80a18670e..8176a0d7b4 100644
--- a/audio/drivers/audioio.c
+++ b/audio/drivers/audioio.c
@@ -27,7 +27,7 @@
#include "../../config.h"
#endif
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#define DEFAULT_DEV "/dev/audio"
diff --git a/audio/drivers/coreaudio.c b/audio/drivers/coreaudio.c
index 1f4fd7ae76..190ae2c8ad 100644
--- a/audio/drivers/coreaudio.c
+++ b/audio/drivers/coreaudio.c
@@ -31,7 +31,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
typedef struct coreaudio
diff --git a/audio/drivers/coreaudio3.m b/audio/drivers/coreaudio3.m
index 8d4eebb32f..897db2fc10 100644
--- a/audio/drivers/coreaudio3.m
+++ b/audio/drivers/coreaudio3.m
@@ -22,7 +22,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#pragma mark - ringbuffer
diff --git a/audio/drivers/ctr_csnd_audio.c b/audio/drivers/ctr_csnd_audio.c
index 165d226e74..eb7986f90b 100644
--- a/audio/drivers/ctr_csnd_audio.c
+++ b/audio/drivers/ctr_csnd_audio.c
@@ -19,7 +19,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
typedef struct
{
diff --git a/audio/drivers/ctr_dsp_audio.c b/audio/drivers/ctr_dsp_audio.c
index 02b52773b8..e25f0bede4 100644
--- a/audio/drivers/ctr_dsp_audio.c
+++ b/audio/drivers/ctr_dsp_audio.c
@@ -17,7 +17,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../ctr/ctr_debug.h"
typedef struct
diff --git a/audio/drivers/ctr_dsp_thread_audio.c b/audio/drivers/ctr_dsp_thread_audio.c
index 08dad28654..4fbbf5f6fa 100644
--- a/audio/drivers/ctr_dsp_thread_audio.c
+++ b/audio/drivers/ctr_dsp_thread_audio.c
@@ -19,7 +19,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../ctr/ctr_debug.h"
typedef struct
diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c
index 98a5057aed..e4a2c1b54c 100644
--- a/audio/drivers/dsound.c
+++ b/audio/drivers/dsound.c
@@ -39,7 +39,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#ifdef _XBOX
diff --git a/audio/drivers/gx_audio.c b/audio/drivers/gx_audio.c
index a6c7c83ce5..95b24b07f5 100644
--- a/audio/drivers/gx_audio.c
+++ b/audio/drivers/gx_audio.c
@@ -27,9 +27,10 @@
#include
#include
-#include "../../retroarch.h"
#include
+#include "../audio_driver.h"
+
typedef struct
{
size_t write_ptr;
diff --git a/audio/drivers/jack.c b/audio/drivers/jack.c
index f0729b385d..6d199067e2 100644
--- a/audio/drivers/jack.c
+++ b/audio/drivers/jack.c
@@ -26,7 +26,7 @@
#include
#include "../../configuration.h"
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#define FRAMES(x) (x / (sizeof(float) * 2))
diff --git a/audio/drivers/openal.c b/audio/drivers/openal.c
index ce540c14a9..606274847e 100644
--- a/audio/drivers/openal.c
+++ b/audio/drivers/openal.c
@@ -33,7 +33,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#define BUFSIZE 1024
diff --git a/audio/drivers/opensl.c b/audio/drivers/opensl.c
index 6e33a466d6..c5a8e59ad0 100644
--- a/audio/drivers/opensl.c
+++ b/audio/drivers/opensl.c
@@ -21,7 +21,7 @@
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
/* Helper macros, COM-style. */
#define SLObjectItf_Realize(a, ...) ((*(a))->Realize(a, __VA_ARGS__))
diff --git a/audio/drivers/oss.c b/audio/drivers/oss.c
index 9dd7634b55..88a88d8b02 100644
--- a/audio/drivers/oss.c
+++ b/audio/drivers/oss.c
@@ -33,7 +33,7 @@
#include "../../config.h"
#endif
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#ifdef HAVE_OSS_BSD
diff --git a/audio/drivers/ps2_audio.c b/audio/drivers/ps2_audio.c
index c16be245e6..786b2a49b4 100644
--- a/audio/drivers/ps2_audio.c
+++ b/audio/drivers/ps2_audio.c
@@ -20,7 +20,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#define AUDIO_BUFFER 128 * 1024
#define AUDIO_CHANNELS 2
diff --git a/audio/drivers/ps3_audio.c b/audio/drivers/ps3_audio.c
index 14d100e63a..1b40ed645f 100644
--- a/audio/drivers/ps3_audio.c
+++ b/audio/drivers/ps3_audio.c
@@ -19,10 +19,10 @@
#include
-#include "../../retroarch.h"
-
#include
+#include "../audio_driver.h"
+
#define AUDIO_BLOCKS 8
#define AUDIO_CHANNELS 2
diff --git a/audio/drivers/psp_audio.c b/audio/drivers/psp_audio.c
index ef34867c70..6faab4e1d0 100644
--- a/audio/drivers/psp_audio.c
+++ b/audio/drivers/psp_audio.c
@@ -40,7 +40,7 @@
#define SceUID uint32_t
#endif
-#include "../../retroarch.h"
+#include "../audio_driver.h"
typedef struct psp_audio
{
diff --git a/audio/drivers/pulse.c b/audio/drivers/pulse.c
index a319e10ebf..fd27ca7b8f 100644
--- a/audio/drivers/pulse.c
+++ b/audio/drivers/pulse.c
@@ -23,7 +23,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
typedef struct
diff --git a/audio/drivers/roar.c b/audio/drivers/roar.c
index da5725763b..a36bbb7b26 100644
--- a/audio/drivers/roar.c
+++ b/audio/drivers/roar.c
@@ -23,7 +23,7 @@
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
typedef struct
diff --git a/audio/drivers/rsound.c b/audio/drivers/rsound.c
index 98c1da4609..fbc6f749a7 100644
--- a/audio/drivers/rsound.c
+++ b/audio/drivers/rsound.c
@@ -21,7 +21,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "rsound.h"
typedef struct rsd
diff --git a/audio/drivers/rwebaudio.c b/audio/drivers/rwebaudio.c
index 1cfcd2fda0..41cf2d1ea6 100644
--- a/audio/drivers/rwebaudio.c
+++ b/audio/drivers/rwebaudio.c
@@ -18,7 +18,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
/* forward declarations */
unsigned RWebAudioSampleRate(void);
diff --git a/audio/drivers/sdl_audio.c b/audio/drivers/sdl_audio.c
index 88592cd582..56554083f5 100644
--- a/audio/drivers/sdl_audio.c
+++ b/audio/drivers/sdl_audio.c
@@ -25,12 +25,12 @@
#include
#include
-#include "../../retroarch.h"
-#include "../../verbosity.h"
-
#include "SDL.h"
#include "SDL_audio.h"
+#include "../audio_driver.h"
+#include "../../verbosity.h"
+
typedef struct sdl_audio
{
#ifdef HAVE_THREADS
diff --git a/audio/drivers/switch_audio.c b/audio/drivers/switch_audio.c
index 4624646ab5..a2b6291ccb 100644
--- a/audio/drivers/switch_audio.c
+++ b/audio/drivers/switch_audio.c
@@ -20,7 +20,7 @@
#include
#include "switch_audio_compat.h"
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#ifdef HAVE_LIBNX
diff --git a/audio/drivers/switch_libnx_audren_audio.c b/audio/drivers/switch_libnx_audren_audio.c
index 144c6b6b4b..998a25a6a2 100644
--- a/audio/drivers/switch_libnx_audren_audio.c
+++ b/audio/drivers/switch_libnx_audren_audio.c
@@ -23,7 +23,7 @@
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#define BUFFER_COUNT 5
diff --git a/audio/drivers/switch_libnx_audren_thread_audio.c b/audio/drivers/switch_libnx_audren_thread_audio.c
index 3ed5fe2d9d..286dbd1dc6 100644
--- a/audio/drivers/switch_libnx_audren_thread_audio.c
+++ b/audio/drivers/switch_libnx_audren_thread_audio.c
@@ -21,7 +21,8 @@
#include
#include
-#include "../../retroarch.h"
+
+#include "../audio_driver.h"
#include "../../verbosity.h"
#include "../../tasks/tasks_internal.h"
diff --git a/audio/drivers/switch_thread_audio.c b/audio/drivers/switch_thread_audio.c
index eaee835cec..3b58fd3c2a 100644
--- a/audio/drivers/switch_thread_audio.c
+++ b/audio/drivers/switch_thread_audio.c
@@ -28,7 +28,8 @@
#endif
#include
-#include "../../retroarch.h"
+
+#include "../audio_driver.h"
#include "../../verbosity.h"
#include "../../tasks/tasks_internal.h"
diff --git a/audio/drivers/tinyalsa.c b/audio/drivers/tinyalsa.c
index 952b35899d..fee4174777 100644
--- a/audio/drivers/tinyalsa.c
+++ b/audio/drivers/tinyalsa.c
@@ -64,7 +64,7 @@
#include
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
/* Implementation tinyalsa pcm */
diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c
index d0729bd023..5f47fd2dd8 100644
--- a/audio/drivers/wasapi.c
+++ b/audio/drivers/wasapi.c
@@ -22,7 +22,7 @@
#include "../common/mmdevice_common.h"
#include "../common/mmdevice_common_inline.h"
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
#include "../../configuration.h"
diff --git a/audio/drivers/wiiu_audio.c b/audio/drivers/wiiu_audio.c
index f493721780..de5d3d9353 100644
--- a/audio/drivers/wiiu_audio.c
+++ b/audio/drivers/wiiu_audio.c
@@ -24,7 +24,7 @@
#include "../../wiiu/wiiu_dbg.h"
#include "../../wiiu/system/memory.h"
-#include "../../retroarch.h"
+#include "../audio_driver.h"
typedef struct
{
diff --git a/audio/drivers/xaudio.c b/audio/drivers/xaudio.c
index e9f7f8bb96..59fbf5d15e 100644
--- a/audio/drivers/xaudio.c
+++ b/audio/drivers/xaudio.c
@@ -42,7 +42,7 @@
#include "../common/mmdevice_common.h"
#endif
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#include "../../verbosity.h"
typedef struct xaudio2 xaudio2_t;
diff --git a/audio/drivers/xenon360_audio.c b/audio/drivers/xenon360_audio.c
index 11525d929e..98a71443f2 100644
--- a/audio/drivers/xenon360_audio.c
+++ b/audio/drivers/xenon360_audio.c
@@ -21,7 +21,7 @@
#include
-#include "../../retroarch.h"
+#include "../audio_driver.h"
#define SOUND_FREQUENCY 48000
#define MAX_BUFFER 2048
diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c
index bca7b14f0b..4585e3b0ac 100644
--- a/cheevos/cheevos.c
+++ b/cheevos/cheevos.c
@@ -54,6 +54,7 @@
#include "cheevos_locals.h"
#include "cheevos_parser.h"
+#include "../audio/audio_driver.h"
#include "../file_path_special.h"
#include "../paths.h"
#include "../command.h"
diff --git a/command.c b/command.c
index 0cd85fd6c0..ffc761502e 100644
--- a/command.c
+++ b/command.c
@@ -44,6 +44,7 @@
#include "network/netplay/netplay.h"
#endif
+#include "audio/audio_driver.h"
#include "command.h"
#include "cheat_manager.h"
#include "content.h"
diff --git a/configuration.c b/configuration.c
index a88be7d078..7b9af50662 100644
--- a/configuration.c
+++ b/configuration.c
@@ -46,6 +46,7 @@
#include "retroarch.h"
#include "verbosity.h"
+#include "audio/audio_driver.h"
#include "gfx/gfx_animation.h"
#include "tasks/task_content.h"
diff --git a/griffin/griffin.c b/griffin/griffin.c
index abb7c63482..f9b0f76c05 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -912,6 +912,7 @@ RSOUND
/*============================================================
AUDIO
============================================================ */
+#include "../audio/audio_driver.c"
#if defined(__PS3__) || defined (__PSL1GHT__)
#include "../audio/drivers/ps3_audio.c"
#elif defined(XENON)
diff --git a/menu/cbs/menu_cbs_cancel.c b/menu/cbs/menu_cbs_cancel.c
index 41b858f60c..aaa524ff0b 100644
--- a/menu/cbs/menu_cbs_cancel.c
+++ b/menu/cbs/menu_cbs_cancel.c
@@ -18,6 +18,7 @@
#include "../menu_driver.h"
#include "../menu_cbs.h"
+#include "../../audio/audio_driver.h"
#include "../../configuration.h"
#include "../../msg_hash.h"
#ifdef HAVE_CHEATS
diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c
index 7d63747cce..ae3bb30554 100644
--- a/menu/cbs/menu_cbs_get_value.c
+++ b/menu/cbs/menu_cbs_get_value.c
@@ -47,6 +47,7 @@
#include "../../playlist.h"
#include "../../manual_content_scan.h"
#include "../misc/cpufreq/cpufreq.h"
+#include "../../audio/audio_driver.h"
#ifdef HAVE_NETWORKING
#include "../../network/netplay/netplay.h"
diff --git a/menu/cbs/menu_cbs_info.c b/menu/cbs/menu_cbs_info.c
index 6c003353e6..a8cb00fcb3 100644
--- a/menu/cbs/menu_cbs_info.c
+++ b/menu/cbs/menu_cbs_info.c
@@ -20,6 +20,7 @@
#include "../menu_dialog.h"
#include "../../configuration.h"
+#include "../../audio/audio_driver.h"
#ifdef HAVE_NETWORKING
#include "../../network/netplay/netplay_discovery.h"
diff --git a/menu/cbs/menu_cbs_left.c b/menu/cbs/menu_cbs_left.c
index 50e522cb6f..35e7faedb4 100644
--- a/menu/cbs/menu_cbs_left.c
+++ b/menu/cbs/menu_cbs_left.c
@@ -40,6 +40,7 @@
#include "../../file_path_special.h"
#include "../../driver.h"
#include "../../retroarch.h"
+#include "../../audio/audio_driver.h"
#include "../../network/netplay/netplay.h"
#include "../../playlist.h"
#include "../../manual_content_scan.h"
diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c
index c39aef6dc7..0b78f67eca 100644
--- a/menu/cbs/menu_cbs_ok.c
+++ b/menu/cbs/menu_cbs_ok.c
@@ -55,6 +55,7 @@
#include "../../core.h"
#include "../../configuration.h"
#include "../../core_info.h"
+#include "../../audio/audio_driver.h"
#include "../../frontend/frontend_driver.h"
#include "../../defaults.h"
#include "../../core_option_manager.h"
diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c
index 7917f126ae..951fdcf322 100644
--- a/menu/cbs/menu_cbs_right.c
+++ b/menu/cbs/menu_cbs_right.c
@@ -39,6 +39,7 @@
#endif
#include "../../file_path_special.h"
#include "../../retroarch.h"
+#include "../../audio/audio_driver.h"
#include "../../verbosity.h"
#include "../../ui/ui_companion_driver.h"
#include "../../network/netplay/netplay.h"
diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c
index 789ab5045d..c884df9015 100644
--- a/menu/cbs/menu_cbs_start.c
+++ b/menu/cbs/menu_cbs_start.c
@@ -43,6 +43,7 @@
#include "../../playlist.h"
#include "../../manual_content_scan.h"
+#include "../../audio/audio_driver.h"
#include "../../input/input_remapping.h"
#include "../../config.def.h"
diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c
index f708b2fd42..2805f21d7e 100644
--- a/menu/cbs/menu_cbs_sublabel.c
+++ b/menu/cbs/menu_cbs_sublabel.c
@@ -29,6 +29,7 @@
#ifdef HAVE_CHEEVOS
#include "../../cheevos/cheevos_menu.h"
#endif
+#include "../../audio/audio_driver.h"
#include "../../core_info.h"
#include "../../verbosity.h"
#include "../../bluetooth/bluetooth_driver.h"
diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c
index 615d93e7f1..d6b7eeee40 100644
--- a/menu/cbs/menu_cbs_title.c
+++ b/menu/cbs/menu_cbs_title.c
@@ -31,6 +31,8 @@
#include "../../cheevos/cheevos.h"
#endif
+#include "../../audio/audio_driver.h"
+
#ifndef BIND_ACTION_GET_TITLE
#define BIND_ACTION_GET_TITLE(cbs, name) (cbs)->action_get_title = (name)
#endif
diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c
index 57eeca4327..d0aa7b13a0 100644
--- a/menu/menu_displaylist.c
+++ b/menu/menu_displaylist.c
@@ -76,6 +76,7 @@
#include
#endif
+#include "../audio/audio_driver.h"
#include "menu_cbs.h"
#include "menu_driver.h"
#include "menu_entries.h"
diff --git a/menu/menu_setting.c b/menu/menu_setting.c
index cedcf94a8e..20027314f8 100644
--- a/menu/menu_setting.c
+++ b/menu/menu_setting.c
@@ -79,6 +79,7 @@
#include "../paths.h"
#include "../dynamic.h"
#include "../list_special.h"
+#include "../audio/audio_driver.h"
#include "../bluetooth/bluetooth_driver.h"
#include "../wifi/wifi_driver.h"
#include "../midi_driver.h"
diff --git a/retroarch.c b/retroarch.c
index e4942780a5..06b4a4e63a 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -86,14 +86,6 @@
#include
#include
#include
-#include
-#include
-#ifdef HAVE_AUDIOMIXER
-#include
-#endif
-#ifdef HAVE_DSP_FILTER
-#include
-#endif
#include
#include
#include
@@ -149,6 +141,7 @@
#include
+#include "audio/audio_driver.h"
#include "gfx/gfx_animation.h"
#include "gfx/gfx_display.h"
#include "gfx/gfx_thumbnail.h"
@@ -241,9 +234,6 @@
#ifdef HAVE_REWIND
#include "state_manager.h"
#endif
-#ifdef HAVE_AUDIOMIXER
-#include "tasks/task_audio_mixer.h"
-#endif
#include "tasks/task_content.h"
#include "tasks/task_file_transfer.h"
#include "tasks/task_powerstate.h"
@@ -259,10 +249,6 @@
#include "accessibility.h"
#endif
-#ifdef HAVE_THREADS
-#include "audio/audio_thread_wrapper.h"
-#endif
-
#if defined(HAVE_SDL) || defined(HAVE_SDL2) || defined(HAVE_SDL_DINGUX)
#include "SDL.h"
#endif
@@ -276,6 +262,10 @@
#include "lakka.h"
#endif
+/* Custom forward declarations */
+static bool recording_init(settings_t *settings, struct rarch_state *p_rarch);
+static bool recording_deinit(void);
+
static struct rarch_state rarch_st;
#ifdef HAVE_THREAD_STORAGE
@@ -331,6 +321,12 @@ static runloop_core_status_msg_t runloop_core_status_msg =
};
static runloop_state_t runloop_state;
+static recording_state_t recording_state;
+
+recording_state_t *recording_state_get_ptr(void)
+{
+ return &recording_state;
+}
/* GLOBAL POINTER GETTERS */
#ifdef HAVE_REWIND
@@ -4778,18 +4774,6 @@ bool command_set_shader(command_t *cmd, const char *arg)
/* TRANSLATION */
#ifdef HAVE_TRANSLATE
-/* TODO/FIXME - Doesn't currently work. Fix this. */
-static bool is_ai_service_speech_running(void)
-{
-#ifdef HAVE_AUDIOMIXER
- enum audio_mixer_state res = audio_driver_mixer_get_stream_state(10);
- bool ret = (res == AUDIO_STREAM_STATE_NONE) || (res == AUDIO_STREAM_STATE_STOPPED);
- if (!ret)
- return true;
-#endif
- return false;
-}
-
static void task_auto_translate_handler(retro_task_t *task)
{
int *mode_ptr = (int*)task->user_data;
@@ -4805,7 +4789,7 @@ static void task_auto_translate_handler(retro_task_t *task)
{
case 1: /* Speech Mode */
#ifdef HAVE_AUDIOMIXER
- if (!is_ai_service_speech_running())
+ if (!audio_driver_is_ai_service_speech_running())
goto task_finished;
#endif
break;
@@ -7478,8 +7462,12 @@ bool command_event(enum event_command cmd, void *data)
path_clear(RARCH_PATH_CORE);
retroarch_system_info_free(&runloop_state);
#endif
- p_rarch->audio_callback.callback = NULL;
- p_rarch->audio_callback.set_state = NULL;
+ {
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
+ audio_st->callback.callback = NULL;
+ audio_st->callback.set_state = NULL;
+ }
if (is_inited)
{
subsystem_current_count = 0;
@@ -7595,30 +7583,32 @@ bool command_event(enum event_command cmd, void *data)
break;
case CMD_EVENT_AUDIO_STOP:
midi_driver_set_all_sounds_off();
- if (!audio_driver_stop(p_rarch))
+ if (!audio_driver_stop())
return false;
break;
case CMD_EVENT_AUDIO_START:
- if (!audio_driver_start(p_rarch,
+ if (!audio_driver_start(
runloop_state.shutdown_initiated))
return false;
break;
case CMD_EVENT_AUDIO_MUTE_TOGGLE:
{
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
bool audio_mute_enable =
*(audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE));
const char *msg = !audio_mute_enable ?
msg_hash_to_str(MSG_AUDIO_MUTED):
msg_hash_to_str(MSG_AUDIO_UNMUTED);
- p_rarch->audio_driver_mute_enable =
- !p_rarch->audio_driver_mute_enable;
+ audio_st->mute_enable =
+ !audio_st->mute_enable;
#if defined(HAVE_GFX_WIDGETS)
if (p_rarch->widgets_active)
gfx_widget_volume_update_and_show(
settings->floats.audio_volume,
- p_rarch->audio_driver_mute_enable);
+ audio_st->mute_enable);
else
#endif
runloop_msg_queue_push(msg, 1, 180, true, NULL,
@@ -7679,13 +7669,13 @@ bool command_event(enum event_command cmd, void *data)
#endif
break;
case CMD_EVENT_RECORD_DEINIT:
- p_rarch->recording_enable = false;
+ recording_state.enable = false;
streaming_set_state(false);
- if (!recording_deinit(p_rarch))
+ if (!recording_deinit())
return false;
break;
case CMD_EVENT_RECORD_INIT:
- p_rarch->recording_enable = true;
+ recording_state.enable = true;
if (!recording_init(settings, p_rarch))
{
command_event(CMD_EVENT_RECORD_DEINIT, NULL);
@@ -8363,6 +8353,8 @@ bool command_event(enum event_command cmd, void *data)
#endif
case CMD_EVENT_FULLSCREEN_TOGGLE:
{
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
input_driver_state_t
*input_st = input_state_get_ptr();
bool *userdata = (bool*)data;
@@ -8373,7 +8365,7 @@ bool command_event(enum event_command cmd, void *data)
if (!video_driver_has_windowed())
return false;
- p_rarch->audio_suspended = true;
+ audio_st->suspended = true;
p_rarch->rarch_is_switching_display_mode = true;
/* we toggled manually, write the new value to settings */
@@ -8405,7 +8397,7 @@ bool command_event(enum event_command cmd, void *data)
}
p_rarch->rarch_is_switching_display_mode = false;
- p_rarch->audio_suspended = false;
+ audio_st->suspended = false;
if (userdata && *userdata == true)
video_driver_cached_frame();
@@ -8705,13 +8697,17 @@ bool command_event(enum event_command cmd, void *data)
}
break;
case CMD_EVENT_VOLUME_UP:
- command_event_set_volume(settings, 0.5f,
+ {
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
+ command_event_set_volume(settings, 0.5f,
#if defined(HAVE_GFX_WIDGETS)
- p_rarch->widgets_active,
+ p_rarch->widgets_active,
#else
- false,
+ false,
#endif
- p_rarch->audio_driver_mute_enable);
+ audio_st->mute_enable);
+ }
break;
case CMD_EVENT_VOLUME_DOWN:
command_event_set_volume(settings, -0.5f,
@@ -8720,7 +8716,7 @@ bool command_event(enum event_command cmd, void *data)
#else
false,
#endif
- p_rarch->audio_driver_mute_enable
+ audio_state_get_ptr()->mute_enable
);
break;
case CMD_EVENT_MIXER_VOLUME_UP:
@@ -8780,7 +8776,7 @@ bool command_event(enum event_command cmd, void *data)
unsigned ai_service_mode = settings->uints.ai_service_mode;
#ifdef HAVE_AUDIOMIXER
- if (ai_service_mode == 1 && is_ai_service_speech_running())
+ if (ai_service_mode == 1 && audio_driver_is_ai_service_speech_running())
{
audio_driver_mixer_stop_stream(10);
audio_driver_mixer_remove_stream(10);
@@ -9212,7 +9208,7 @@ int rarch_main(int argc, char *argv[], void *data)
sthread_tls_set(&p_rarch->rarch_tls, MAGIC_POINTER);
#endif
p_rarch->video_driver_active = true;
- p_rarch->audio_driver_active = true;
+ audio_state_get_ptr()->active = true;
{
uint8_t i;
@@ -9823,12 +9819,10 @@ static bool mmap_preprocess_descriptors(
static bool rarch_clear_all_thread_waits(
unsigned clear_threads, void *data)
{
- struct rarch_state *p_rarch = &rarch_st;
- if ( clear_threads > 0)
- audio_driver_start(p_rarch,
- false);
+ if (clear_threads > 0)
+ audio_driver_start(false);
else
- audio_driver_stop(p_rarch);
+ audio_driver_stop();
return true;
}
@@ -11107,16 +11101,19 @@ static bool retroarch_environment_cb(unsigned cmd, void *data)
case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK:
#ifdef HAVE_THREADS
{
- const struct retro_audio_callback *cb = (const struct retro_audio_callback*)data;
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
+ const struct
+ retro_audio_callback *cb = (const struct retro_audio_callback*)data;
RARCH_LOG("[Environ]: SET_AUDIO_CALLBACK.\n");
#ifdef HAVE_NETWORKING
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
return false;
#endif
- if (p_rarch->recording_data) /* A/V sync is a must. */
+ if (recording_state.data) /* A/V sync is a must. */
return false;
if (cb)
- p_rarch->audio_callback = *cb;
+ audio_st->callback = *cb;
}
break;
#else
@@ -11204,7 +11201,7 @@ static bool retroarch_environment_cb(unsigned cmd, void *data)
/* Cannot continue recording with different parameters.
* Take the easiest route out and just restart the recording. */
- if (p_rarch->recording_data)
+ if (recording_state.data)
{
runloop_msg_queue_push(
msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
@@ -11433,7 +11430,7 @@ static bool retroarch_environment_cb(unsigned cmd, void *data)
/* Cannot continue recording with different parameters.
* Take the easiest route out and just restart the recording. */
- if (p_rarch->recording_data)
+ if (recording_state.data)
{
runloop_msg_queue_push(
msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
@@ -11779,17 +11776,19 @@ static bool retroarch_environment_cb(unsigned cmd, void *data)
case RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE:
{
- int result = 0;
- if ( !p_rarch->audio_suspended &&
- p_rarch->audio_driver_active)
+ int result = 0;
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
+ if ( !audio_st->suspended &&
+ audio_st->active)
result |= 2;
- if (p_rarch->video_driver_active
+ if ( p_rarch->video_driver_active
&& !(p_rarch->current_video->frame == video_null.frame))
result |= 1;
#ifdef HAVE_RUNAHEAD
if (p_rarch->request_fast_savestate)
result |= 4;
- if (p_rarch->hard_disable_audio)
+ if (audio_st->hard_disable)
result |= 8;
#endif
#ifdef HAVE_NETWORKING
@@ -12323,6 +12322,8 @@ static void uninit_libretro_symbols(
{
input_driver_state_t
*input_st = input_state_get_ptr();
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
#ifdef HAVE_DYNAMIC
if (p_rarch->lib_handle)
dylib_close(p_rarch->lib_handle);
@@ -12339,13 +12340,13 @@ static void uninit_libretro_symbols(
runloop_state.game_options_active,
path_get(RARCH_PATH_CORE_OPTIONS),
runloop_state.core_options);
- runloop_state.game_options_active = false;
- runloop_state.folder_options_active = false;
- runloop_state.core_options = NULL;
+ runloop_state.game_options_active = false;
+ runloop_state.folder_options_active = false;
+ runloop_state.core_options = NULL;
}
retroarch_system_info_free(&runloop_state);
- p_rarch->audio_callback.callback = NULL;
- p_rarch->audio_callback.set_state = NULL;
+ audio_st->callback.callback = NULL;
+ audio_st->callback.set_state = NULL;
retroarch_frame_time_free();
retroarch_audio_buffer_status_free();
input_game_focus_free();
@@ -13454,16 +13455,16 @@ const char* config_get_record_driver_options(void)
#if 0
/* TODO/FIXME - not used apparently */
-static void find_record_driver(struct rarch_state *p_rarch, const char *prefix,
+static void find_record_driver(const char *prefix,
bool verbosity_enabled)
{
- settings_t *settings = p_rarch->configuration_settings;
+ settings_t *settings = config_get_ptr();
int i = (int)driver_find_index(
"record_driver",
settings->arrays.record_driver);
if (i >= 0)
- p_rarch->recording_driver = (const record_driver_t*)record_drivers[i];
+ recording_state.driver = (const record_driver_t*)record_drivers[i];
else
{
if (verbosity_enabled)
@@ -13478,9 +13479,9 @@ static void find_record_driver(struct rarch_state *p_rarch, const char *prefix,
RARCH_WARN("[recording] Going to default to first %s...\n", prefix);
}
- p_rarch->recording_driver = (const record_driver_t*)record_drivers[0];
+ recording_state.driver = (const record_driver_t*)record_drivers[0];
- if (!p_rarch->recording_driver)
+ if (!recording_state.driver)
retroarch_fail(p_rarch, 1, "find_record_driver()");
}
}
@@ -13507,13 +13508,13 @@ static const record_driver_t *ffemu_find_backend(const char *ident)
return NULL;
}
-static void recording_driver_free_state(struct rarch_state *p_rarch)
+static void recording_driver_free_state(void)
{
/* TODO/FIXME - this is not being called anywhere */
- p_rarch->recording_gpu_width = 0;
- p_rarch->recording_gpu_height = 0;
- p_rarch->recording_width = 0;
- p_rarch->recording_height = 0;
+ recording_state.gpu_width = 0;
+ recording_state.gpu_height = 0;
+ recording_state.width = 0;
+ recording_stte.height = 0;
}
#endif
@@ -13585,8 +13586,8 @@ static void recording_dump_frame(
}
/* User has resized. We kinda have a problem now. */
- if ( vp.width != p_rarch->recording_gpu_width ||
- vp.height != p_rarch->recording_gpu_height)
+ if ( vp.width != recording_state.gpu_width ||
+ vp.height != recording_state.gpu_height)
{
RARCH_WARN("[recording] %s\n",
msg_hash_to_str(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE));
@@ -13605,9 +13606,9 @@ static void recording_dump_frame(
if (!video_driver_read_viewport(p_rarch->video_driver_record_gpu_buffer, is_idle))
return;
- ffemu_data.pitch = (int)(p_rarch->recording_gpu_width * 3);
- ffemu_data.width = (unsigned)p_rarch->recording_gpu_width;
- ffemu_data.height = (unsigned)p_rarch->recording_gpu_height;
+ ffemu_data.pitch = (int)(recording_state.gpu_width * 3);
+ ffemu_data.width = (unsigned)recording_state.gpu_width;
+ ffemu_data.height = (unsigned)recording_state.gpu_height;
ffemu_data.data = p_rarch->video_driver_record_gpu_buffer + (ffemu_data.height - 1) * ffemu_data.pitch;
ffemu_data.pitch = -ffemu_data.pitch;
@@ -13615,32 +13616,31 @@ static void recording_dump_frame(
else
ffemu_data.is_dupe = !data;
- p_rarch->recording_driver->push_video(p_rarch->recording_data, &ffemu_data);
+ recording_state.driver->push_video(recording_state.data, &ffemu_data);
}
-static bool recording_deinit(struct rarch_state *p_rarch)
+static bool recording_deinit(void)
{
- if (!p_rarch->recording_data || !p_rarch->recording_driver)
+ if (!recording_state.data || !recording_state.driver)
return false;
- if (p_rarch->recording_driver->finalize)
- p_rarch->recording_driver->finalize(p_rarch->recording_data);
+ if (recording_state.driver->finalize)
+ recording_state.driver->finalize(recording_state.data);
- if (p_rarch->recording_driver->free)
- p_rarch->recording_driver->free(p_rarch->recording_data);
+ if (recording_state.driver->free)
+ recording_state.driver->free(recording_state.data);
- p_rarch->recording_data = NULL;
- p_rarch->recording_driver = NULL;
+ recording_state.data = NULL;
+ recording_state.driver = NULL;
- video_driver_gpu_record_deinit(p_rarch);
+ video_driver_gpu_record_deinit(&rarch_st);
return true;
}
bool recording_is_enabled(void)
{
- struct rarch_state *p_rarch = &rarch_st;
- return p_rarch->recording_enable;
+ return recording_state.enable;
}
bool streaming_is_enabled(void)
@@ -13684,7 +13684,7 @@ static bool recording_init(
current_core_type = p_rarch->current_core_type;
const enum retro_pixel_format
video_driver_pix_fmt = p_rarch->video_driver_pix_fmt;
- bool recording_enable = p_rarch->recording_enable;
+ bool recording_enable = recording_state.enable;
if (!recording_enable)
return false;
@@ -13833,8 +13833,8 @@ static bool recording_init(
params.aspect_ratio = (float)vp.width / vp.height;
params.pix_fmt = FFEMU_PIX_BGR24;
- p_rarch->recording_gpu_width = vp.width;
- p_rarch->recording_gpu_height = vp.height;
+ recording_state.gpu_width = vp.width;
+ recording_state.gpu_height = vp.height;
RARCH_LOG("[recording] %s %u x %u\n", msg_hash_to_str(MSG_DETECTED_VIEWPORT_OF),
vp.width, vp.height);
@@ -13845,10 +13845,10 @@ static bool recording_init(
}
else
{
- if (p_rarch->recording_width || p_rarch->recording_height)
+ if (recording_state.width || recording_state.height)
{
- params.out_width = p_rarch->recording_width;
- params.out_height = p_rarch->recording_height;
+ params.out_width = recording_state.width;
+ params.out_height = recording_state.height;
}
if (video_force_aspect &&
@@ -13886,7 +13886,8 @@ static bool recording_init(
(unsigned)params.pix_fmt);
if (!record_driver_init_first(
- &p_rarch->recording_driver, &p_rarch->recording_data, ¶ms))
+ &recording_state.driver,
+ &recording_state.data, ¶ms))
{
RARCH_ERR("[recording] %s\n",
msg_hash_to_str(MSG_FAILED_TO_START_RECORDING));
@@ -15185,145 +15186,6 @@ void input_keyboard_event(bool down, unsigned code,
/* AUDIO */
-static enum resampler_quality audio_driver_get_resampler_quality(
- settings_t *settings)
-{
- if (settings)
- return (enum resampler_quality)settings->uints.audio_resampler_quality;
- return RESAMPLER_QUALITY_DONTCARE;
-}
-
-#ifdef HAVE_AUDIOMIXER
-audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
- return NULL;
- return &p_rarch->audio_mixer_streams[i];
-}
-
-const char *audio_driver_mixer_get_stream_name(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
- return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
- if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
- return p_rarch->audio_mixer_streams[i].name;
- return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
-}
-
-static void audio_driver_mixer_deinit(struct rarch_state *p_rarch)
-{
- unsigned i;
-
- p_rarch->audio_mixer_active = false;
-
- for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
- {
- audio_driver_mixer_stop_stream(i);
- audio_driver_mixer_remove_stream(i);
- }
-
- audio_mixer_done();
-}
-#endif
-
-/**
- * audio_compute_buffer_statistics:
- *
- * Computes audio buffer statistics.
- *
- **/
-static bool audio_compute_buffer_statistics(
- struct rarch_state *p_rarch,
- audio_statistics_t *stats)
-{
- unsigned i, low_water_size, high_water_size, avg, stddev;
- uint64_t accum = 0;
- uint64_t accum_var = 0;
- unsigned low_water_count = 0;
- unsigned high_water_count = 0;
- unsigned samples = MIN(
- (unsigned)p_rarch->audio_driver_free_samples_count,
- AUDIO_BUFFER_FREE_SAMPLES_COUNT);
-
- if (samples < 3)
- return false;
-
- stats->samples = (unsigned)
- p_rarch->audio_driver_free_samples_count;
-
-#ifdef WARPUP
- /* uint64 to double not implemented, fair chance
- * signed int64 to double doesn't exist either */
- /* https://forums.libretro.com/t/unsupported-platform-help/13903/ */
- (void)stddev;
-#elif defined(_MSC_VER) && _MSC_VER <= 1200
- /* FIXME: error C2520: conversion from unsigned __int64
- * to double not implemented, use signed __int64 */
- (void)stddev;
-#else
- for (i = 1; i < samples; i++)
- accum += p_rarch->audio_driver_free_samples_buf[i];
-
- avg = (unsigned)accum / (samples - 1);
-
- for (i = 1; i < samples; i++)
- {
- int diff = avg - p_rarch->audio_driver_free_samples_buf[i];
- accum_var += diff * diff;
- }
-
- stddev = (unsigned)
- sqrt((double)accum_var / (samples - 2));
-
- stats->average_buffer_saturation = (1.0f - (float)avg
- / p_rarch->audio_driver_buffer_size) * 100.0;
- stats->std_deviation_percentage = ((float)stddev
- / p_rarch->audio_driver_buffer_size) * 100.0;
-#endif
-
- low_water_size = (unsigned)(p_rarch->audio_driver_buffer_size * 3 / 4);
- high_water_size = (unsigned)(p_rarch->audio_driver_buffer_size / 4);
-
- for (i = 1; i < samples; i++)
- {
- if (p_rarch->audio_driver_free_samples_buf[i] >= low_water_size)
- low_water_count++;
- else if (p_rarch->audio_driver_free_samples_buf[i] <= high_water_size)
- high_water_count++;
- }
-
- stats->close_to_underrun = (100.0f * low_water_count) / (samples - 1);
- stats->close_to_blocking = (100.0f * high_water_count) / (samples - 1);
-
- return true;
-}
-
-#ifdef DEBUG
-static void report_audio_buffer_statistics(struct rarch_state *p_rarch)
-{
- audio_statistics_t audio_stats;
- audio_stats.samples = 0;
- audio_stats.average_buffer_saturation = 0.0f;
- audio_stats.std_deviation_percentage = 0.0f;
- audio_stats.close_to_underrun = 0.0f;
- audio_stats.close_to_blocking = 0.0f;
-
- if (!audio_compute_buffer_statistics(p_rarch, &audio_stats))
- return;
-
- RARCH_LOG("[Audio]: Average audio buffer saturation: %.2f %%,"
- " standard deviation (percentage points): %.2f %%.\n"
- "[Audio]: Amount of time spent close to underrun: %.2f %%."
- " Close to blocking: %.2f %%.\n",
- audio_stats.average_buffer_saturation,
- audio_stats.std_deviation_percentage,
- audio_stats.close_to_underrun,
- audio_stats.close_to_blocking);
-}
-#endif
-
/**
* config_get_audio_driver_options:
*
@@ -15336,608 +15198,63 @@ const char *config_get_audio_driver_options(void)
return char_list_new_special(STRING_LIST_AUDIO_DRIVERS, NULL);
}
-static void audio_driver_deinit_resampler(struct rarch_state *p_rarch)
-{
- if (p_rarch->audio_driver_resampler && p_rarch->audio_driver_resampler_data)
- p_rarch->audio_driver_resampler->free(p_rarch->audio_driver_resampler_data);
- p_rarch->audio_driver_resampler = NULL;
- p_rarch->audio_driver_resampler_data = NULL;
- p_rarch->audio_driver_resampler_ident[0] = '\0';
- p_rarch->audio_driver_resampler_quality = RESAMPLER_QUALITY_DONTCARE;
-}
-
-
-static bool audio_driver_deinit_internal(struct rarch_state *p_rarch,
- bool audio_enable)
-{
- if (p_rarch->current_audio && p_rarch->current_audio->free)
- {
- if (p_rarch->audio_driver_context_audio_data)
- p_rarch->current_audio->free(
- p_rarch->audio_driver_context_audio_data);
- p_rarch->audio_driver_context_audio_data = NULL;
- }
-
- if (p_rarch->audio_driver_output_samples_conv_buf)
- memalign_free(p_rarch->audio_driver_output_samples_conv_buf);
- p_rarch->audio_driver_output_samples_conv_buf = NULL;
-
- if (p_rarch->audio_driver_input_data)
- memalign_free(p_rarch->audio_driver_input_data);
- p_rarch->audio_driver_input_data = NULL;
-
- p_rarch->audio_driver_data_ptr = 0;
-
-#ifdef HAVE_REWIND
- if (p_rarch->audio_driver_rewind_buf)
- memalign_free(p_rarch->audio_driver_rewind_buf);
- p_rarch->audio_driver_rewind_buf = NULL;
-
- p_rarch->audio_driver_rewind_size = 0;
-#endif
-
- if (!audio_enable)
- {
- p_rarch->audio_driver_active = false;
- return false;
- }
-
- audio_driver_deinit_resampler(p_rarch);
-
- if (p_rarch->audio_driver_output_samples_buf)
- memalign_free(p_rarch->audio_driver_output_samples_buf);
- p_rarch->audio_driver_output_samples_buf = NULL;
-
-#ifdef HAVE_DSP_FILTER
- audio_driver_dsp_filter_free();
-#endif
-#ifdef DEBUG
- report_audio_buffer_statistics(p_rarch);
-#endif
-
- return true;
-}
-
-static bool audio_driver_free_devices_list(struct rarch_state *p_rarch)
-{
- if (!p_rarch->current_audio || !p_rarch->current_audio->device_list_free
- || !p_rarch->audio_driver_context_audio_data)
- return false;
- p_rarch->current_audio->device_list_free(
- p_rarch->audio_driver_context_audio_data,
- p_rarch->audio_driver_devices_list);
- p_rarch->audio_driver_devices_list = NULL;
- return true;
-}
-
-static bool audio_driver_deinit(struct rarch_state *p_rarch,
- settings_t *settings)
-{
-#ifdef HAVE_AUDIOMIXER
- audio_driver_mixer_deinit(p_rarch);
-#endif
- audio_driver_free_devices_list(p_rarch);
-
- return audio_driver_deinit_internal(p_rarch,
- settings->bools.audio_enable);
-}
-
-static bool audio_driver_find_driver(struct rarch_state *p_rarch,
- settings_t *settings,
- const char *prefix,
- bool verbosity_enabled)
-{
- int i = (int)driver_find_index(
- "audio_driver",
- settings->arrays.audio_driver);
-
- if (i >= 0)
- p_rarch->current_audio = (const audio_driver_t*)
- audio_drivers[i];
- else
- {
- const audio_driver_t *tmp = NULL;
- if (verbosity_enabled)
- {
- unsigned d;
- RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
- settings->arrays.audio_driver);
- RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
- for (d = 0; audio_drivers[d]; d++)
- {
- if (audio_drivers[d])
- RARCH_LOG_OUTPUT("\t%s\n", audio_drivers[d]->ident);
- }
- RARCH_WARN("Going to default to first %s...\n", prefix);
- }
-
- tmp = (const audio_driver_t*)audio_drivers[0];
-
- if (!tmp)
- return false;
- p_rarch->current_audio = tmp;
- }
-
- return true;
-}
-
-static bool audio_driver_init_internal(
- struct rarch_state *p_rarch,
- settings_t *settings,
- bool audio_cb_inited)
-{
- unsigned new_rate = 0;
- float *samples_buf = NULL;
- size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
- bool audio_enable = settings->bools.audio_enable;
- bool audio_sync = settings->bools.audio_sync;
- bool audio_rate_control = settings->bools.audio_rate_control;
- float slowmotion_ratio = settings->floats.slowmotion_ratio;
- unsigned audio_latency = (runloop_state.audio_latency > settings->uints.audio_latency) ?
- runloop_state.audio_latency : settings->uints.audio_latency;
-#ifdef HAVE_REWIND
- int16_t *rewind_buf = NULL;
-#endif
- /* Accomodate rewind since at some point we might have two full buffers. */
- size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO * slowmotion_ratio;
- int16_t *conv_buf = (int16_t*)memalign_alloc(64, outsamples_max * sizeof(int16_t));
- float *audio_buf = (float*)memalign_alloc(64, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
- bool verbosity_enabled = verbosity_is_enabled();
-
- convert_s16_to_float_init_simd();
- convert_float_to_s16_init_simd();
-
- /* Used for recording even if audio isn't enabled. */
- retro_assert(conv_buf != NULL);
- retro_assert(audio_buf != NULL);
-
- if (!conv_buf || !audio_buf)
- goto error;
-
- memset(audio_buf, 0, AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * sizeof(float));
-
- p_rarch->audio_driver_input_data = audio_buf;
- p_rarch->audio_driver_output_samples_conv_buf = conv_buf;
- p_rarch->audio_driver_chunk_block_size = AUDIO_CHUNK_SIZE_BLOCKING;
- p_rarch->audio_driver_chunk_nonblock_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
- p_rarch->audio_driver_chunk_size = p_rarch->audio_driver_chunk_block_size;
-
-#ifdef HAVE_REWIND
- /* Needs to be able to hold full content of a full max_bufsamples
- * in addition to its own. */
- rewind_buf = (int16_t*)memalign_alloc(64, max_bufsamples * sizeof(int16_t));
- retro_assert(rewind_buf != NULL);
-
- if (!rewind_buf)
- goto error;
-
- p_rarch->audio_driver_rewind_buf = rewind_buf;
- p_rarch->audio_driver_rewind_size = max_bufsamples;
-#endif
-
- if (!audio_enable)
- {
- p_rarch->audio_driver_active = false;
- return false;
- }
-
- if (!(audio_driver_find_driver(p_rarch, settings,
- "audio driver", verbosity_enabled)))
- retroarch_fail(p_rarch, 1, "audio_driver_find()");
-
- if (!p_rarch->current_audio || !p_rarch->current_audio->init)
- {
- RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
- p_rarch->audio_driver_active = false;
- return false;
- }
-
-#ifdef HAVE_THREADS
- if (audio_cb_inited)
- {
- RARCH_LOG("[Audio]: Starting threaded audio driver ...\n");
- if (!audio_init_thread(
- &p_rarch->current_audio,
- &p_rarch->audio_driver_context_audio_data,
- *settings->arrays.audio_device
- ? settings->arrays.audio_device : NULL,
- settings->uints.audio_output_sample_rate, &new_rate,
- audio_latency,
- settings->uints.audio_block_frames,
- p_rarch->current_audio))
- {
- RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
- retroarch_fail(p_rarch, 1, "audio_driver_init_internal()");
- }
- }
- else
-#endif
- {
- p_rarch->audio_driver_context_audio_data =
- p_rarch->current_audio->init(*settings->arrays.audio_device ?
- settings->arrays.audio_device : NULL,
- settings->uints.audio_output_sample_rate,
- audio_latency,
- settings->uints.audio_block_frames,
- &new_rate);
- }
-
- if (new_rate != 0)
- configuration_set_int(settings, settings->uints.audio_output_sample_rate, new_rate);
-
- if (!p_rarch->audio_driver_context_audio_data)
- {
- RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
- p_rarch->audio_driver_active = false;
- }
-
- p_rarch->audio_driver_use_float = false;
- if ( p_rarch->audio_driver_active
- && p_rarch->current_audio->use_float(
- p_rarch->audio_driver_context_audio_data))
- p_rarch->audio_driver_use_float = true;
-
- if (!audio_sync && p_rarch->audio_driver_active)
- {
- if (p_rarch->audio_driver_active &&
- p_rarch->audio_driver_context_audio_data)
- p_rarch->current_audio->set_nonblock_state(
- p_rarch->audio_driver_context_audio_data, true);
-
- p_rarch->audio_driver_chunk_size =
- p_rarch->audio_driver_chunk_nonblock_size;
- }
-
- if (p_rarch->audio_driver_input <= 0.0f)
- {
- /* Should never happen. */
- RARCH_WARN("[Audio]: Input rate is invalid (%.3f Hz)."
- " Using output rate (%u Hz).\n",
- p_rarch->audio_driver_input, settings->uints.audio_output_sample_rate);
-
- p_rarch->audio_driver_input = settings->uints.audio_output_sample_rate;
- }
-
- p_rarch->audio_source_ratio_original =
- p_rarch->audio_source_ratio_current =
- (double)settings->uints.audio_output_sample_rate / p_rarch->audio_driver_input;
-
- if (!string_is_empty(settings->arrays.audio_resampler))
- strlcpy(p_rarch->audio_driver_resampler_ident,
- settings->arrays.audio_resampler,
- sizeof(p_rarch->audio_driver_resampler_ident));
- else
- p_rarch->audio_driver_resampler_ident[0] = '\0';
-
- p_rarch->audio_driver_resampler_quality =
- audio_driver_get_resampler_quality(settings);
-
- if (!retro_resampler_realloc(
- &p_rarch->audio_driver_resampler_data,
- &p_rarch->audio_driver_resampler,
- p_rarch->audio_driver_resampler_ident,
- p_rarch->audio_driver_resampler_quality,
- p_rarch->audio_source_ratio_original))
- {
- RARCH_ERR("Failed to initialize resampler \"%s\".\n",
- p_rarch->audio_driver_resampler_ident);
- p_rarch->audio_driver_active = false;
- }
-
- p_rarch->audio_driver_data_ptr = 0;
-
- retro_assert(settings->uints.audio_output_sample_rate <
- p_rarch->audio_driver_input * AUDIO_MAX_RATIO);
-
- samples_buf = (float*)memalign_alloc(64, outsamples_max * sizeof(float));
-
- retro_assert(samples_buf != NULL);
-
- if (!samples_buf)
- goto error;
-
- p_rarch->audio_driver_output_samples_buf = (float*)samples_buf;
- p_rarch->audio_driver_control = false;
-
- if (
- !audio_cb_inited
- && p_rarch->audio_driver_active
- && audio_rate_control
- )
- {
- /* Audio rate control requires write_avail
- * and buffer_size to be implemented. */
- if (p_rarch->current_audio->buffer_size)
- {
- p_rarch->audio_driver_buffer_size =
- p_rarch->current_audio->buffer_size(
- p_rarch->audio_driver_context_audio_data);
- p_rarch->audio_driver_control = true;
- }
- else
- RARCH_WARN("[Audio]: Rate control was desired, but driver does not support needed features.\n");
- }
-
- command_event(CMD_EVENT_DSP_FILTER_INIT, NULL);
-
- p_rarch->audio_driver_free_samples_count = 0;
-
-#ifdef HAVE_AUDIOMIXER
- audio_mixer_init(settings->uints.audio_output_sample_rate);
-#endif
-
- /* Threaded driver is initially stopped. */
- if (
- p_rarch->audio_driver_active
- && audio_cb_inited
- )
- audio_driver_start(p_rarch,
- false);
-
- return true;
-
-error:
- return audio_driver_deinit(p_rarch, settings);
-}
-
-/**
- * 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.
- **/
-static void audio_driver_flush(
- struct rarch_state *p_rarch,
- float slowmotion_ratio,
- bool audio_fastforward_mute,
- const int16_t *data, size_t samples,
- bool is_slowmotion, bool is_fastmotion)
-{
- struct resampler_data src_data;
- float audio_volume_gain = (p_rarch->audio_driver_mute_enable ||
- (audio_fastforward_mute && is_fastmotion)) ?
- 0.0f : p_rarch->audio_driver_volume_gain;
-
- src_data.data_out = NULL;
- src_data.output_frames = 0;
-
- convert_s16_to_float(p_rarch->audio_driver_input_data, data, samples,
- audio_volume_gain);
-
- src_data.data_in = p_rarch->audio_driver_input_data;
- src_data.input_frames = samples >> 1;
-
-#ifdef HAVE_DSP_FILTER
- if (p_rarch->audio_driver_dsp)
- {
- struct retro_dsp_data dsp_data;
-
- dsp_data.input = NULL;
- dsp_data.input_frames = 0;
- dsp_data.output = NULL;
- dsp_data.output_frames = 0;
-
- dsp_data.input = p_rarch->audio_driver_input_data;
- dsp_data.input_frames = (unsigned)(samples >> 1);
-
- retro_dsp_filter_process(p_rarch->audio_driver_dsp, &dsp_data);
-
- if (dsp_data.output)
- {
- src_data.data_in = dsp_data.output;
- src_data.input_frames = dsp_data.output_frames;
- }
- }
-#endif
-
- src_data.data_out = p_rarch->audio_driver_output_samples_buf;
-
- if (p_rarch->audio_driver_control)
- {
- /* Readjust the audio input rate. */
- int half_size =
- (int)(p_rarch->audio_driver_buffer_size / 2);
- int avail =
- (int)p_rarch->current_audio->write_avail(
- p_rarch->audio_driver_context_audio_data);
- int delta_mid = avail - half_size;
- double direction = (double)delta_mid / half_size;
- double adjust = 1.0 +
- p_rarch->audio_driver_rate_control_delta * direction;
- unsigned write_idx =
- p_rarch->audio_driver_free_samples_count++ &
- (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
-
- p_rarch->audio_driver_free_samples_buf
- [write_idx] = avail;
- p_rarch->audio_source_ratio_current =
- p_rarch->audio_source_ratio_original * adjust;
-
-#if 0
- if (verbosity_is_enabled())
- {
- RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n",
- (unsigned)(100 - (avail * 100) /
- p_rarch->audio_driver_buffer_size));
- RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
- p_rarch->audio_source_ratio_current,
- p_rarch->audio_source_ratio_original);
- }
-#endif
- }
-
- src_data.ratio = p_rarch->audio_source_ratio_current;
-
- if (is_slowmotion)
- src_data.ratio *= slowmotion_ratio;
-
- /* Note: Ideally we would divide by the user-configured
- * 'fastforward_ratio' when fast forward is enabled,
- * but in practice this doesn't work:
- * - 'fastforward_ratio' is only a limit. If the host
- * cannot push frames fast enough, the actual ratio
- * will be lower - and crackling will ensue
- * - Most of the time 'fastforward_ratio' will be
- * zero (unlimited)
- * So what we would need to do is measure the time since
- * the last audio flush operation, and calculate a 'real'
- * fast-forward ratio - but this doesn't work either.
- * The measurement is inaccurate and the frame-by-frame
- * fluctuations are too large, so crackling is unavoidable.
- * Since it's going to crackle anyway, there's no point
- * trying to do anything. Just leave the ratio as-is,
- * and hope for the best... */
-
- p_rarch->audio_driver_resampler->process(
- p_rarch->audio_driver_resampler_data, &src_data);
-
-#ifdef HAVE_AUDIOMIXER
- if (p_rarch->audio_mixer_active)
- {
- bool override = true;
- float mixer_gain = 0.0f;
- bool audio_driver_mixer_mute_enable =
- p_rarch->audio_driver_mixer_mute_enable;
-
- if (!audio_driver_mixer_mute_enable)
- {
- if (p_rarch->audio_driver_mixer_volume_gain == 1.0f)
- override = false;
- mixer_gain =
- p_rarch->audio_driver_mixer_volume_gain;
- }
- audio_mixer_mix(
- p_rarch->audio_driver_output_samples_buf,
- src_data.output_frames, mixer_gain, override);
- }
-#endif
-
- {
- const void *output_data = p_rarch->audio_driver_output_samples_buf;
- unsigned output_frames = (unsigned)src_data.output_frames;
-
- if (p_rarch->audio_driver_use_float)
- output_frames *= sizeof(float);
- else
- {
- convert_float_to_s16(p_rarch->audio_driver_output_samples_conv_buf,
- (const float*)output_data, output_frames * 2);
-
- output_data = p_rarch->audio_driver_output_samples_conv_buf;
- output_frames *= sizeof(int16_t);
- }
-
- p_rarch->current_audio->write(
- p_rarch->audio_driver_context_audio_data,
- output_data, output_frames * 2);
- }
-}
-
-/**
- * audio_driver_sample:
- * @left : value of the left audio channel.
- * @right : value of the right audio channel.
- *
- * Audio sample render callback function.
- **/
-static void audio_driver_sample(int16_t left, int16_t right)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (p_rarch->audio_suspended)
- return;
- p_rarch->audio_driver_output_samples_conv_buf[p_rarch->audio_driver_data_ptr++] = left;
- p_rarch->audio_driver_output_samples_conv_buf[p_rarch->audio_driver_data_ptr++] = right;
-
- if (p_rarch->audio_driver_data_ptr < p_rarch->audio_driver_chunk_size)
- return;
-
- if ( p_rarch->recording_data &&
- p_rarch->recording_driver &&
- p_rarch->recording_driver->push_audio)
- {
- struct record_audio_data ffemu_data;
-
- ffemu_data.data = p_rarch->audio_driver_output_samples_conv_buf;
- ffemu_data.frames = p_rarch->audio_driver_data_ptr / 2;
-
- p_rarch->recording_driver->push_audio(p_rarch->recording_data, &ffemu_data);
- }
-
- if (!(runloop_state.paused ||
- !p_rarch->audio_driver_active ||
- !p_rarch->audio_driver_output_samples_buf))
- audio_driver_flush(
- p_rarch,
- p_rarch->configuration_settings->floats.slowmotion_ratio,
- p_rarch->configuration_settings->bools.audio_fastforward_mute,
- p_rarch->audio_driver_output_samples_conv_buf,
- p_rarch->audio_driver_data_ptr,
- runloop_state.slowmotion,
- runloop_state.fastmotion);
-
- p_rarch->audio_driver_data_ptr = 0;
-}
-
#ifdef HAVE_MENU
static void audio_driver_menu_sample(void)
{
static int16_t samples_buf[1024] = {0};
- struct rarch_state *p_rarch = &rarch_st;
- struct retro_system_av_info *av_info = &p_rarch->video_driver_av_info;
+ settings_t *settings = config_get_ptr();
+ struct retro_system_av_info *av_info = &rarch_st.video_driver_av_info;
const struct retro_system_timing *info =
(const struct retro_system_timing*)&av_info->timing;
unsigned sample_count = (info->sample_rate / info->fps) * 2;
+ audio_driver_state_t *audio_st = audio_state_get_ptr();
bool check_flush = !(
- runloop_state.paused ||
- !p_rarch->audio_driver_active ||
- !p_rarch->audio_driver_output_samples_buf);
- if (p_rarch->audio_suspended)
+ runloop_state.paused
+ || !audio_st->active
+ || !audio_st->output_samples_buf);
+ if (audio_st->suspended)
check_flush = false;
while (sample_count > 1024)
{
- if ( p_rarch->recording_data &&
- p_rarch->recording_driver &&
- p_rarch->recording_driver->push_audio)
+ if ( recording_state_get_ptr()->data &&
+ recording_state_get_ptr()->driver &&
+ recording_state_get_ptr()->driver->push_audio)
{
struct record_audio_data ffemu_data;
ffemu_data.data = samples_buf;
ffemu_data.frames = 1024 / 2;
- p_rarch->recording_driver->push_audio(
- p_rarch->recording_data, &ffemu_data);
+ recording_state_get_ptr()->driver->push_audio(
+ recording_state_get_ptr()->data, &ffemu_data);
}
if (check_flush)
audio_driver_flush(
- p_rarch,
- p_rarch->configuration_settings->floats.slowmotion_ratio,
- p_rarch->configuration_settings->bools.audio_fastforward_mute,
+ settings->floats.slowmotion_ratio,
+ settings->bools.audio_fastforward_mute,
samples_buf,
1024,
runloop_state.slowmotion,
runloop_state.fastmotion);
sample_count -= 1024;
}
- if ( p_rarch->recording_data &&
- p_rarch->recording_driver &&
- p_rarch->recording_driver->push_audio)
+ if ( recording_state_get_ptr()->data &&
+ recording_state_get_ptr()->driver &&
+ recording_state_get_ptr()->driver->push_audio)
{
struct record_audio_data ffemu_data;
ffemu_data.data = samples_buf;
ffemu_data.frames = sample_count / 2;
- p_rarch->recording_driver->push_audio(
- p_rarch->recording_data, &ffemu_data);
+ recording_state_get_ptr()->driver->push_audio(
+ recording_state_get_ptr()->data, &ffemu_data);
}
if (check_flush)
audio_driver_flush(
- p_rarch,
- p_rarch->configuration_settings->floats.slowmotion_ratio,
- p_rarch->configuration_settings->bools.audio_fastforward_mute,
+ settings->floats.slowmotion_ratio,
+ settings->bools.audio_fastforward_mute,
samples_buf,
sample_count,
runloop_state.slowmotion,
@@ -15945,1000 +15262,6 @@ static void audio_driver_menu_sample(void)
}
#endif
-/**
- * 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).
- **/
-static size_t audio_driver_sample_batch(const int16_t *data, size_t frames)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
- frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
- if (p_rarch->audio_suspended)
- return frames;
-
- if ( p_rarch->recording_data &&
- p_rarch->recording_driver &&
- p_rarch->recording_driver->push_audio)
- {
- struct record_audio_data ffemu_data;
-
- ffemu_data.data = data;
- ffemu_data.frames = (frames << 1) / 2;
-
- p_rarch->recording_driver->push_audio(
- p_rarch->recording_data, &ffemu_data);
- }
-
- if (!(
- runloop_state.paused ||
- !p_rarch->audio_driver_active ||
- !p_rarch->audio_driver_output_samples_buf))
- audio_driver_flush(
- p_rarch,
- p_rarch->configuration_settings->floats.slowmotion_ratio,
- p_rarch->configuration_settings->bools.audio_fastforward_mute,
- data,
- frames << 1,
- runloop_state.slowmotion,
- runloop_state.fastmotion);
-
- return frames;
-}
-
-#ifdef HAVE_REWIND
-/**
- * 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.
- **/
-static void audio_driver_sample_rewind(int16_t left, int16_t right)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (p_rarch->audio_driver_rewind_ptr == 0)
- return;
-
- p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = right;
- p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_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).
- **/
-static size_t audio_driver_sample_batch_rewind(
- const int16_t *data, size_t frames)
-{
- size_t i;
- struct rarch_state *p_rarch = &rarch_st;
- size_t samples = frames << 1;
-
- for (i = 0; i < samples; i++)
- {
- if (p_rarch->audio_driver_rewind_ptr > 0)
- p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] = data[i];
- }
-
- return frames;
-}
-#endif
-
-#ifdef HAVE_DSP_FILTER
-void audio_driver_dsp_filter_free(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (p_rarch->audio_driver_dsp)
- retro_dsp_filter_free(p_rarch->audio_driver_dsp);
- p_rarch->audio_driver_dsp = NULL;
-}
-
-bool audio_driver_dsp_filter_init(const char *device)
-{
- retro_dsp_filter_t *audio_driver_dsp = NULL;
- struct rarch_state *p_rarch = &rarch_st;
- struct string_list *plugs = NULL;
-#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
- char basedir[PATH_MAX_LENGTH];
- char ext_name[PATH_MAX_LENGTH];
-
- basedir[0] = ext_name[0] = '\0';
-
- fill_pathname_basedir(basedir, device, sizeof(basedir));
-
- if (!frontend_driver_get_core_extension(ext_name, sizeof(ext_name)))
- return false;
-
- plugs = dir_list_new(basedir, ext_name, false, true, false, false);
- if (!plugs)
- return false;
-#endif
- audio_driver_dsp = retro_dsp_filter_new(
- device, plugs, p_rarch->audio_driver_input);
- if (!audio_driver_dsp)
- return false;
-
- p_rarch->audio_driver_dsp = audio_driver_dsp;
-
- return true;
-}
-#endif
-
-void audio_driver_set_buffer_size(size_t bufsize)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_driver_buffer_size = bufsize;
-}
-
-static float audio_driver_monitor_adjust_system_rates(
- double input_sample_rate,
- double input_fps,
- float video_refresh_rate,
- unsigned video_swap_interval,
- float audio_max_timing_skew)
-{
- float inp_sample_rate = input_sample_rate;
- const float target_video_sync_rate = video_refresh_rate
- / video_swap_interval;
- float timing_skew =
- fabs(1.0f - input_fps / target_video_sync_rate);
- if (timing_skew <= audio_max_timing_skew)
- return (inp_sample_rate * target_video_sync_rate / input_fps);
- return inp_sample_rate;
-}
-
-#ifdef HAVE_REWIND
-void audio_driver_setup_rewind(void)
-{
- unsigned i;
- struct rarch_state *p_rarch = &rarch_st;
-
- /* Push audio ready to be played. */
- p_rarch->audio_driver_rewind_ptr = p_rarch->audio_driver_rewind_size;
-
- for (i = 0; i < p_rarch->audio_driver_data_ptr; i += 2)
- {
- if (p_rarch->audio_driver_rewind_ptr > 0)
- p_rarch->audio_driver_rewind_buf[
- --p_rarch->audio_driver_rewind_ptr] =
- p_rarch->audio_driver_output_samples_conv_buf[i + 1];
-
- if (p_rarch->audio_driver_rewind_ptr > 0)
- p_rarch->audio_driver_rewind_buf[--p_rarch->audio_driver_rewind_ptr] =
- p_rarch->audio_driver_output_samples_conv_buf[i + 0];
- }
-
- p_rarch->audio_driver_data_ptr = 0;
-}
-#endif
-
-
-bool audio_driver_get_devices_list(void **data)
-{
- struct rarch_state *p_rarch = &rarch_st;
- struct string_list**ptr = (struct string_list**)data;
- if (!ptr)
- return false;
- *ptr = p_rarch->audio_driver_devices_list;
- return true;
-}
-
-#ifdef HAVE_AUDIOMIXER
-bool audio_driver_mixer_extension_supported(const char *ext)
-{
- unsigned i;
- struct string_list str_list;
- union string_list_elem_attr attr;
- bool ret = false;
-
- attr.i = 0;
- if (!string_list_initialize(&str_list))
- return false;
-
-#ifdef HAVE_STB_VORBIS
- string_list_append(&str_list, "ogg", attr);
-#endif
-#ifdef HAVE_IBXM
- string_list_append(&str_list, "mod", attr);
- string_list_append(&str_list, "s3m", attr);
- string_list_append(&str_list, "xm", attr);
-#endif
-#ifdef HAVE_DR_FLAC
- string_list_append(&str_list, "flac", attr);
-#endif
-#ifdef HAVE_DR_MP3
- string_list_append(&str_list, "mp3", attr);
-#endif
- string_list_append(&str_list, "wav", attr);
-
- for (i = 0; i < str_list.size; i++)
- {
- const char *str_ext = str_list.elems[i].data;
- if (string_is_equal_noncase(str_ext, ext))
- {
- ret = true;
- break;
- }
- }
-
- string_list_deinitialize(&str_list);
-
- return ret;
-}
-
-static int audio_mixer_find_index(
- struct rarch_state *p_rarch,
- audio_mixer_sound_t *sound)
-{
- unsigned i;
-
- for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
- {
- audio_mixer_sound_t *handle = p_rarch->audio_mixer_streams[i].handle;
- if (handle == sound)
- return i;
- }
- return -1;
-}
-
-static void audio_mixer_play_stop_cb(
- audio_mixer_sound_t *sound, unsigned reason)
-{
- struct rarch_state *p_rarch = &rarch_st;
- int idx = audio_mixer_find_index(p_rarch, sound);
-
- switch (reason)
- {
- case AUDIO_MIXER_SOUND_FINISHED:
- audio_mixer_destroy(sound);
-
- if (idx >= 0)
- {
- unsigned i = (unsigned)idx;
-
- if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
- free(p_rarch->audio_mixer_streams[i].name);
-
- p_rarch->audio_mixer_streams[i].name = NULL;
- p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
- p_rarch->audio_mixer_streams[i].volume = 0.0f;
- p_rarch->audio_mixer_streams[i].buf = NULL;
- p_rarch->audio_mixer_streams[i].stop_cb = NULL;
- p_rarch->audio_mixer_streams[i].handle = NULL;
- p_rarch->audio_mixer_streams[i].voice = NULL;
- }
- break;
- case AUDIO_MIXER_SOUND_STOPPED:
- break;
- case AUDIO_MIXER_SOUND_REPEATED:
- break;
- }
-}
-
-static void audio_mixer_menu_stop_cb(
- audio_mixer_sound_t *sound, unsigned reason)
-{
- struct rarch_state *p_rarch = &rarch_st;
- int idx = audio_mixer_find_index(p_rarch, sound);
-
- switch (reason)
- {
- case AUDIO_MIXER_SOUND_FINISHED:
- if (idx >= 0)
- {
- unsigned i = (unsigned)idx;
- p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
- p_rarch->audio_mixer_streams[i].volume = 0.0f;
- }
- break;
- case AUDIO_MIXER_SOUND_STOPPED:
- break;
- case AUDIO_MIXER_SOUND_REPEATED:
- break;
- }
-}
-
-static void audio_mixer_play_stop_sequential_cb(
- audio_mixer_sound_t *sound, unsigned reason)
-{
- struct rarch_state *p_rarch = &rarch_st;
- int idx = audio_mixer_find_index(p_rarch, sound);
-
- switch (reason)
- {
- case AUDIO_MIXER_SOUND_FINISHED:
- audio_mixer_destroy(sound);
-
- if (idx >= 0)
- {
- unsigned i = (unsigned)idx;
-
- if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
- free(p_rarch->audio_mixer_streams[i].name);
-
- if (i < AUDIO_MIXER_MAX_STREAMS)
- p_rarch->audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER;
- else
- p_rarch->audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_SYSTEM;
-
- p_rarch->audio_mixer_streams[i].name = NULL;
- p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
- p_rarch->audio_mixer_streams[i].volume = 0.0f;
- p_rarch->audio_mixer_streams[i].buf = NULL;
- p_rarch->audio_mixer_streams[i].stop_cb = NULL;
- p_rarch->audio_mixer_streams[i].handle = NULL;
- p_rarch->audio_mixer_streams[i].voice = NULL;
-
- i++;
-
- for (; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
- {
- if (p_rarch->audio_mixer_streams[i].state
- == AUDIO_STREAM_STATE_STOPPED)
- {
- audio_driver_mixer_play_stream_sequential(i);
- break;
- }
- }
- }
- break;
- case AUDIO_MIXER_SOUND_STOPPED:
- break;
- case AUDIO_MIXER_SOUND_REPEATED:
- break;
- }
-}
-
-static bool audio_driver_mixer_get_free_stream_slot(
- unsigned *id, enum audio_mixer_stream_type type)
-{
- unsigned i = AUDIO_MIXER_MAX_STREAMS;
- unsigned count = AUDIO_MIXER_MAX_SYSTEM_STREAMS;
- struct rarch_state *p_rarch = &rarch_st;
-
- if (type == AUDIO_STREAM_TYPE_USER)
- {
- i = 0;
- count = AUDIO_MIXER_MAX_STREAMS;
- }
-
- for (; i < count; i++)
- {
- if (p_rarch->audio_mixer_streams[i].state == AUDIO_STREAM_STATE_NONE)
- {
- *id = i;
- return true;
- }
- }
-
- return false;
-}
-
-bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params)
-{
- struct rarch_state *p_rarch = &rarch_st;
- unsigned free_slot = 0;
- audio_mixer_voice_t *voice = NULL;
- audio_mixer_sound_t *handle = NULL;
- audio_mixer_stop_cb_t stop_cb = audio_mixer_play_stop_cb;
- bool looped = false;
- void *buf = NULL;
-
- if (params->stream_type == AUDIO_STREAM_TYPE_NONE)
- return false;
-
- switch (params->slot_selection_type)
- {
- case AUDIO_MIXER_SLOT_SELECTION_MANUAL:
- free_slot = params->slot_selection_idx;
-
- /* If we are using a manually specified
- * slot, must free any existing stream
- * before assigning the new one */
- audio_driver_mixer_stop_stream(free_slot);
- audio_driver_mixer_remove_stream(free_slot);
-
- break;
- case AUDIO_MIXER_SLOT_SELECTION_AUTOMATIC:
- default:
- if (!audio_driver_mixer_get_free_stream_slot(
- &free_slot, params->stream_type))
- return false;
- break;
- }
-
- if (params->state == AUDIO_STREAM_STATE_NONE)
- return false;
-
- buf = malloc(params->bufsize);
-
- if (!buf)
- return false;
-
- memcpy(buf, params->buf, params->bufsize);
-
- switch (params->type)
- {
- case AUDIO_MIXER_TYPE_WAV:
- handle = audio_mixer_load_wav(buf, (int32_t)params->bufsize,
- p_rarch->audio_driver_resampler_ident,
- p_rarch->audio_driver_resampler_quality);
- /* WAV is a special case - input buffer is not
- * free()'d when sound playback is complete (it is
- * converted to a PCM buffer, which is free()'d instead),
- * so have to do it here */
- free(buf);
- buf = NULL;
- break;
- case AUDIO_MIXER_TYPE_OGG:
- handle = audio_mixer_load_ogg(buf, (int32_t)params->bufsize);
- break;
- case AUDIO_MIXER_TYPE_MOD:
- handle = audio_mixer_load_mod(buf, (int32_t)params->bufsize);
- break;
- case AUDIO_MIXER_TYPE_FLAC:
-#ifdef HAVE_DR_FLAC
- handle = audio_mixer_load_flac(buf, (int32_t)params->bufsize);
-#endif
- break;
- case AUDIO_MIXER_TYPE_MP3:
-#ifdef HAVE_DR_MP3
- handle = audio_mixer_load_mp3(buf, (int32_t)params->bufsize);
-#endif
- break;
- case AUDIO_MIXER_TYPE_NONE:
- break;
- }
-
- if (!handle)
- {
- free(buf);
- return false;
- }
-
- switch (params->state)
- {
- case AUDIO_STREAM_STATE_PLAYING_LOOPED:
- looped = true;
- voice = audio_mixer_play(handle, looped, params->volume,
- p_rarch->audio_driver_resampler_ident,
- p_rarch->audio_driver_resampler_quality, stop_cb);
- break;
- case AUDIO_STREAM_STATE_PLAYING:
- voice = audio_mixer_play(handle, looped, params->volume,
- p_rarch->audio_driver_resampler_ident,
- p_rarch->audio_driver_resampler_quality, stop_cb);
- break;
- case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
- stop_cb = audio_mixer_play_stop_sequential_cb;
- voice = audio_mixer_play(handle, looped, params->volume,
- p_rarch->audio_driver_resampler_ident,
- p_rarch->audio_driver_resampler_quality, stop_cb);
- break;
- default:
- break;
- }
-
- p_rarch->audio_mixer_active = true;
-
- p_rarch->audio_mixer_streams[free_slot].name =
- !string_is_empty(params->basename) ? strdup(params->basename) : NULL;
- p_rarch->audio_mixer_streams[free_slot].buf = buf;
- p_rarch->audio_mixer_streams[free_slot].handle = handle;
- p_rarch->audio_mixer_streams[free_slot].voice = voice;
- p_rarch->audio_mixer_streams[free_slot].stream_type = params->stream_type;
- p_rarch->audio_mixer_streams[free_slot].type = params->type;
- p_rarch->audio_mixer_streams[free_slot].state = params->state;
- p_rarch->audio_mixer_streams[free_slot].volume = params->volume;
- p_rarch->audio_mixer_streams[free_slot].stop_cb = stop_cb;
-
- return true;
-}
-
-enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return AUDIO_STREAM_STATE_NONE;
-
- return p_rarch->audio_mixer_streams[i].state;
-}
-
-static void audio_driver_mixer_play_stream_internal(
- struct rarch_state *p_rarch,
- unsigned i, unsigned type)
-{
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return;
-
- switch (p_rarch->audio_mixer_streams[i].state)
- {
- case AUDIO_STREAM_STATE_STOPPED:
- p_rarch->audio_mixer_streams[i].voice =
- audio_mixer_play(p_rarch->audio_mixer_streams[i].handle,
- (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false,
- 1.0f, p_rarch->audio_driver_resampler_ident,
- p_rarch->audio_driver_resampler_quality,
- p_rarch->audio_mixer_streams[i].stop_cb);
- p_rarch->audio_mixer_streams[i].state = (enum audio_mixer_state)type;
- break;
- case AUDIO_STREAM_STATE_PLAYING:
- case AUDIO_STREAM_STATE_PLAYING_LOOPED:
- case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
- case AUDIO_STREAM_STATE_NONE:
- break;
- }
-}
-
-static void audio_driver_load_menu_bgm_callback(retro_task_t *task,
- void *task_data, void *user_data, const char *error)
-{
- bool contentless = false;
- bool is_inited = false;
-
- content_get_status(&contentless, &is_inited);
-
- if (!is_inited)
- audio_driver_mixer_play_menu_sound_looped(AUDIO_MIXER_SYSTEM_SLOT_BGM);
-}
-
-void audio_driver_load_system_sounds(void)
-{
- char sounds_path[PATH_MAX_LENGTH];
- char sounds_fallback_path[PATH_MAX_LENGTH];
- char basename_noext[PATH_MAX_LENGTH];
- settings_t *settings = config_get_ptr();
- const char *dir_assets = settings->paths.directory_assets;
- const bool audio_enable_menu = settings->bools.audio_enable_menu;
- const bool audio_enable_menu_ok = audio_enable_menu && settings->bools.audio_enable_menu_ok;
- const bool audio_enable_menu_cancel = audio_enable_menu && settings->bools.audio_enable_menu_cancel;
- const bool audio_enable_menu_notice = audio_enable_menu && settings->bools.audio_enable_menu_notice;
- const bool audio_enable_menu_bgm = audio_enable_menu && settings->bools.audio_enable_menu_bgm;
- const bool audio_enable_cheevo_unlock = settings->bools.cheevos_unlock_sound_enable;
- const char *path_ok = NULL;
- const char *path_cancel = NULL;
- const char *path_notice = NULL;
- const char *path_bgm = NULL;
- const char *path_cheevo_unlock = NULL;
- struct string_list *list = NULL;
- struct string_list *list_fallback = NULL;
- unsigned i = 0;
-
- if (!audio_enable_menu && !audio_enable_cheevo_unlock)
- goto end;
-
- sounds_path[0] = sounds_fallback_path[0] =
- basename_noext[0] ='\0';
-
- fill_pathname_join(
- sounds_fallback_path,
- dir_assets,
- "sounds",
- sizeof(sounds_fallback_path));
-
- fill_pathname_application_special(
- sounds_path,
- sizeof(sounds_path),
- APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS);
-
- list = dir_list_new(sounds_path, MENU_SOUND_FORMATS, false, false, false, false);
- list_fallback = dir_list_new(sounds_fallback_path, MENU_SOUND_FORMATS, false, false, false, false);
-
- if (!list)
- {
- list = list_fallback;
- list_fallback = NULL;
- }
-
- if (!list || list->size == 0)
- goto end;
-
- if (list_fallback && list_fallback->size > 0)
- {
- for (i = 0; i < list_fallback->size; i++)
- {
- if (list->size == 0 || !string_list_find_elem(list, list_fallback->elems[i].data))
- {
- union string_list_elem_attr attr = {0};
- string_list_append(list, list_fallback->elems[i].data, attr);
- }
- }
- }
-
- for (i = 0; i < list->size; i++)
- {
- const char *path = list->elems[i].data;
- const char *ext = path_get_extension(path);
-
- if (audio_driver_mixer_extension_supported(ext))
- {
- basename_noext[0] = '\0';
- fill_pathname_base_noext(basename_noext, path, sizeof(basename_noext));
-
- if (string_is_equal_noncase(basename_noext, "ok"))
- path_ok = path;
- else if (string_is_equal_noncase(basename_noext, "cancel"))
- path_cancel = path;
- else if (string_is_equal_noncase(basename_noext, "notice"))
- path_notice = path;
- else if (string_is_equal_noncase(basename_noext, "bgm"))
- path_bgm = path;
- else if (string_is_equal_noncase(basename_noext, "unlock"))
- path_cheevo_unlock = path;
- }
- }
-
- if (path_ok && audio_enable_menu_ok)
- task_push_audio_mixer_load(path_ok, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_OK);
- if (path_cancel && audio_enable_menu_cancel)
- task_push_audio_mixer_load(path_cancel, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_CANCEL);
- if (path_notice && audio_enable_menu_notice)
- task_push_audio_mixer_load(path_notice, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_NOTICE);
- if (path_bgm && audio_enable_menu_bgm)
- task_push_audio_mixer_load(path_bgm, audio_driver_load_menu_bgm_callback, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_BGM);
- if (path_cheevo_unlock && audio_enable_cheevo_unlock)
- task_push_audio_mixer_load(path_cheevo_unlock, NULL, NULL, true, AUDIO_MIXER_SLOT_SELECTION_MANUAL, AUDIO_MIXER_SYSTEM_SLOT_ACHIEVEMENT_UNLOCK);
-
-end:
- if (list)
- string_list_free(list);
- if (list_fallback)
- string_list_free(list_fallback);
-}
-
-void audio_driver_mixer_play_stream(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
- audio_driver_mixer_play_stream_internal(p_rarch,
- i, AUDIO_STREAM_STATE_PLAYING);
-}
-
-void audio_driver_mixer_play_menu_sound_looped(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
- audio_driver_mixer_play_stream_internal(p_rarch,
- i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
-}
-
-void audio_driver_mixer_play_menu_sound(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_menu_stop_cb;
- audio_driver_mixer_play_stream_internal(p_rarch,
- i, AUDIO_STREAM_STATE_PLAYING);
-}
-
-void audio_driver_mixer_play_stream_looped(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_cb;
- audio_driver_mixer_play_stream_internal(p_rarch,
- i, AUDIO_STREAM_STATE_PLAYING_LOOPED);
-}
-
-void audio_driver_mixer_play_stream_sequential(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_mixer_streams[i].stop_cb = audio_mixer_play_stop_sequential_cb;
- audio_driver_mixer_play_stream_internal(p_rarch,
- i, AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL);
-}
-
-float audio_driver_mixer_get_stream_volume(unsigned i)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return 0.0f;
-
- return p_rarch->audio_mixer_streams[i].volume;
-}
-
-void audio_driver_mixer_set_stream_volume(unsigned i, float vol)
-{
- audio_mixer_voice_t *voice = NULL;
- struct rarch_state *p_rarch = &rarch_st;
-
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return;
-
- p_rarch->audio_mixer_streams[i].volume = vol;
-
- voice =
- p_rarch->audio_mixer_streams[i].voice;
-
- if (voice)
- audio_mixer_voice_set_volume(voice, DB_TO_GAIN(vol));
-}
-
-void audio_driver_mixer_stop_stream(unsigned i)
-{
- bool set_state = false;
- struct rarch_state *p_rarch = &rarch_st;
-
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return;
-
- switch (p_rarch->audio_mixer_streams[i].state)
- {
- case AUDIO_STREAM_STATE_PLAYING:
- case AUDIO_STREAM_STATE_PLAYING_LOOPED:
- case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
- set_state = true;
- break;
- case AUDIO_STREAM_STATE_STOPPED:
- case AUDIO_STREAM_STATE_NONE:
- break;
- }
-
- if (set_state)
- {
- audio_mixer_voice_t *voice = p_rarch->audio_mixer_streams[i].voice;
-
- if (voice)
- audio_mixer_stop(voice);
- p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
- p_rarch->audio_mixer_streams[i].volume = 1.0f;
- }
-}
-
-void audio_driver_mixer_remove_stream(unsigned i)
-{
- bool destroy = false;
- struct rarch_state *p_rarch = &rarch_st;
-
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return;
-
- switch (p_rarch->audio_mixer_streams[i].state)
- {
- case AUDIO_STREAM_STATE_PLAYING:
- case AUDIO_STREAM_STATE_PLAYING_LOOPED:
- case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
- audio_driver_mixer_stop_stream(i);
- destroy = true;
- break;
- case AUDIO_STREAM_STATE_STOPPED:
- destroy = true;
- break;
- case AUDIO_STREAM_STATE_NONE:
- break;
- }
-
- if (destroy)
- {
- audio_mixer_sound_t *handle = p_rarch->audio_mixer_streams[i].handle;
- if (handle)
- audio_mixer_destroy(handle);
-
- if (!string_is_empty(p_rarch->audio_mixer_streams[i].name))
- free(p_rarch->audio_mixer_streams[i].name);
-
- p_rarch->audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
- p_rarch->audio_mixer_streams[i].stop_cb = NULL;
- p_rarch->audio_mixer_streams[i].volume = 0.0f;
- p_rarch->audio_mixer_streams[i].handle = NULL;
- p_rarch->audio_mixer_streams[i].voice = NULL;
- p_rarch->audio_mixer_streams[i].name = NULL;
- }
-}
-#endif
-
-bool audio_driver_enable_callback(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (!p_rarch->audio_callback.callback)
- return false;
- if (p_rarch->audio_callback.set_state)
- p_rarch->audio_callback.set_state(true);
- return true;
-}
-
-bool audio_driver_disable_callback(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (!p_rarch->audio_callback.callback)
- return false;
-
- if (p_rarch->audio_callback.set_state)
- p_rarch->audio_callback.set_state(false);
- return true;
-}
-
-bool audio_driver_callback(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- settings_t *settings = p_rarch->configuration_settings;
-#ifdef HAVE_MENU
- bool core_paused = runloop_state.paused || (settings->bools.menu_pause_libretro && menu_state_get_ptr()->alive);
-#else
- bool core_paused = runloop_state.paused;
-#endif
-
- if (!p_rarch->audio_callback.callback)
- return false;
-
- if (!core_paused && p_rarch->audio_callback.callback)
- p_rarch->audio_callback.callback();
-
- return true;
-}
-
-bool audio_driver_has_callback(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- if (p_rarch->audio_callback.callback)
- return true;
- return false;
-}
-
-#ifdef HAVE_AUDIOMIXER
-bool audio_driver_mixer_toggle_mute(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- p_rarch->audio_driver_mixer_mute_enable =
- !p_rarch->audio_driver_mixer_mute_enable;
- return true;
-}
-#endif
-
-static INLINE bool audio_driver_alive(struct rarch_state *p_rarch)
-{
- if ( p_rarch->current_audio
- && p_rarch->current_audio->alive
- && p_rarch->audio_driver_context_audio_data)
- return p_rarch->current_audio->alive(p_rarch->audio_driver_context_audio_data);
- return false;
-}
-
-static bool audio_driver_start(struct rarch_state *p_rarch,
- bool is_shutdown)
-{
- if (!p_rarch->current_audio || !p_rarch->current_audio->start
- || !p_rarch->audio_driver_context_audio_data)
- goto error;
- if (!p_rarch->current_audio->start(
- p_rarch->audio_driver_context_audio_data, is_shutdown))
- goto error;
-
- return true;
-
-error:
- RARCH_ERR("%s\n",
- msg_hash_to_str(MSG_FAILED_TO_START_AUDIO_DRIVER));
- p_rarch->audio_driver_active = false;
- return false;
-}
-
-static bool audio_driver_stop(struct rarch_state *p_rarch)
-{
- if ( !p_rarch->current_audio
- || !p_rarch->current_audio->stop
- || !p_rarch->audio_driver_context_audio_data
- || !audio_driver_alive(p_rarch)
- )
- return false;
- return p_rarch->current_audio->stop(
- p_rarch->audio_driver_context_audio_data);
-}
-
-#ifdef HAVE_REWIND
-void audio_driver_frame_is_reverse(void)
-{
- struct rarch_state *p_rarch = &rarch_st;
- /* We just rewound. Flush rewind audio buffer. */
- if ( p_rarch->recording_data &&
- p_rarch->recording_driver &&
- p_rarch->recording_driver->push_audio)
- {
- struct record_audio_data ffemu_data;
-
- ffemu_data.data = p_rarch->audio_driver_rewind_buf +
- p_rarch->audio_driver_rewind_ptr;
- ffemu_data.frames = (p_rarch->audio_driver_rewind_size -
- p_rarch->audio_driver_rewind_ptr) / 2;
-
- p_rarch->recording_driver->push_audio(p_rarch->recording_data, &ffemu_data);
- }
-
- if (!(
- runloop_state.paused ||
- !p_rarch->audio_driver_active ||
- !p_rarch->audio_driver_output_samples_buf))
- if (!p_rarch->audio_suspended)
- audio_driver_flush(
- p_rarch,
- p_rarch->configuration_settings->floats.slowmotion_ratio,
- p_rarch->configuration_settings->bools.audio_fastforward_mute,
- p_rarch->audio_driver_rewind_buf +
- p_rarch->audio_driver_rewind_ptr,
- p_rarch->audio_driver_rewind_size -
- p_rarch->audio_driver_rewind_ptr,
- runloop_state.slowmotion,
- runloop_state.fastmotion);
-}
-#endif
-
-void audio_set_float(enum audio_action action, float val)
-{
- struct rarch_state *p_rarch = &rarch_st;
-
- switch (action)
- {
- case AUDIO_ACTION_VOLUME_GAIN:
- p_rarch->audio_driver_volume_gain = DB_TO_GAIN(val);
- break;
- case AUDIO_ACTION_MIXER_VOLUME_GAIN:
-#ifdef HAVE_AUDIOMIXER
- p_rarch->audio_driver_mixer_volume_gain = DB_TO_GAIN(val);
-#endif
- break;
- case AUDIO_ACTION_RATE_CONTROL_DELTA:
- p_rarch->audio_driver_rate_control_delta = val;
- break;
- case AUDIO_ACTION_NONE:
- default:
- break;
- }
-}
-
-float *audio_get_float_ptr(enum audio_action action)
-{
- struct rarch_state *p_rarch = &rarch_st;
-
- switch (action)
- {
- case AUDIO_ACTION_RATE_CONTROL_DELTA:
- return &p_rarch->audio_driver_rate_control_delta;
- case AUDIO_ACTION_NONE:
- default:
- break;
- }
-
- return NULL;
-}
-
-bool *audio_get_bool_ptr(enum audio_action action)
-{
- struct rarch_state *p_rarch = &rarch_st;
-
- switch (action)
- {
- case AUDIO_ACTION_MIXER_MUTE_ENABLE:
-#ifdef HAVE_AUDIOMIXER
- return &p_rarch->audio_driver_mixer_mute_enable;
-#else
- break;
-#endif
- case AUDIO_ACTION_MUTE_ENABLE:
- return &p_rarch->audio_driver_mute_enable;
- case AUDIO_ACTION_NONE:
- default:
- break;
- }
-
- return NULL;
-}
-
/* VIDEO */
const char *video_display_server_get_ident(void)
{
@@ -18267,11 +16590,11 @@ enum retro_pixel_format video_driver_get_pixel_format(void)
void video_driver_cached_frame(void)
{
struct rarch_state *p_rarch = &rarch_st;
- void *recording = p_rarch->recording_data;
+ void *recording = recording_state.data;
struct retro_callbacks *cbs = &p_rarch->retro_ctx;
/* Cannot allow recording when pushing duped frames. */
- p_rarch->recording_data = NULL;
+ recording_state.data = NULL;
if (p_rarch->current_core.inited)
cbs->frame_cb(
@@ -18281,7 +16604,7 @@ void video_driver_cached_frame(void)
p_rarch->frame_cache_height,
p_rarch->frame_cache_pitch);
- p_rarch->recording_data = recording;
+ recording_state.data = recording;
}
static void video_driver_lock_new(struct rarch_state *p_rarch)
@@ -19122,9 +17445,9 @@ static void video_driver_frame(const void *data, unsigned width,
!video_info.post_filter_record
|| !data
|| p_rarch->video_driver_record_gpu_buffer
- ) && p_rarch->recording_data
- && p_rarch->recording_driver
- && p_rarch->recording_driver->push_video)
+ ) && recording_state.data
+ && recording_state.driver
+ && recording_state.driver->push_video)
recording_dump_frame(p_rarch,
data, width, height,
pitch, runloop_idle);
@@ -19146,9 +17469,9 @@ static void video_driver_frame(const void *data, unsigned width,
data, width, height, pitch);
if (video_info.post_filter_record
- && p_rarch->recording_data
- && p_rarch->recording_driver
- && p_rarch->recording_driver->push_video)
+ && recording_state.data
+ && recording_state.driver
+ && recording_state.driver->push_video)
recording_dump_frame(p_rarch,
p_rarch->video_driver_state_buffer,
output_width, output_height, output_pitch,
@@ -19245,7 +17568,7 @@ static void video_driver_frame(const void *data, unsigned width,
video_info.osd_stat_params.color = COLOR_ABGR(
red, green, blue, alpha);
- audio_compute_buffer_statistics(p_rarch, &audio_stats);
+ audio_compute_buffer_statistics(&audio_stats);
snprintf(video_info.stat_text,
sizeof(video_info.stat_text),
@@ -20113,10 +18436,11 @@ static void driver_adjust_system_rates(
if (input_sample_rate > 0.0)
{
+ audio_driver_state_t *audio_st = audio_state_get_ptr();
if (vrr_runloop_enable)
- p_rarch->audio_driver_input = input_sample_rate;
+ audio_st->input = input_sample_rate;
else
- p_rarch->audio_driver_input =
+ audio_st->input =
audio_driver_monitor_adjust_system_rates(
input_sample_rate,
input_fps,
@@ -20125,7 +18449,7 @@ static void driver_adjust_system_rates(
audio_max_timing_skew);
RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
- p_rarch->audio_driver_input);
+ audio_st->input);
}
runloop_state.force_nonblock = false;
@@ -20181,6 +18505,8 @@ void driver_set_nonblock_state(void)
*p_rarch = &rarch_st;
input_driver_state_t
*input_st = input_state_get_ptr();
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
bool enable = input_st ?
input_st->nonblocking_flag : false;
settings_t *settings = p_rarch->configuration_settings;
@@ -20189,7 +18515,7 @@ void driver_set_nonblock_state(void)
bool adaptive_vsync = settings->bools.video_adaptive_vsync;
unsigned swap_interval = settings->uints.video_swap_interval;
bool video_driver_active = p_rarch->video_driver_active;
- bool audio_driver_active = p_rarch->audio_driver_active;
+ bool audio_driver_active = audio_st->active;
bool runloop_force_nonblock = runloop_state.force_nonblock;
/* Only apply non-block-state for video if we're using vsync. */
@@ -20207,14 +18533,14 @@ void driver_set_nonblock_state(void)
}
}
- if (audio_driver_active && p_rarch->audio_driver_context_audio_data)
- p_rarch->current_audio->set_nonblock_state(
- p_rarch->audio_driver_context_audio_data,
+ if (audio_driver_active && audio_st->context_audio_data)
+ audio_st->current_audio->set_nonblock_state(
+ audio_st->context_audio_data,
audio_sync ? enable : true);
- p_rarch->audio_driver_chunk_size = enable
- ? p_rarch->audio_driver_chunk_nonblock_size
- : p_rarch->audio_driver_chunk_block_size;
+ audio_st->chunk_size = enable
+ ? audio_st->chunk_nonblock_size
+ : audio_st->chunk_block_size;
}
/**
@@ -20229,6 +18555,8 @@ static void drivers_init(struct rarch_state *p_rarch,
int flags,
bool verbosity_enabled)
{
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
input_driver_state_t
*input_st = input_state_get_ptr();
#ifdef HAVE_MENU
@@ -20285,15 +18613,15 @@ static void drivers_init(struct rarch_state *p_rarch,
/* Initialize audio driver */
if (flags & DRIVER_AUDIO_MASK)
{
- audio_driver_init_internal(p_rarch,
+ audio_driver_init_internal(
settings,
- p_rarch->audio_callback.callback != NULL);
- if ( p_rarch->current_audio &&
- p_rarch->current_audio->device_list_new &&
- p_rarch->audio_driver_context_audio_data)
- p_rarch->audio_driver_devices_list = (struct string_list*)
- p_rarch->current_audio->device_list_new(
- p_rarch->audio_driver_context_audio_data);
+ audio_st->callback.callback != NULL);
+ if ( audio_st->current_audio &&
+ audio_st->current_audio->device_list_new &&
+ audio_st->context_audio_data)
+ audio_st->devices_list = (struct string_list*)
+ audio_st->current_audio->device_list_new(
+ audio_st->context_audio_data);
}
if (flags & DRIVER_CAMERA_MASK)
@@ -20505,7 +18833,7 @@ static void driver_uninit(struct rarch_state *p_rarch, int flags)
}
if (flags & DRIVER_AUDIO_MASK)
- audio_driver_deinit(p_rarch, p_rarch->configuration_settings);
+ audio_driver_deinit(p_rarch->configuration_settings);
if ((flags & DRIVER_VIDEO_MASK))
p_rarch->video_driver_data = NULL;
@@ -20514,7 +18842,7 @@ static void driver_uninit(struct rarch_state *p_rarch, int flags)
input_state_get_ptr()->current_data = NULL;
if ((flags & DRIVER_AUDIO_MASK))
- p_rarch->audio_driver_context_audio_data = NULL;
+ audio_state_get_ptr()->context_audio_data = NULL;
if (flags & DRIVER_MIDI_MASK)
midi_driver_free();
@@ -20567,8 +18895,8 @@ static void retroarch_deinit_drivers(
video_driver_set_cached_frame_ptr(NULL);
/* Audio */
- p_rarch->audio_driver_active = false;
- p_rarch->current_audio = NULL;
+ audio_state_get_ptr()->active = false;
+ audio_state_get_ptr()->current_audio = NULL;
/* Input */
input_st->keyboard_linefeed_enable = false;
@@ -20618,8 +18946,11 @@ bool driver_ctl(enum driver_ctl_state state, void *data)
case RARCH_DRIVER_CTL_SET_REFRESH_RATE:
{
float *hz = (float*)data;
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
settings_t *settings = p_rarch->configuration_settings;
- unsigned audio_output_sample_rate = settings->uints.audio_output_sample_rate;
+ unsigned
+ audio_output_sample_rate = settings->uints.audio_output_sample_rate;
bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
float video_refresh_rate = settings->floats.video_refresh_rate;
float audio_max_timing_skew = settings->floats.audio_max_timing_skew;
@@ -20629,9 +18960,9 @@ bool driver_ctl(enum driver_ctl_state state, void *data)
video_monitor_set_refresh_rate(*hz);
/* Sets audio monitor rate to new value. */
- p_rarch->audio_source_ratio_original =
- p_rarch->audio_source_ratio_current = (double)audio_output_sample_rate
- / p_rarch->audio_driver_input;
+ audio_st->source_ratio_original =
+ audio_st->source_ratio_current =
+ (double)audio_output_sample_rate / audio_st->input;
driver_adjust_system_rates(p_rarch,
vrr_runloop_enable,
@@ -21239,6 +19570,8 @@ static void do_runahead(
const bool have_dynamic = false;
#endif
uint64_t frame_count = p_rarch->video_driver_frame_count;
+ audio_driver_state_t
+ *audio_st = audio_state_get_ptr();
if (runahead_count <= 0 || !p_rarch->runahead_available)
goto force_input_dirty;
@@ -21273,7 +19606,7 @@ static void do_runahead(
if (suspended_frame)
{
- p_rarch->audio_suspended = true;
+ audio_st->suspended = true;
p_rarch->video_driver_active = false;
}
@@ -21285,7 +19618,7 @@ static void do_runahead(
if (suspended_frame)
{
RUNAHEAD_RESUME_VIDEO(p_rarch);
- p_rarch->audio_suspended = false;
+ audio_st->suspended = false;
}
if (frame_number == 0)
@@ -21343,19 +19676,19 @@ static void do_runahead(
for (frame_number = 0; frame_number < runahead_count - 1; frame_number++)
{
p_rarch->video_driver_active = false;
- p_rarch->audio_suspended = true;
- p_rarch->hard_disable_audio = true;
+ audio_st->suspended = true;
+ audio_st->hard_disable = true;
RUNAHEAD_RUN_SECONDARY(p_rarch);
- p_rarch->hard_disable_audio = false;
- p_rarch->audio_suspended = false;
+ audio_st->hard_disable = false;
+ audio_st->suspended = false;
RUNAHEAD_RESUME_VIDEO(p_rarch);
}
}
- p_rarch->audio_suspended = true;
- p_rarch->hard_disable_audio = true;
+ audio_st->suspended = true;
+ audio_st->hard_disable = true;
RUNAHEAD_RUN_SECONDARY(p_rarch);
- p_rarch->hard_disable_audio = false;
- p_rarch->audio_suspended = false;
+ audio_st->hard_disable = false;
+ audio_st->suspended = false;
#endif
}
p_rarch->runahead_force_input_dirty = false;
@@ -22010,8 +20343,8 @@ static bool retroarch_parse_input_and_config(
case 'r':
strlcpy(global->record.path, optarg,
sizeof(global->record.path));
- if (p_rarch->recording_enable)
- p_rarch->recording_enable = true;
+ if (recording_state.enable)
+ recording_state.enable = true;
break;
case RA_OPT_SET_SHADER:
@@ -22248,8 +20581,8 @@ static bool retroarch_parse_input_and_config(
case RA_OPT_SIZE:
if (sscanf(optarg, "%ux%u",
- &p_rarch->recording_width,
- &p_rarch->recording_height) != 2)
+ &recording_state.width,
+ &recording_state.height) != 2)
{
RARCH_ERR("Wrong format for --size.\n");
retroarch_print_help(argv[0]);
@@ -22446,8 +20779,8 @@ bool retroarch_main_init(int argc, char *argv[])
#endif
input_st->osk_idx = OSK_LOWERCASE_LATIN;
- p_rarch->video_driver_active = true;
- p_rarch->audio_driver_active = true;
+ p_rarch->video_driver_active = true;
+ audio_state_get_ptr()->active = true;
if (setjmp(p_rarch->error_sjlj_context) > 0)
{
@@ -22588,7 +20921,7 @@ bool retroarch_main_init(int argc, char *argv[])
* Attempts to find a default driver for
* all driver types.
*/
- if (!(audio_driver_find_driver(p_rarch, settings,
+ if (!(audio_driver_find_driver(settings,
"audio driver", verbosity_enabled)))
retroarch_fail(p_rarch, 1, "audio_driver_find()");
video_driver_find_driver(p_rarch, settings,
@@ -23958,7 +22291,7 @@ static void runloop_apply_fastmotion_override(
fastforward_ratio_current);
}
-static enum runloop_state runloop_check_state(
+static enum runloop_state_enum runloop_check_state(
struct rarch_state *p_rarch,
settings_t *settings,
retro_time_t current_time)
@@ -25210,6 +23543,7 @@ int runloop_iterate(void)
enum analog_dpad_mode dpad_mode[MAX_USERS];
struct rarch_state *p_rarch = &rarch_st;
input_driver_state_t *input_st = input_state_get_ptr();
+ audio_driver_state_t *audio_st = audio_state_get_ptr();
settings_t *settings = p_rarch->configuration_settings;
unsigned video_frame_delay = settings->uints.video_frame_delay;
bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
@@ -25248,7 +23582,7 @@ int runloop_iterate(void)
retro_time_t current = current_time;
bool is_locked_fps = (runloop_state.paused
|| input_st->nonblocking_flag)
- | !!p_rarch->recording_data;
+ | !!recording_state.data;
retro_time_t delta = (!runloop_last_frame_time || is_locked_fps)
? runloop_state.frame_time.reference
: (current - runloop_last_frame_time);
@@ -25276,20 +23610,20 @@ int runloop_iterate(void)
bool audio_buf_underrun = false;
if (!(runloop_state.paused ||
- !p_rarch->audio_driver_active ||
- !p_rarch->audio_driver_output_samples_buf) &&
- p_rarch->current_audio->write_avail &&
- p_rarch->audio_driver_context_audio_data &&
- p_rarch->audio_driver_buffer_size)
+ !audio_st->active ||
+ !audio_st->output_samples_buf) &&
+ audio_st->current_audio->write_avail &&
+ audio_st->context_audio_data &&
+ audio_st->buffer_size)
{
size_t audio_buf_avail;
- if ((audio_buf_avail = p_rarch->current_audio->write_avail(
- p_rarch->audio_driver_context_audio_data)) > p_rarch->audio_driver_buffer_size)
- audio_buf_avail = p_rarch->audio_driver_buffer_size;
+ if ((audio_buf_avail = audio_st->current_audio->write_avail(
+ audio_st->context_audio_data)) > audio_st->buffer_size)
+ audio_buf_avail = audio_st->buffer_size;
audio_buf_occupancy = (unsigned)(100 - (audio_buf_avail * 100) /
- p_rarch->audio_driver_buffer_size);
+ audio_st->buffer_size);
/* Elsewhere, we standardise on a 'low water mark'
* of 25% of the total audio buffer size - use
@@ -25307,7 +23641,7 @@ int runloop_iterate(void)
audio_buf_active, audio_buf_occupancy, audio_buf_underrun);
}
- switch ((enum runloop_state)runloop_check_state(p_rarch,
+ switch ((enum runloop_state_enum)runloop_check_state(p_rarch,
settings, current_time))
{
case RUNLOOP_STATE_QUIT:
@@ -25527,12 +23861,12 @@ end:
if (p_rarch->fastforward_after_frames == 1)
{
/* Nonblocking audio */
- if (p_rarch->audio_driver_active &&
- p_rarch->audio_driver_context_audio_data)
- p_rarch->current_audio->set_nonblock_state(
- p_rarch->audio_driver_context_audio_data, true);
- p_rarch->audio_driver_chunk_size =
- p_rarch->audio_driver_chunk_nonblock_size;
+ if (audio_st->active &&
+ audio_st->context_audio_data)
+ audio_st->current_audio->set_nonblock_state(
+ audio_st->context_audio_data, true);
+ audio_st->chunk_size =
+ audio_st->chunk_nonblock_size;
}
p_rarch->fastforward_after_frames++;
@@ -25540,14 +23874,13 @@ end:
if (p_rarch->fastforward_after_frames == 6)
{
/* Blocking audio */
- if (p_rarch->audio_driver_active &&
- p_rarch->audio_driver_context_audio_data)
- p_rarch->current_audio->set_nonblock_state(
- p_rarch->audio_driver_context_audio_data,
+ if (audio_st->active &&
+ audio_st->context_audio_data)
+ audio_st->current_audio->set_nonblock_state(
+ audio_st->context_audio_data,
audio_sync ? false : true);
- p_rarch->audio_driver_chunk_size =
- p_rarch->audio_driver_chunk_block_size;
+ audio_st->chunk_size = audio_st->chunk_block_size;
p_rarch->fastforward_after_frames = 0;
}
}
@@ -26100,7 +24433,7 @@ static bool core_unload_game(struct rarch_state *p_rarch)
p_rarch->current_core.game_loaded = false;
}
- audio_driver_stop(p_rarch);
+ audio_driver_stop();
return true;
}
diff --git a/retroarch.h b/retroarch.h
index 455d283f3d..289bf1830e 100644
--- a/retroarch.h
+++ b/retroarch.h
@@ -34,11 +34,6 @@
#include
#include
#include
-#ifdef HAVE_AUDIOMIXER
-#include
-#endif
-
-#include "audio/audio_defines.h"
#include "gfx/video_driver.h"
#include "core.h"
@@ -151,122 +146,6 @@ void rarch_favorites_deinit(void);
/* Audio */
-#ifdef HAVE_AUDIOMIXER
-typedef struct audio_mixer_stream
-{
- audio_mixer_sound_t *handle;
- audio_mixer_voice_t *voice;
- audio_mixer_stop_cb_t stop_cb;
- void *buf;
- char *name;
- size_t bufsize;
- float volume;
- enum audio_mixer_stream_type stream_type;
- enum audio_mixer_type type;
- enum audio_mixer_state state;
-} audio_mixer_stream_t;
-
-typedef struct audio_mixer_stream_params
-{
- void *buf;
- char *basename;
- audio_mixer_stop_cb_t cb;
- size_t bufsize;
- unsigned slot_selection_idx;
- float volume;
- enum audio_mixer_slot_selection_type slot_selection_type;
- enum audio_mixer_stream_type stream_type;
- enum audio_mixer_type type;
- enum audio_mixer_state state;
-} audio_mixer_stream_params_t;
-#endif
-
-typedef struct audio_driver
-{
- /* Creates and initializes handle to audio driver.
- *
- * Returns: audio driver handle on success, otherwise NULL.
- **/
- void *(*init)(const char *device, unsigned rate,
- unsigned latency, unsigned block_frames, unsigned *new_rate);
-
- /*
- * @data : Pointer to audio data handle.
- * @buf : Audio buffer data.
- * @size : Size of audio buffer.
- *
- * Write samples to audio driver.
- *
- * Write data in buffer to audio driver.
- * A frame here is defined as one combined sample of left and right
- * channels. (I.e. 44.1kHz, 16-bit stereo has 88.2k samples/s, and
- * 44.1k frames/s.)
- *
- * Samples are interleaved in format LRLRLRLRLR ...
- * If the driver returns true in use_float(), a floating point
- * format will be used, with range [-1.0, 1.0].
- * If not, signed 16-bit samples in native byte ordering will be used.
- *
- * This function returns the number of frames successfully written.
- * If an error occurs, -1 should be returned.
- * Note that non-blocking behavior that cannot write at this time
- * should return 0 as returning -1 will terminate the driver.
- *
- * Unless said otherwise with set_nonblock_state(), all writes
- * are blocking, and it should block till it has written all frames.
- */
- ssize_t (*write)(void *data, const void *buf, size_t size);
-
- /* Temporarily pauses the audio driver. */
- bool (*stop)(void *data);
-
- /* Resumes audio driver from the paused state. */
- bool (*start)(void *data, bool is_shutdown);
-
- /* Is the audio driver currently running? */
- bool (*alive)(void *data);
-
- /* Should we care about blocking in audio thread? Fast forwarding.
- *
- * If state is true, nonblocking operation is assumed.
- * This is typically used for fast-forwarding. If driver cannot
- * implement nonblocking writes, this can be disregarded, but should
- * log a message to stderr.
- * */
- void (*set_nonblock_state)(void *data, bool toggle);
-
- /* Stops and frees driver data. */
- void (*free)(void *data);
-
- /* Defines if driver will take standard floating point samples,
- * or int16_t samples.
- *
- * If true is returned, the audio driver is capable of using
- * floating point data. This will likely increase performance as the
- * resampler unit uses floating point. The sample range is
- * [-1.0, 1.0].
- * */
- bool (*use_float)(void *data);
-
- /* Human-readable identifier. */
- const char *ident;
-
- /* Optional. Get audio device list (allocates, caller has to free this) */
- void *(*device_list_new)(void *data);
-
- /* Optional. Frees audio device list */
- void (*device_list_free)(void *data, void *data2);
-
- /* Optional. */
- size_t (*write_avail)(void *data);
-
- size_t (*buffer_size)(void *data);
-} audio_driver_t;
-
-bool audio_driver_enable_callback(void);
-
-bool audio_driver_disable_callback(void);
-
/**
* config_get_audio_driver_options:
*
@@ -276,95 +155,6 @@ bool audio_driver_disable_callback(void);
**/
const char* config_get_audio_driver_options(void);
-bool audio_driver_mixer_extension_supported(const char *ext);
-
-void audio_driver_dsp_filter_free(void);
-
-bool audio_driver_dsp_filter_init(const char *device);
-
-void audio_driver_set_buffer_size(size_t bufsize);
-
-bool audio_driver_get_devices_list(void **ptr);
-
-void audio_driver_setup_rewind(void);
-
-bool audio_driver_callback(void);
-
-bool audio_driver_has_callback(void);
-
-void audio_driver_frame_is_reverse(void);
-
-void audio_set_float(enum audio_action action, float val);
-
-float *audio_get_float_ptr(enum audio_action action);
-
-bool *audio_get_bool_ptr(enum audio_action action);
-
-#ifdef HAVE_AUDIOMIXER
-audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i);
-
-bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params);
-
-void audio_driver_mixer_play_stream(unsigned i);
-
-void audio_driver_mixer_play_menu_sound(unsigned i);
-
-void audio_driver_mixer_play_menu_sound_looped(unsigned i);
-
-void audio_driver_mixer_play_stream_sequential(unsigned i);
-
-void audio_driver_mixer_play_stream_looped(unsigned i);
-
-void audio_driver_mixer_stop_stream(unsigned i);
-
-float audio_driver_mixer_get_stream_volume(unsigned i);
-
-void audio_driver_mixer_set_stream_volume(unsigned i, float vol);
-
-void audio_driver_mixer_remove_stream(unsigned i);
-
-enum audio_mixer_state audio_driver_mixer_get_stream_state(unsigned i);
-
-const char *audio_driver_mixer_get_stream_name(unsigned i);
-
-void audio_driver_load_system_sounds(void);
-
-#endif
-
-extern audio_driver_t audio_rsound;
-extern audio_driver_t audio_audioio;
-extern audio_driver_t audio_oss;
-extern audio_driver_t audio_alsa;
-extern audio_driver_t audio_alsathread;
-extern audio_driver_t audio_tinyalsa;
-extern audio_driver_t audio_roar;
-extern audio_driver_t audio_openal;
-extern audio_driver_t audio_opensl;
-extern audio_driver_t audio_jack;
-extern audio_driver_t audio_sdl;
-extern audio_driver_t audio_xa;
-extern audio_driver_t audio_pulse;
-extern audio_driver_t audio_dsound;
-extern audio_driver_t audio_wasapi;
-extern audio_driver_t audio_coreaudio;
-extern audio_driver_t audio_coreaudio3;
-extern audio_driver_t audio_xenon360;
-extern audio_driver_t audio_ps3;
-extern audio_driver_t audio_gx;
-extern audio_driver_t audio_ax;
-extern audio_driver_t audio_psp;
-extern audio_driver_t audio_ps2;
-extern audio_driver_t audio_ctr_csnd;
-extern audio_driver_t audio_ctr_dsp;
-#ifdef HAVE_THREADS
-extern audio_driver_t audio_ctr_dsp_thread;
-#endif
-extern audio_driver_t audio_switch;
-extern audio_driver_t audio_switch_thread;
-extern audio_driver_t audio_switch_libnx_audren;
-extern audio_driver_t audio_switch_libnx_audren_thread;
-extern audio_driver_t audio_rwebaudio;
-
/* Recording */
typedef struct record_driver
@@ -499,6 +289,24 @@ bool retroarch_get_current_savestate_path(char *path, size_t len);
runloop_state_t *runloop_state_get_ptr(void);
+struct recording
+{
+ const record_driver_t *driver;
+ void *data;
+
+ size_t gpu_width;
+ size_t gpu_height;
+
+ unsigned width;
+ unsigned height;
+
+ bool enable;
+};
+
+typedef struct recording recording_state_t;
+
+recording_state_t *recording_state_get_ptr(void);
+
RETRO_END_DECLS
#endif
diff --git a/retroarch_data.h b/retroarch_data.h
index 6cbda3dac9..0a1602be88 100644
--- a/retroarch_data.h
+++ b/retroarch_data.h
@@ -61,20 +61,6 @@
#define TIME_TO_FPS(last_time, new_time, frames) ((1000000.0f * (frames)) / ((new_time) - (last_time)))
-#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
-
-#define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac|wav"
-
-/**
- * db_to_gain:
- * @db : Decibels.
- *
- * Converts decibels to voltage gain.
- *
- * Returns: voltage gain value.
- **/
-#define DB_TO_GAIN(db) (powf(10.0f, (db) / 20.0f))
-
#define DEFAULT_NETWORK_GAMEPAD_PORT 55400
#define UDP_FRAME_PACKETS 16
@@ -320,114 +306,6 @@ input_st->bsv_movie_state.eof_exit)
/* DRIVERS */
-audio_driver_t audio_null = {
- NULL, /* init */
- NULL, /* write */
- NULL, /* stop */
- NULL, /* start */
- NULL, /* alive */
- NULL, /* set_nonblock_state */
- NULL, /* free */
- NULL, /* use_float */
- "null",
- NULL,
- NULL,
- NULL, /* write_avail */
- NULL
-};
-
-static const audio_driver_t *audio_drivers[] = {
-#ifdef HAVE_ALSA
- &audio_alsa,
-#if !defined(__QNX__) && defined(HAVE_THREADS)
- &audio_alsathread,
-#endif
-#endif
-#ifdef HAVE_TINYALSA
- &audio_tinyalsa,
-#endif
-#if defined(HAVE_AUDIOIO)
- &audio_audioio,
-#endif
-#if defined(HAVE_OSS) || defined(HAVE_OSS_BSD)
- &audio_oss,
-#endif
-#ifdef HAVE_RSOUND
- &audio_rsound,
-#endif
-#ifdef HAVE_COREAUDIO
- &audio_coreaudio,
-#endif
-#ifdef HAVE_COREAUDIO3
- &audio_coreaudio3,
-#endif
-#ifdef HAVE_AL
- &audio_openal,
-#endif
-#ifdef HAVE_SL
- &audio_opensl,
-#endif
-#ifdef HAVE_ROAR
- &audio_roar,
-#endif
-#ifdef HAVE_JACK
- &audio_jack,
-#endif
-#if defined(HAVE_SDL) || defined(HAVE_SDL2)
- &audio_sdl,
-#endif
-#ifdef HAVE_XAUDIO
- &audio_xa,
-#endif
-#ifdef HAVE_DSOUND
- &audio_dsound,
-#endif
-#ifdef HAVE_WASAPI
- &audio_wasapi,
-#endif
-#ifdef HAVE_PULSE
- &audio_pulse,
-#endif
-#if defined(__PSL1GHT__) || defined(__PS3__)
- &audio_ps3,
-#endif
-#ifdef XENON
- &audio_xenon360,
-#endif
-#ifdef GEKKO
- &audio_gx,
-#endif
-#ifdef WIIU
- &audio_ax,
-#endif
-#ifdef EMSCRIPTEN
- &audio_rwebaudio,
-#endif
-#if defined(PSP) || defined(VITA) || defined(ORBIS)
- &audio_psp,
-#endif
-#if defined(PS2)
- &audio_ps2,
-#endif
-#ifdef _3DS
- &audio_ctr_csnd,
- &audio_ctr_dsp,
-#ifdef HAVE_THREADS
- &audio_ctr_dsp_thread,
-#endif
-#endif
-#ifdef SWITCH
- &audio_switch,
- &audio_switch_thread,
-#ifdef HAVE_LIBNX
- &audio_switch_libnx_audren,
- &audio_switch_libnx_audren_thread,
-#endif
-#endif
- &audio_null,
- NULL,
-};
-
static const video_display_server_t dispserv_null = {
NULL, /* init */
NULL, /* destroy */
@@ -762,8 +640,6 @@ typedef struct discord_state discord_state_t;
struct rarch_state
{
- double audio_source_ratio_original;
- double audio_source_ratio_current;
struct retro_system_av_info video_driver_av_info; /* double alignment */
#ifdef HAVE_CRTSWITCHRES
videocrt_switch_t crt_switch_st; /* double alignment */
@@ -788,8 +664,6 @@ struct rarch_state
#endif
#endif
- uint64_t audio_driver_free_samples_count;
-
#ifdef HAVE_RUNAHEAD
uint64_t runahead_last_frame_count;
#endif
@@ -799,11 +673,9 @@ struct rarch_state
struct retro_camera_callback camera_cb; /* uint64_t alignment */
struct string_list *subsystem_fullpaths;
- struct string_list *audio_driver_devices_list;
uint8_t *video_driver_record_gpu_buffer;
bool *load_no_content_hook;
- float *audio_driver_output_samples_buf;
#if defined(HAVE_RUNAHEAD)
#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
char *secondary_library_path;
@@ -811,9 +683,6 @@ struct rarch_state
retro_ctx_load_content_info_t *load_content_info;
#endif
- const record_driver_t *recording_driver;
- void *recording_data;
-
#ifdef HAVE_THREADS
slock_t *display_lock;
slock_t *context_lock;
@@ -861,20 +730,6 @@ struct rarch_state
void *video_context_data;
-#ifdef HAVE_REWIND
- int16_t *audio_driver_rewind_buf;
-#endif
- int16_t *audio_driver_output_samples_conv_buf;
-
-#ifdef HAVE_DSP_FILTER
- retro_dsp_filter_t *audio_driver_dsp;
-#endif
- const retro_resampler_t *audio_driver_resampler;
-
- void *audio_driver_resampler_data;
- const audio_driver_t *current_audio;
- void *audio_driver_context_audio_data;
-
#ifdef HAVE_HID
const void *hid_data;
#endif
@@ -907,7 +762,6 @@ struct rarch_state
content_state_t content_st; /* ptr alignment */
struct retro_hw_render_callback hw_render; /* ptr alignment */
retro_input_state_t input_state_callback_original; /* ptr alignment */
- struct retro_audio_callback audio_callback; /* ptr alignment */
video_driver_frame_t frame_bak; /* ptr alignment */
struct rarch_dir_shader_list dir_shader_list; /* ptr alignment */
#ifdef HAVE_RUNAHEAD
@@ -923,11 +777,6 @@ struct rarch_state
struct retro_callbacks secondary_callbacks; /* ptr alignment */
#endif
#endif
-#ifdef HAVE_AUDIOMIXER
- struct audio_mixer_stream
- audio_mixer_streams[AUDIO_MIXER_MAX_SYSTEM_STREAMS];
- /* ptr alignment */
-#endif
#ifdef HAVE_NETWORKING
struct netplay_room netplay_host_room; /* ptr alignment */
#endif
@@ -948,22 +797,8 @@ struct rarch_state
uintptr_t video_driver_display;
uintptr_t video_driver_window;
- size_t recording_gpu_width;
- size_t recording_gpu_height;
-
size_t frame_cache_pitch;
- size_t audio_driver_chunk_size;
- size_t audio_driver_chunk_nonblock_size;
- size_t audio_driver_chunk_block_size;
-
-#ifdef HAVE_REWIND
- size_t audio_driver_rewind_ptr;
- size_t audio_driver_rewind_size;
-#endif
- size_t audio_driver_buffer_size;
- size_t audio_driver_data_ptr;
-
#ifdef HAVE_RUNAHEAD
size_t runahead_save_state_size;
#endif
@@ -998,9 +833,6 @@ struct rarch_state
#endif
unsigned fastforward_after_frames;
- unsigned recording_width;
- unsigned recording_height;
-
#ifdef HAVE_VIDEO_FILTER
unsigned video_driver_state_scale;
unsigned video_driver_state_out_bpp;
@@ -1013,24 +845,13 @@ struct rarch_state
unsigned server_port_deferred;
#endif
- unsigned audio_driver_free_samples_buf[
- AUDIO_BUFFER_FREE_SAMPLES_COUNT];
unsigned perf_ptr_rarch;
unsigned perf_ptr_libretro;
- float *audio_driver_input_data;
float video_driver_core_hz;
float video_driver_aspect_ratio;
float video_refresh_rate_original;
-#ifdef HAVE_AUDIOMIXER
- float audio_driver_mixer_volume_gain;
-#endif
-
- float audio_driver_rate_control_delta;
- float audio_driver_input;
- float audio_driver_volume_gain;
-
enum rarch_core_type current_core_type;
enum rarch_core_type explicit_current_core_type;
enum rotation initial_screen_orientation;
@@ -1044,7 +865,6 @@ struct rarch_state
#endif
enum rarch_display_type video_driver_display_type;
enum poll_type_override_t core_poll_type_override;
- enum resampler_quality audio_driver_resampler_quality;
/**
* dynamic.c:dynamic_request_hw_context will try to set flag data when the context
@@ -1090,7 +910,6 @@ struct rarch_state
char current_savefile_dir[PATH_MAX_LENGTH];
char current_savestate_dir[PATH_MAX_LENGTH];
char dir_savestate[PATH_MAX_LENGTH];
- char audio_driver_resampler_ident[64];
#ifdef HAVE_GFX_WIDGETS
bool widgets_active;
@@ -1191,7 +1010,6 @@ struct rarch_state
bool bluetooth_driver_active;
bool wifi_driver_active;
bool video_driver_active;
- bool audio_driver_active;
bool camera_driver_active;
#ifdef HAVE_VIDEO_FILTER
bool video_driver_state_out_rgb32;
@@ -1201,16 +1019,9 @@ struct rarch_state
bool video_started_fullscreen;
- bool audio_driver_control;
- bool audio_driver_mute_enable;
- bool audio_driver_use_float;
-
- bool audio_suspended;
-
#ifdef HAVE_RUNAHEAD
bool runahead_save_state_size_known;
bool request_fast_savestate;
- bool hard_disable_audio;
bool input_is_dirty;
#endif
@@ -1223,7 +1034,6 @@ struct rarch_state
bool has_set_netplay_check_frames;
#endif
- bool recording_enable;
bool streaming_enable;
bool main_ui_companion_is_on_foreground;
@@ -1236,9 +1046,4 @@ struct rarch_state
bool runahead_secondary_core_available;
bool runahead_force_input_dirty;
#endif
-
-#ifdef HAVE_AUDIOMIXER
- bool audio_driver_mixer_mute_enable;
- bool audio_mixer_active;
-#endif
};
diff --git a/retroarch_fwd_decls.h b/retroarch_fwd_decls.h
index f7f4cf9112..efac075e8e 100644
--- a/retroarch_fwd_decls.h
+++ b/retroarch_fwd_decls.h
@@ -73,23 +73,6 @@ static void ui_companion_driver_init_first(
settings_t *settings,
struct rarch_state *p_rarch);
-static bool audio_driver_stop(struct rarch_state *p_rarch);
-static bool audio_driver_start(struct rarch_state *p_rarch,
- bool is_shutdown);
-
-static bool recording_init(settings_t *settings,
- struct rarch_state *p_rarch);
-static bool recording_deinit(struct rarch_state *p_rarch);
-
-#ifdef HAVE_AUDIOMIXER
-static void audio_mixer_play_stop_sequential_cb(
- audio_mixer_sound_t *sound, unsigned reason);
-static void audio_mixer_play_stop_cb(
- audio_mixer_sound_t *sound, unsigned reason);
-static void audio_mixer_menu_stop_cb(
- audio_mixer_sound_t *sound, unsigned reason);
-#endif
-
static void video_driver_gpu_record_deinit(struct rarch_state *p_rarch);
static retro_proc_address_t video_driver_get_proc_address(const char *sym);
static uintptr_t video_driver_get_current_framebuffer(void);
diff --git a/runloop.h b/runloop.h
index c6c750a1ae..3a27f72d51 100644
--- a/runloop.h
+++ b/runloop.h
@@ -35,7 +35,7 @@
#include "core_option_manager.h"
-enum runloop_state
+enum runloop_state_enum
{
RUNLOOP_STATE_ITERATE = 0,
RUNLOOP_STATE_POLLED_AND_SLEEP,
diff --git a/state_manager.c b/state_manager.c
index 2453f8e4e1..844431d0aa 100644
--- a/state_manager.c
+++ b/state_manager.c
@@ -33,6 +33,7 @@
#include "retroarch.h"
#include "verbosity.h"
#include "content.h"
+#include "audio/audio_driver.h"
#ifdef HAVE_NETWORKING
#include "network/netplay/netplay.h"
diff --git a/tasks/task_audio_mixer.c b/tasks/task_audio_mixer.c
index 5e6fa46933..aa63fd58f8 100644
--- a/tasks/task_audio_mixer.c
+++ b/tasks/task_audio_mixer.c
@@ -29,6 +29,7 @@
#include
#include "../file_path_special.h"
+#include "../audio/audio_driver.h"
#include "../retroarch.h"
#include "../verbosity.h"
diff --git a/tasks/task_content.c b/tasks/task_content.c
index ab0e983401..cf917bd95e 100644
--- a/tasks/task_content.c
+++ b/tasks/task_content.c
@@ -90,6 +90,7 @@
#include "../playlist.h"
#include "../paths.h"
#include "../retroarch.h"
+#include "../runloop.h"
#include "../verbosity.h"
#include "../msg_hash.h"