diff --git a/Makefile.common b/Makefile.common
index 31e61bf99f..cdb17952b4 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -205,7 +205,6 @@ OBJ += frontend/frontend.o \
file_path_special.o \
file_path_str.o \
$(LIBRETRO_COMM_DIR)/hash/rhash.o \
- audio/audio_driver.o \
$(LIBRETRO_COMM_DIR)/audio/audio_mixer.o \
input/common/input_hid_common.o \
input/input_driver.o \
diff --git a/audio/audio_driver.c b/audio/audio_driver.c
deleted file mode 100644
index f432dd1e16..0000000000
--- a/audio/audio_driver.c
+++ /dev/null
@@ -1,1861 +0,0 @@
-/* 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 .
- */
-
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-#include "audio_driver.h"
-#include "audio_thread_wrapper.h"
-#include "../gfx/video_driver.h"
-#include "../record/record_driver.h"
-#include "../frontend/frontend_driver.h"
-#include "../tasks/task_audio_mixer.h"
-#include "../tasks/tasks_internal.h"
-
-#include "../command.h"
-#include "../driver.h"
-#include "../configuration.h"
-#include "../retroarch.h"
-#include "../verbosity.h"
-#include "../list_special.h"
-#include "../file_path_special.h"
-#include "../content.h"
-
-#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
-
-#define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac"
-
-/**
- * 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))
-
-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
-#ifdef __CELLOS_LV2__
- &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,
-#endif
-#ifdef SWITCH
- &audio_switch_thread,
- &audio_switch,
-#endif
- &audio_null,
- NULL,
-};
-
-static struct audio_mixer_stream audio_mixer_streams[AUDIO_MIXER_MAX_SYSTEM_STREAMS] = {{0}};
-
-static size_t audio_driver_chunk_size = 0;
-static size_t audio_driver_chunk_nonblock_size = 0;
-static size_t audio_driver_chunk_block_size = 0;
-
-static size_t audio_driver_rewind_ptr = 0;
-static size_t audio_driver_rewind_size = 0;
-
-static int16_t *audio_driver_rewind_buf = NULL;
-static int16_t *audio_driver_output_samples_conv_buf = NULL;
-
-static unsigned audio_driver_free_samples_buf[AUDIO_BUFFER_FREE_SAMPLES_COUNT];
-static uint64_t audio_driver_free_samples_count = 0;
-
-static size_t audio_driver_buffer_size = 0;
-static size_t audio_driver_data_ptr = 0;
-
-static bool audio_driver_control = false;
-static bool audio_driver_mixer_mute_enable = false;
-static bool audio_driver_mute_enable = false;
-static bool audio_driver_use_float = false;
-static bool audio_driver_active = false;
-static bool audio_mixer_active = false;
-
-static float audio_driver_rate_control_delta = 0.0f;
-static float audio_driver_input = 0.0f;
-static float audio_driver_volume_gain = 0.0f;
-static float audio_driver_mixer_volume_gain = 0.0f;
-
-static float *audio_driver_input_data = NULL;
-static float *audio_driver_output_samples_buf = NULL;
-
-static double audio_source_ratio_original = 0.0f;
-static double audio_source_ratio_current = 0.0f;
-
-static struct retro_audio_callback audio_callback = {0};
-
-static retro_dsp_filter_t *audio_driver_dsp = NULL;
-static struct string_list *audio_driver_devices_list = NULL;
-static const retro_resampler_t *audio_driver_resampler = NULL;
-
-static void *audio_driver_resampler_data = NULL;
-static const audio_driver_t *current_audio = NULL;
-static void *audio_driver_context_audio_data = NULL;
-
-static bool audio_suspended = false;
-static bool audio_is_threaded = false;
-
-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);
-
-static enum resampler_quality audio_driver_get_resampler_quality(void)
-{
- settings_t *settings = config_get_ptr();
-
- if (!settings)
- return RESAMPLER_QUALITY_DONTCARE;
-
- return (enum resampler_quality)settings->uints.audio_resampler_quality;
-}
-
-audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i)
-{
- if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
- return NULL;
- return &audio_mixer_streams[i];
-}
-
-const char *audio_driver_mixer_get_stream_name(unsigned i)
-{
- if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
- return "N/A";
- if (!string_is_empty(audio_mixer_streams[i].name))
- return audio_mixer_streams[i].name;
- return "N/A";
-}
-
-/**
- * compute_audio_buffer_statistics:
- *
- * Computes audio buffer statistics.
- *
- **/
-bool compute_audio_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;
- unsigned samples = MIN(
- (unsigned)audio_driver_free_samples_count,
- AUDIO_BUFFER_FREE_SAMPLES_COUNT);
-
- if (!stats || samples < 3)
- return false;
-
- stats->samples = (unsigned)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 += audio_driver_free_samples_buf[i];
-
- avg = (unsigned)accum / (samples - 1);
-
- for (i = 1; i < samples; i++)
- {
- int diff = avg - 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
- / audio_driver_buffer_size) * 100.0;
- stats->std_deviation_percentage = ((float)stddev
- / audio_driver_buffer_size) * 100.0;
-#endif
-
- low_water_size = (unsigned)(audio_driver_buffer_size * 3 / 4);
- high_water_size = (unsigned)(audio_driver_buffer_size / 4);
-
- for (i = 1; i < samples; i++)
- {
- if (audio_driver_free_samples_buf[i] >= low_water_size)
- low_water_count++;
- else if (audio_driver_free_samples_buf[i] <= high_water_size)
- high_water_count++;
- }
-
- stats->close_to_underrun = (100.0 * low_water_count) / (samples - 1);
- stats->close_to_blocking = (100.0 * high_water_count) / (samples - 1);
-
- return true;
-}
-
-static void report_audio_buffer_statistics(void)
-{
- audio_statistics_t audio_stats = {0.0f};
- if (!compute_audio_buffer_statistics(&audio_stats))
- return;
-
-#ifdef DEBUG
- 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
-}
-
-/**
- * audio_driver_find_handle:
- * @idx : index of driver to get handle to.
- *
- * Returns: handle to audio driver at index. Can be NULL
- * if nothing found.
- **/
-const void *audio_driver_find_handle(int idx)
-{
- const void *drv = audio_drivers[idx];
- if (!drv)
- return NULL;
- return drv;
-}
-
-/**
- * audio_driver_find_ident:
- * @idx : index of driver to get handle to.
- *
- * Returns: Human-readable identifier of audio driver at index. Can be NULL
- * if nothing found.
- **/
-const char *audio_driver_find_ident(int idx)
-{
- const audio_driver_t *drv = audio_drivers[idx];
- if (!drv)
- return NULL;
- return drv->ident;
-}
-
-/**
- * config_get_audio_driver_options:
- *
- * Get an enumerated list of all audio driver names, separated by '|'.
- *
- * Returns: string listing of all audio driver names, separated by '|'.
- **/
-const char *config_get_audio_driver_options(void)
-{
- return char_list_new_special(STRING_LIST_AUDIO_DRIVERS, NULL);
-}
-
-static bool audio_driver_deinit_internal(void)
-{
- settings_t *settings = config_get_ptr();
-
- if (current_audio && current_audio->free)
- {
- if (audio_driver_context_audio_data)
- current_audio->free(audio_driver_context_audio_data);
- audio_driver_context_audio_data = NULL;
- }
-
- if (audio_driver_output_samples_conv_buf)
- free(audio_driver_output_samples_conv_buf);
- audio_driver_output_samples_conv_buf = NULL;
-
- audio_driver_data_ptr = 0;
-
- if (audio_driver_rewind_buf)
- free(audio_driver_rewind_buf);
- audio_driver_rewind_buf = NULL;
-
- audio_driver_rewind_size = 0;
-
- if (settings && !settings->bools.audio_enable)
- {
- audio_driver_active = false;
- return false;
- }
-
- audio_driver_deinit_resampler();
-
- if (audio_driver_input_data)
- free(audio_driver_input_data);
- audio_driver_input_data = NULL;
-
- if (audio_driver_output_samples_buf)
- free(audio_driver_output_samples_buf);
- audio_driver_output_samples_buf = NULL;
-
- command_event(CMD_EVENT_DSP_FILTER_DEINIT, NULL);
-
- report_audio_buffer_statistics();
-
- return true;
-}
-
-static void audio_driver_mixer_init(unsigned audio_out_rate)
-{
- audio_mixer_init(audio_out_rate);
-}
-
-static bool audio_driver_init_internal(bool audio_cb_inited)
-{
- unsigned new_rate = 0;
- float *aud_inp_data = NULL;
- float *samples_buf = NULL;
- int16_t *conv_buf = NULL;
- int16_t *rewind_buf = NULL;
- size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
- settings_t *settings = config_get_ptr();
- /* Accomodate rewind since at some point we might have two full buffers. */
- size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO *
- settings->floats.slowmotion_ratio;
-
- convert_s16_to_float_init_simd();
- convert_float_to_s16_init_simd();
-
- conv_buf = (int16_t*)malloc(outsamples_max
- * sizeof(int16_t));
- /* Used for recording even if audio isn't enabled. */
- retro_assert(conv_buf != NULL);
-
- if (!conv_buf)
- goto error;
-
- audio_driver_output_samples_conv_buf = conv_buf;
- audio_driver_chunk_block_size = AUDIO_CHUNK_SIZE_BLOCKING;
- audio_driver_chunk_nonblock_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
- audio_driver_chunk_size = audio_driver_chunk_block_size;
-
- /* Needs to be able to hold full content of a full max_bufsamples
- * in addition to its own. */
- rewind_buf = (int16_t*)malloc(max_bufsamples * sizeof(int16_t));
- retro_assert(rewind_buf != NULL);
-
- if (!rewind_buf)
- goto error;
-
- audio_driver_rewind_buf = rewind_buf;
- audio_driver_rewind_size = max_bufsamples;
-
- if (!settings->bools.audio_enable)
- {
- audio_driver_active = false;
- return false;
- }
-
- audio_driver_find_driver();
-#ifdef HAVE_THREADS
- if (audio_cb_inited)
- {
- audio_is_threaded = true;
- RARCH_LOG("[Audio]: Starting threaded audio driver ...\n");
- if (!audio_init_thread(
- ¤t_audio,
- &audio_driver_context_audio_data,
- *settings->arrays.audio_device
- ? settings->arrays.audio_device : NULL,
- settings->uints.audio_out_rate, &new_rate,
- settings->uints.audio_latency,
- settings->uints.audio_block_frames,
- current_audio))
- {
- RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
- retroarch_fail(1, "audio_driver_init_internal()");
- }
- }
- else
-#endif
- {
- audio_is_threaded = false;
- audio_driver_context_audio_data =
- current_audio->init(*settings->arrays.audio_device ?
- settings->arrays.audio_device : NULL,
- settings->uints.audio_out_rate,
- settings->uints.audio_latency,
- settings->uints.audio_block_frames,
- &new_rate);
- }
-
- if (new_rate != 0)
- {
- configuration_set_int(settings, settings->uints.audio_out_rate, new_rate);
- }
-
- if (!audio_driver_context_audio_data)
- {
- RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
- audio_driver_active = false;
- }
-
- audio_driver_use_float = false;
- if ( audio_driver_active
- && current_audio->use_float(audio_driver_context_audio_data))
- audio_driver_use_float = true;
-
- if (!settings->bools.audio_sync && audio_driver_active)
- {
- command_event(CMD_EVENT_AUDIO_SET_NONBLOCKING_STATE, NULL);
- audio_driver_chunk_size = audio_driver_chunk_nonblock_size;
- }
-
- if (audio_driver_input <= 0.0f)
- {
- /* Should never happen. */
- RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n",
- audio_driver_input, settings->uints.audio_out_rate);
- audio_driver_input = settings->uints.audio_out_rate;
- }
-
- audio_source_ratio_original = audio_source_ratio_current =
- (double)settings->uints.audio_out_rate / audio_driver_input;
-
- if (!retro_resampler_realloc(
- &audio_driver_resampler_data,
- &audio_driver_resampler,
- settings->arrays.audio_resampler,
- audio_driver_get_resampler_quality(),
- audio_source_ratio_original))
- {
- RARCH_ERR("Failed to initialize resampler \"%s\".\n",
- settings->arrays.audio_resampler);
- audio_driver_active = false;
- }
-
- aud_inp_data = (float*)malloc(max_bufsamples * sizeof(float));
- retro_assert(aud_inp_data != NULL);
-
- if (!aud_inp_data)
- goto error;
-
- audio_driver_input_data = aud_inp_data;
- audio_driver_data_ptr = 0;
-
- retro_assert(settings->uints.audio_out_rate <
- audio_driver_input * AUDIO_MAX_RATIO);
-
- samples_buf = (float*)malloc(outsamples_max * sizeof(float));
-
- retro_assert(samples_buf != NULL);
-
- if (!samples_buf)
- goto error;
-
- audio_driver_output_samples_buf = samples_buf;
- audio_driver_control = false;
-
- if (
- !audio_cb_inited
- && audio_driver_active
- && settings->bools.audio_rate_control
- )
- {
- /* Audio rate control requires write_avail
- * and buffer_size to be implemented. */
- if (current_audio->buffer_size)
- {
- audio_driver_buffer_size =
- current_audio->buffer_size(audio_driver_context_audio_data);
- 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);
-
- audio_driver_free_samples_count = 0;
-
- audio_driver_mixer_init(settings->uints.audio_out_rate);
-
- /* Threaded driver is initially stopped. */
- if (
- audio_driver_active
- && audio_cb_inited
- )
- audio_driver_start(false);
-
- return true;
-
-error:
- return audio_driver_deinit();
-}
-
-void audio_driver_set_nonblocking_state(bool enable)
-{
- settings_t *settings = config_get_ptr();
- if (
- audio_driver_active
- && audio_driver_context_audio_data
- )
- current_audio->set_nonblock_state(
- audio_driver_context_audio_data,
- settings->bools.audio_sync ? enable : true);
-
- audio_driver_chunk_size = enable ?
- audio_driver_chunk_nonblock_size :
- audio_driver_chunk_block_size;
-}
-
-/**
- * audio_driver_flush:
- * @data : pointer to audio buffer.
- * @right : amount of samples to write.
- *
- * Writes audio samples to audio driver. Will first
- * perform DSP processing (if enabled) and resampling.
- **/
-static void audio_driver_flush(const int16_t *data, size_t samples,
- bool is_slowmotion)
-{
- struct resampler_data src_data;
- float audio_volume_gain = !audio_driver_mute_enable ?
- audio_driver_volume_gain : 0.0f;
-
- src_data.data_out = NULL;
- src_data.output_frames = 0;
-
- convert_s16_to_float(audio_driver_input_data, data, samples,
- audio_volume_gain);
-
- src_data.data_in = audio_driver_input_data;
- src_data.input_frames = samples >> 1;
-
- if (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 = audio_driver_input_data;
- dsp_data.input_frames = (unsigned)(samples >> 1);
-
- retro_dsp_filter_process(audio_driver_dsp, &dsp_data);
-
- if (dsp_data.output)
- {
- src_data.data_in = dsp_data.output;
- src_data.input_frames = dsp_data.output_frames;
- }
- }
-
- src_data.data_out = audio_driver_output_samples_buf;
-
- if (audio_driver_control)
- {
- /* Readjust the audio input rate. */
- int half_size = (int)(audio_driver_buffer_size / 2);
- int avail =
- (int)current_audio->write_avail(audio_driver_context_audio_data);
- int delta_mid = avail - half_size;
- double direction = (double)delta_mid / half_size;
- double adjust = 1.0 + audio_driver_rate_control_delta * direction;
- unsigned write_idx = audio_driver_free_samples_count++ &
- (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
-
- audio_driver_free_samples_buf
- [write_idx] = avail;
- audio_source_ratio_current =
- 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) / audio_driver_buffer_size));
- RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
- audio_source_ratio_current,
- audio_source_ratio_original);
- }
-#endif
- }
-
- src_data.ratio = audio_source_ratio_current;
-
- if (is_slowmotion)
- {
- settings_t *settings = config_get_ptr();
- src_data.ratio *= settings->floats.slowmotion_ratio;
- }
-
- audio_driver_resampler->process(audio_driver_resampler_data, &src_data);
-
- if (audio_mixer_active)
- {
- bool override = audio_driver_mixer_mute_enable ? true :
- (audio_driver_mixer_volume_gain != 1.0f) ? true : false;
- float mixer_gain = !audio_driver_mixer_mute_enable ?
- audio_driver_mixer_volume_gain : 0.0f;
- audio_mixer_mix(audio_driver_output_samples_buf,
- src_data.output_frames, mixer_gain, override);
- }
-
- {
- const void *output_data = audio_driver_output_samples_buf;
- unsigned output_frames = (unsigned)src_data.output_frames;
-
- if (audio_driver_use_float)
- output_frames *= sizeof(float);
- else
- {
- convert_float_to_s16(audio_driver_output_samples_conv_buf,
- (const float*)output_data, output_frames * 2);
-
- output_data = audio_driver_output_samples_conv_buf;
- output_frames *= sizeof(int16_t);
- }
-
- if (current_audio->write(audio_driver_context_audio_data,
- output_data, output_frames * 2) < 0)
- audio_driver_active = false;
- }
-}
-
-/**
- * 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)
-{
- bool is_perfcnt_enable = false;
- bool is_paused = false;
- bool is_idle = false;
- bool is_slowmotion = false;
-
- if (audio_suspended)
- return;
-
- audio_driver_output_samples_conv_buf[audio_driver_data_ptr++] = left;
- audio_driver_output_samples_conv_buf[audio_driver_data_ptr++] = right;
-
- if (audio_driver_data_ptr < audio_driver_chunk_size)
- return;
-
- if (recording_data)
- recording_push_audio(audio_driver_output_samples_conv_buf,
- audio_driver_data_ptr);
-
- runloop_get_status(&is_paused, &is_idle, &is_slowmotion,
- &is_perfcnt_enable);
-
- if (!(is_paused ||
- !audio_driver_active ||
- !audio_driver_input_data ||
- !audio_driver_output_samples_buf))
- audio_driver_flush(audio_driver_output_samples_conv_buf,
- audio_driver_data_ptr, is_slowmotion);
-
- audio_driver_data_ptr = 0;
-}
-
-void audio_driver_menu_sample(void)
-{
- bool check_flush = false;
- bool is_perfcnt_enable = false;
- bool is_paused = false;
- bool is_idle = false;
- bool is_slowmotion = false;
- static int16_t samples_buf[1024] = {0};
- struct retro_system_av_info *av_info = video_viewport_get_system_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;
- runloop_get_status(&is_paused, &is_idle, &is_slowmotion,
- &is_perfcnt_enable);
- check_flush = !(
- is_paused ||
- !audio_driver_active ||
- !audio_driver_input_data ||
- !audio_driver_output_samples_buf);
-
- while (sample_count > 1024)
- {
- if (recording_data)
- recording_push_audio(samples_buf, 1024);
- if (check_flush)
- audio_driver_flush(samples_buf, 1024, is_slowmotion);
- sample_count -= 1024;
- }
- if (recording_data)
- recording_push_audio(samples_buf, sample_count);
- if (check_flush)
- audio_driver_flush(samples_buf, sample_count, is_slowmotion);
-}
-
-/**
- * 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)
-{
- bool is_perfcnt_enable = false;
- bool is_paused = false;
- bool is_idle = false;
- bool is_slowmotion = false;
-
- if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
- frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
-
- if (audio_suspended)
- return frames;
-
- if (recording_data)
- recording_push_audio(data, frames << 1);
-
- runloop_get_status(&is_paused, &is_idle, &is_slowmotion,
- &is_perfcnt_enable);
- if (!(
- is_paused ||
- !audio_driver_active ||
- !audio_driver_input_data ||
- !audio_driver_output_samples_buf))
- audio_driver_flush(data, frames << 1, is_slowmotion);
-
- return frames;
-}
-
-/**
- * audio_driver_sample_rewind:
- * @left : value of the left audio channel.
- * @right : value of the right audio channel.
- *
- * Audio sample render callback function (rewind version).
- * This callback function will be used instead of
- * audio_driver_sample when rewinding is activated.
- **/
-void audio_driver_sample_rewind(int16_t left, int16_t right)
-{
- if (audio_driver_rewind_ptr == 0)
- return;
-
- audio_driver_rewind_buf[--audio_driver_rewind_ptr] = right;
- audio_driver_rewind_buf[--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).
- **/
-size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames)
-{
- size_t i;
- size_t samples = frames << 1;
-
- for (i = 0; i < samples; i++)
- {
- if (audio_driver_rewind_ptr > 0)
- audio_driver_rewind_buf[--audio_driver_rewind_ptr] = data[i];
- }
-
- return frames;
-}
-
-void audio_driver_dsp_filter_free(void)
-{
- if (audio_driver_dsp)
- retro_dsp_filter_free(audio_driver_dsp);
- audio_driver_dsp = NULL;
-}
-
-void audio_driver_dsp_filter_init(const char *device)
-{
- struct string_list *plugs = NULL;
-#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
- char *basedir = (char*)calloc(PATH_MAX_LENGTH, sizeof(*basedir));
- char *ext_name = (char*)calloc(PATH_MAX_LENGTH, sizeof(*ext_name));
- size_t str_size = PATH_MAX_LENGTH * sizeof(char);
- fill_pathname_basedir(basedir, device, str_size);
-
- if (!frontend_driver_get_core_extension(ext_name, str_size))
- goto error;
-
- plugs = dir_list_new(basedir, ext_name, false, true, false, false);
- if (!plugs)
- goto error;
-#endif
- audio_driver_dsp = retro_dsp_filter_new(
- device, plugs, audio_driver_input);
- if (!audio_driver_dsp)
- goto error;
-
-#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
- free(basedir);
- free(ext_name);
-#endif
-
- return;
-
-error:
-#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
- free(basedir);
- free(ext_name);
-#endif
- if (!audio_driver_dsp)
- RARCH_ERR("[DSP]: Failed to initialize DSP filter \"%s\".\n", device);
-}
-
-void audio_driver_set_buffer_size(size_t bufsize)
-{
- audio_driver_buffer_size = bufsize;
-}
-
-void audio_driver_monitor_adjust_system_rates(void)
-{
- float timing_skew;
- settings_t *settings = config_get_ptr();
- float video_refresh_rate = settings->floats.video_refresh_rate;
- float max_timing_skew = settings->floats.audio_max_timing_skew;
- struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
- const struct retro_system_timing *info =
- (const struct retro_system_timing*)&av_info->timing;
-
- if (info->sample_rate <= 0.0)
- return;
-
- timing_skew = fabs(1.0f - info->fps / video_refresh_rate);
- audio_driver_input = info->sample_rate;
-
- if (timing_skew <= max_timing_skew && !settings->bools.vrr_runloop_enable)
- audio_driver_input *= (video_refresh_rate / info->fps);
-
- RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
- audio_driver_input);
-}
-
-void audio_driver_setup_rewind(void)
-{
- unsigned i;
-
- /* Push audio ready to be played. */
- audio_driver_rewind_ptr = audio_driver_rewind_size;
-
- for (i = 0; i < audio_driver_data_ptr; i += 2)
- {
- if (audio_driver_rewind_ptr > 0)
- audio_driver_rewind_buf[--audio_driver_rewind_ptr] =
- audio_driver_output_samples_conv_buf[i + 1];
-
- if (audio_driver_rewind_ptr > 0)
- audio_driver_rewind_buf[--audio_driver_rewind_ptr] =
- audio_driver_output_samples_conv_buf[i + 0];
- }
-
- audio_driver_data_ptr = 0;
-}
-
-bool audio_driver_find_driver(void)
-{
- int i;
- driver_ctx_info_t drv;
- settings_t *settings = config_get_ptr();
-
- drv.label = "audio_driver";
- drv.s = settings->arrays.audio_driver;
-
- driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv);
-
- i = (int)drv.len;
-
- if (i >= 0)
- current_audio = (const audio_driver_t*)audio_driver_find_handle(i);
- else
- {
- if (verbosity_is_enabled())
- {
- unsigned d;
- RARCH_ERR("Couldn't find any audio driver named \"%s\"\n",
- settings->arrays.audio_driver);
- RARCH_LOG_OUTPUT("Available audio drivers are:\n");
- for (d = 0; audio_driver_find_handle(d); d++)
- RARCH_LOG_OUTPUT("\t%s\n", audio_driver_find_ident(d));
- RARCH_WARN("Going to default to first audio driver...\n");
- }
-
- current_audio = (const audio_driver_t*)audio_driver_find_handle(0);
-
- if (!current_audio)
- retroarch_fail(1, "audio_driver_find()");
- }
-
- return true;
-}
-
-void audio_driver_deinit_resampler(void)
-{
- if (audio_driver_resampler && audio_driver_resampler_data)
- audio_driver_resampler->free(audio_driver_resampler_data);
- audio_driver_resampler = NULL;
- audio_driver_resampler_data = NULL;
-}
-
-bool audio_driver_free_devices_list(void)
-{
- if (!current_audio || !current_audio->device_list_free
- || !audio_driver_context_audio_data)
- return false;
- current_audio->device_list_free(audio_driver_context_audio_data,
- audio_driver_devices_list);
- audio_driver_devices_list = NULL;
- return true;
-}
-
-bool audio_driver_new_devices_list(void)
-{
- if (!current_audio || !current_audio->device_list_new
- || !audio_driver_context_audio_data)
- return false;
- audio_driver_devices_list = (struct string_list*)
- current_audio->device_list_new(audio_driver_context_audio_data);
- if (!audio_driver_devices_list)
- return false;
- return true;
-}
-
-bool audio_driver_init(void)
-{
- return audio_driver_init_internal(audio_callback.callback != NULL);
-}
-
-bool audio_driver_get_devices_list(void **data)
-{
- struct string_list**ptr = (struct string_list**)data;
- if (!ptr)
- return false;
- *ptr = audio_driver_devices_list;
- return true;
-}
-
-bool audio_driver_mixer_extension_supported(const char *ext)
-{
- union string_list_elem_attr attr;
- unsigned i;
- bool ret = false;
- struct string_list *str_list = string_list_new();
-
- attr.i = 0;
-
-#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_free(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_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_mixer_streams[i].name))
- free(audio_mixer_streams[i].name);
-
- audio_mixer_streams[i].name = NULL;
- audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
- audio_mixer_streams[i].volume = 0.0f;
- audio_mixer_streams[i].buf = NULL;
- audio_mixer_streams[i].stop_cb = NULL;
- audio_mixer_streams[i].handle = NULL;
- 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)
-{
- int idx = audio_mixer_find_index(sound);
-
- switch (reason)
- {
- case AUDIO_MIXER_SOUND_FINISHED:
- if (idx >= 0)
- {
- unsigned i = (unsigned)idx;
- audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
- 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)
-{
- 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_mixer_streams[i].name))
- free(audio_mixer_streams[i].name);
-
- if (i < AUDIO_MIXER_MAX_STREAMS)
- audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER;
- else
- audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_SYSTEM;
-
- audio_mixer_streams[i].name = NULL;
- audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
- audio_mixer_streams[i].volume = 0.0f;
- audio_mixer_streams[i].buf = NULL;
- audio_mixer_streams[i].stop_cb = NULL;
- audio_mixer_streams[i].handle = NULL;
- audio_mixer_streams[i].voice = NULL;
-
- i++;
-
- for (; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
- {
- if (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 = (type == AUDIO_STREAM_TYPE_USER) ? 0 : AUDIO_MIXER_MAX_STREAMS;
- unsigned count = (type == AUDIO_STREAM_TYPE_USER) ? AUDIO_MIXER_MAX_STREAMS : AUDIO_MIXER_MAX_SYSTEM_STREAMS;
- for (; i < count; i++)
- {
- if (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)
-{
- 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;
- 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);
- 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, stop_cb);
- break;
- case AUDIO_STREAM_STATE_PLAYING:
- voice = audio_mixer_play(handle, looped, params->volume, 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, stop_cb);
- break;
- default:
- break;
- }
-
- audio_mixer_active = true;
-
- audio_mixer_streams[free_slot].name = !string_is_empty(params->basename) ? strdup(params->basename) : NULL;
- audio_mixer_streams[free_slot].buf = buf;
- audio_mixer_streams[free_slot].handle = handle;
- audio_mixer_streams[free_slot].voice = voice;
- audio_mixer_streams[free_slot].stream_type = params->stream_type;
- audio_mixer_streams[free_slot].type = params->type;
- audio_mixer_streams[free_slot].state = params->state;
- audio_mixer_streams[free_slot].volume = params->volume;
- audio_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_mixer_streams[i].state;
-}
-
-static void audio_driver_mixer_play_stream_internal(unsigned i, unsigned type)
-{
- bool set_state = false;
-
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return;
-
- switch (audio_mixer_streams[i].state)
- {
- case AUDIO_STREAM_STATE_STOPPED:
- audio_mixer_streams[i].voice = audio_mixer_play(audio_mixer_streams[i].handle,
- (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false,
- 1.0f, audio_mixer_streams[i].stop_cb);
- set_state = true;
- break;
- case AUDIO_STREAM_STATE_PLAYING:
- case AUDIO_STREAM_STATE_PLAYING_LOOPED:
- case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
- case AUDIO_STREAM_STATE_NONE:
- break;
- }
-
- if (set_state)
- audio_mixer_streams[i].state = (enum audio_mixer_state)type;
-}
-
-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_menu_sounds(void)
-{
- settings_t *settings = config_get_ptr();
- char *sounds_path = NULL;
- char *sounds_fallback_path = NULL;
- const char *path_ok = NULL;
- const char *path_cancel = NULL;
- const char *path_notice = NULL;
- const char *path_bgm = NULL;
- struct string_list *list = NULL;
- struct string_list *list_fallback = NULL;
- unsigned i = 0;
-
- sounds_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
- sounds_fallback_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
- sounds_path[0] = sounds_fallback_path[0] = '\0';
-
- fill_pathname_join(
- sounds_fallback_path,
- settings->paths.directory_assets,
- "sounds",
- PATH_MAX_LENGTH * sizeof(char)
- );
-
- fill_pathname_application_special(sounds_path, PATH_MAX_LENGTH * sizeof(char), 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);
- char basename_noext[PATH_MAX_LENGTH];
-
- basename_noext[0] = '\0';
-
- fill_pathname_base_noext(basename_noext, path, sizeof(basename_noext));
-
- if (audio_driver_mixer_extension_supported(ext))
- {
- if (string_is_equal_noncase(basename_noext, "ok"))
- path_ok = path;
- if (string_is_equal_noncase(basename_noext, "cancel"))
- path_cancel = path;
- if (string_is_equal_noncase(basename_noext, "notice"))
- path_notice = path;
- if (string_is_equal_noncase(basename_noext, "bgm"))
- path_bgm = path;
- }
- }
-
- if (path_ok && settings->bools.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 && settings->bools.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 && settings->bools.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 && settings->bools.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);
-
-end:
- if (list)
- string_list_free(list);
- if (list_fallback)
- string_list_free(list_fallback);
- if (sounds_path)
- free(sounds_path);
- if (sounds_fallback_path)
- free(sounds_fallback_path);
-}
-
-void audio_driver_mixer_play_stream(unsigned i)
-{
- audio_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_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_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_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_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_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_mixer_streams[i].volume = vol;
-
- voice = 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;
-
- if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
- return;
-
- switch (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 = audio_mixer_streams[i].voice;
-
- if (voice)
- audio_mixer_stop(voice);
- audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
- audio_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_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_mixer_streams[i].handle;
- if (handle)
- audio_mixer_destroy(handle);
-
- if (!string_is_empty(audio_mixer_streams[i].name))
- free(audio_mixer_streams[i].name);
-
- audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
- audio_mixer_streams[i].stop_cb = NULL;
- audio_mixer_streams[i].volume = 0.0f;
- audio_mixer_streams[i].handle = NULL;
- audio_mixer_streams[i].voice = NULL;
- audio_mixer_streams[i].name = NULL;
- }
-}
-
-static void audio_driver_mixer_deinit(void)
-{
- unsigned i;
-
- 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();
-}
-
-bool audio_driver_deinit(void)
-{
- audio_driver_mixer_deinit();
- audio_driver_free_devices_list();
-
- if (!audio_driver_deinit_internal())
- return false;
- return true;
-}
-
-bool audio_driver_set_callback(const void *data)
-{
- const struct retro_audio_callback *cb = (const struct retro_audio_callback*)data;
-
- if (cb)
- audio_callback = *cb;
-
- return true;
-}
-
-bool audio_driver_enable_callback(void)
-{
- if (!audio_callback.callback)
- return false;
- if (audio_callback.set_state)
- audio_callback.set_state(true);
- return true;
-}
-
-bool audio_driver_disable_callback(void)
-{
- if (!audio_callback.callback)
- return false;
-
- if (audio_callback.set_state)
- audio_callback.set_state(false);
- return true;
-}
-
-/* Sets audio monitor rate to new value. */
-void audio_driver_monitor_set_rate(void)
-{
- settings_t *settings = config_get_ptr();
- double new_src_ratio = (double)settings->uints.audio_out_rate /
- audio_driver_input;
-
- audio_source_ratio_original = new_src_ratio;
- audio_source_ratio_current = new_src_ratio;
-}
-
-bool audio_driver_callback(void)
-{
- if (!audio_callback.callback)
- return false;
-
- if (audio_callback.callback)
- audio_callback.callback();
-
- return true;
-}
-
-bool audio_driver_has_callback(void)
-{
- if (audio_callback.callback)
- return true;
- return false;
-}
-
-bool audio_driver_toggle_mute(void)
-{
- audio_driver_mute_enable = !audio_driver_mute_enable;
- return true;
-}
-
-bool audio_driver_mixer_toggle_mute(void)
-{
- audio_driver_mixer_mute_enable = !audio_driver_mixer_mute_enable;
- return true;
-}
-
-static INLINE bool audio_driver_alive(void)
-{
- if ( current_audio
- && current_audio->alive
- && audio_driver_context_audio_data)
- return current_audio->alive(audio_driver_context_audio_data);
- return false;
-}
-
-bool audio_driver_start(bool is_shutdown)
-{
- if (!current_audio || !current_audio->start
- || !audio_driver_context_audio_data)
- goto error;
- if (!current_audio->start(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));
- audio_driver_active = false;
- return false;
-}
-
-bool audio_driver_stop(void)
-{
- if (!current_audio || !current_audio->stop
- || !audio_driver_context_audio_data)
- return false;
- if (!audio_driver_alive())
- return false;
- return current_audio->stop(audio_driver_context_audio_data);
-}
-
-void audio_driver_unset_callback(void)
-{
- audio_callback.callback = NULL;
- audio_callback.set_state = NULL;
-}
-
-void audio_driver_frame_is_reverse(void)
-{
- bool is_perfcnt_enable = false;
- bool is_paused = false;
- bool is_idle = false;
- bool is_slowmotion = false;
-
- /* We just rewound. Flush rewind audio buffer. */
- if (recording_data)
- recording_push_audio(
- audio_driver_rewind_buf + audio_driver_rewind_ptr,
- audio_driver_rewind_size - audio_driver_rewind_ptr);
-
- runloop_get_status(&is_paused, &is_idle, &is_slowmotion,
- &is_perfcnt_enable);
- if (!(
- is_paused ||
- !audio_driver_active ||
- !audio_driver_input_data ||
- !audio_driver_output_samples_buf))
- audio_driver_flush(
- audio_driver_rewind_buf + audio_driver_rewind_ptr,
- audio_driver_rewind_size - audio_driver_rewind_ptr,
- is_slowmotion);
-}
-
-void audio_driver_destroy_data(void)
-{
- audio_driver_context_audio_data = NULL;
-}
-
-void audio_driver_suspend(void)
-{
- audio_suspended = true;
-}
-
-bool audio_driver_is_suspended(void)
-{
- return audio_suspended;
-}
-
-void audio_driver_resume(void)
-{
- audio_suspended = false;
-}
-
-void audio_driver_set_active(void)
-{
- audio_driver_active = true;
-}
-
-bool audio_driver_is_active(void)
-{
- return audio_driver_active;
-}
-
-void audio_driver_destroy(void)
-{
- audio_driver_active = false;
- current_audio = NULL;
-}
-
-void audio_set_bool(enum audio_action action, bool val)
-{
- switch (action)
- {
- case AUDIO_ACTION_MIXER:
- audio_mixer_active = val;
- break;
- case AUDIO_ACTION_NONE:
- default:
- break;
- }
-}
-
-void audio_set_float(enum audio_action action, float val)
-{
- switch (action)
- {
- case AUDIO_ACTION_VOLUME_GAIN:
- audio_driver_volume_gain = db_to_gain(val);
- break;
- case AUDIO_ACTION_MIXER_VOLUME_GAIN:
- audio_driver_mixer_volume_gain = db_to_gain(val);
- break;
- case AUDIO_ACTION_RATE_CONTROL_DELTA:
- audio_driver_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_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:
- return &audio_driver_mixer_mute_enable;
- case AUDIO_ACTION_MUTE_ENABLE:
- return &audio_driver_mute_enable;
- case AUDIO_ACTION_NONE:
- default:
- break;
- }
-
- return NULL;
-}
-
-const char* audio_driver_get_ident(void)
-{
- if (!current_audio)
- return NULL;
-
- return current_audio->ident;
-}
diff --git a/audio/audio_driver.h b/audio/audio_driver.h
deleted file mode 100644
index 624ca6a453..0000000000
--- a/audio/audio_driver.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/* 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 "audio_defines.h"
-
-RETRO_BEGIN_DECLS
-
-typedef struct audio_mixer_stream
-{
- audio_mixer_sound_t *handle;
- audio_mixer_voice_t *voice;
- audio_mixer_stop_cb_t stop_cb;
- enum audio_mixer_stream_type stream_type;
- enum audio_mixer_type type;
- enum audio_mixer_state state;
- float volume;
- void *buf;
- char *name;
- size_t bufsize;
-} audio_mixer_stream_t;
-
-typedef struct audio_mixer_stream_params
-{
- float volume;
- enum audio_mixer_slot_selection_type slot_selection_type;
- unsigned slot_selection_idx;
- enum audio_mixer_stream_type stream_type;
- enum audio_mixer_type type;
- enum audio_mixer_state state;
- void *buf;
- char *basename;
- size_t bufsize;
- audio_mixer_stop_cb_t cb;
-} audio_mixer_stream_params_t;
-
-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;
-
-void audio_driver_destroy_data(void);
-
-void audio_driver_suspend(void);
-
-bool audio_driver_is_suspended(void);
-
-void audio_driver_resume(void);
-
-void audio_driver_set_active(void);
-
-bool audio_driver_is_active(void);
-
-void audio_driver_destroy(void);
-
-void audio_driver_deinit_resampler(void);
-
-bool audio_driver_free_devices_list(void);
-
-bool audio_driver_new_devices_list(void);
-
-bool audio_driver_enable_callback(void);
-
-bool audio_driver_disable_callback(void);
-
-/**
- * audio_driver_find_handle:
- * @index : index of driver to get handle to.
- *
- * Returns: handle to audio driver at index. Can be NULL
- * if nothing found.
- **/
-const void *audio_driver_find_handle(int index);
-
-/**
- * audio_driver_find_ident:
- * @index : index of driver to get handle to.
- *
- * Returns: Human-readable identifier of audio driver at index. Can be NULL
- * if nothing found.
- **/
-const char *audio_driver_find_ident(int index);
-
-void audio_driver_set_nonblocking_state(bool enable);
-
-/**
- * config_get_audio_driver_options:
- *
- * Get an enumerated list of all audio driver names, separated by '|'.
- *
- * Returns: string listing of all audio driver names, separated by '|'.
- **/
-const char* config_get_audio_driver_options(void);
-
-void audio_driver_sample(int16_t left, int16_t right);
-
-size_t audio_driver_sample_batch(const int16_t *data, size_t frames);
-
-void audio_driver_sample_rewind(int16_t left, int16_t right);
-
-size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames);
-
-bool audio_driver_mixer_extension_supported(const char *ext);
-
-void audio_driver_dsp_filter_free(void);
-
-void 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);
-
-void audio_driver_monitor_adjust_system_rates(void);
-
-bool audio_driver_set_callback(const void *data);
-
-bool audio_driver_callback(void);
-
-bool audio_driver_has_callback(void);
-
-/* Sets audio monitor rate to new value. */
-void audio_driver_monitor_set_rate(void);
-
-bool audio_driver_find_driver(void);
-
-bool audio_driver_toggle_mute(void);
-
-bool audio_driver_start(bool is_shutdown);
-
-bool audio_driver_stop(void);
-
-void audio_driver_unset_callback(void);
-
-void audio_driver_frame_is_reverse(void);
-
-void audio_set_float(enum audio_action action, float val);
-
-void audio_set_bool(enum audio_action action, bool val);
-
-void audio_unset_bool(enum audio_action action, bool val);
-
-float *audio_get_float_ptr(enum audio_action action);
-
-bool *audio_get_bool_ptr(enum audio_action action);
-
-bool audio_driver_deinit(void);
-
-bool audio_driver_init(void);
-
-void audio_driver_menu_sample(void);
-
-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);
-
-bool compute_audio_buffer_statistics(audio_statistics_t *stats);
-
-void audio_driver_load_menu_sounds(void);
-
-const char* audio_driver_get_ident(void);
-
-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;
-extern audio_driver_t audio_switch;
-extern audio_driver_t audio_switch_thread;
-extern audio_driver_t audio_rwebaudio;
-extern audio_driver_t audio_null;
-
-RETRO_END_DECLS
-
-#endif
diff --git a/audio/audio_thread_wrapper.h b/audio/audio_thread_wrapper.h
index 11fee2d566..8ee8be2be0 100644
--- a/audio/audio_thread_wrapper.h
+++ b/audio/audio_thread_wrapper.h
@@ -19,7 +19,7 @@
#include
-#include "audio_driver.h"
+#include "../retroarch.h"
/**
* audio_init_thread:
diff --git a/audio/drivers/alsa.c b/audio/drivers/alsa.c
index 755e672bd0..f0d7b139a6 100644
--- a/audio/drivers/alsa.c
+++ b/audio/drivers/alsa.c
@@ -21,7 +21,7 @@
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
typedef struct alsa
diff --git a/audio/drivers/alsa_qsa.c b/audio/drivers/alsa_qsa.c
index 3114ffcdd2..d192370bb7 100644
--- a/audio/drivers/alsa_qsa.c
+++ b/audio/drivers/alsa_qsa.c
@@ -19,7 +19,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#define MAX_FRAG_SIZE 3072
#define DEFAULT_RATE 48000
diff --git a/audio/drivers/alsathread.c b/audio/drivers/alsathread.c
index d7e45072bf..33cfe02af4 100644
--- a/audio/drivers/alsathread.c
+++ b/audio/drivers/alsathread.c
@@ -24,7 +24,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#define TRY_ALSA(x) if (x < 0) \
diff --git a/audio/drivers/audioio.c b/audio/drivers/audioio.c
index b51a7fffc0..66a219ec3c 100644
--- a/audio/drivers/audioio.c
+++ b/audio/drivers/audioio.c
@@ -27,7 +27,7 @@
#include "config.h"
#endif
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#define DEFAULT_DEV "/dev/audio"
diff --git a/audio/drivers/coreaudio.c b/audio/drivers/coreaudio.c
index f35fa96e77..0a8ca82971 100644
--- a/audio/drivers/coreaudio.c
+++ b/audio/drivers/coreaudio.c
@@ -31,7 +31,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
typedef struct coreaudio
diff --git a/audio/drivers/coreaudio3.m b/audio/drivers/coreaudio3.m
index 176024411b..0849233353 100644
--- a/audio/drivers/coreaudio3.m
+++ b/audio/drivers/coreaudio3.m
@@ -22,7 +22,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#pragma mark - ringbuffer
diff --git a/audio/drivers/ctr_csnd_audio.c b/audio/drivers/ctr_csnd_audio.c
index 019dd8a040..e1783ebb2c 100644
--- a/audio/drivers/ctr_csnd_audio.c
+++ b/audio/drivers/ctr_csnd_audio.c
@@ -19,7 +19,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
typedef struct
{
diff --git a/audio/drivers/ctr_dsp_audio.c b/audio/drivers/ctr_dsp_audio.c
index afed352ab4..46de845f8d 100644
--- a/audio/drivers/ctr_dsp_audio.c
+++ b/audio/drivers/ctr_dsp_audio.c
@@ -17,7 +17,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../ctr/ctr_debug.h"
typedef struct
diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c
index d74c0a2c0d..1f36b6f311 100644
--- a/audio/drivers/dsound.c
+++ b/audio/drivers/dsound.c
@@ -37,7 +37,7 @@
#endif
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#ifdef _XBOX
diff --git a/audio/drivers/gx_audio.c b/audio/drivers/gx_audio.c
index e41f15f916..f4f2be0ca8 100644
--- a/audio/drivers/gx_audio.c
+++ b/audio/drivers/gx_audio.c
@@ -27,7 +27,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../defines/gx_defines.h"
typedef struct
diff --git a/audio/drivers/jack.c b/audio/drivers/jack.c
index 40a116f292..ede8c1a370 100644
--- a/audio/drivers/jack.c
+++ b/audio/drivers/jack.c
@@ -25,7 +25,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../configuration.h"
#include "../../verbosity.h"
diff --git a/audio/drivers/nullaudio.c b/audio/drivers/nullaudio.c
index c7dffc6f7e..4d92ecdb97 100644
--- a/audio/drivers/nullaudio.c
+++ b/audio/drivers/nullaudio.c
@@ -14,7 +14,7 @@
* If not, see .
*/
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
static void *null_audio_init(const char *device, unsigned rate, unsigned latency,
diff --git a/audio/drivers/openal.c b/audio/drivers/openal.c
index 6127ca9b4d..1c9cfc6575 100644
--- a/audio/drivers/openal.c
+++ b/audio/drivers/openal.c
@@ -33,7 +33,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#define BUFSIZE 1024
diff --git a/audio/drivers/opensl.c b/audio/drivers/opensl.c
index c683fecd5c..26ec306f67 100644
--- a/audio/drivers/opensl.c
+++ b/audio/drivers/opensl.c
@@ -21,7 +21,7 @@
#include
-#include "../audio_driver.h"
+#include "../../retroarch.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 1c6691187e..73b4a61eeb 100644
--- a/audio/drivers/oss.c
+++ b/audio/drivers/oss.c
@@ -33,7 +33,7 @@
#include "config.h"
#endif
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#ifdef HAVE_OSS_BSD
diff --git a/audio/drivers/ps2_audio.c b/audio/drivers/ps2_audio.c
index 9720eb4643..3a50a61c4a 100644
--- a/audio/drivers/ps2_audio.c
+++ b/audio/drivers/ps2_audio.c
@@ -21,7 +21,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.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 1f5eba29b6..c6edf9ecda 100644
--- a/audio/drivers/ps3_audio.c
+++ b/audio/drivers/ps3_audio.c
@@ -19,7 +19,7 @@
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../defines/ps3_defines.h"
diff --git a/audio/drivers/psp_audio.c b/audio/drivers/psp_audio.c
index 5c979033bc..3bfe115fde 100644
--- a/audio/drivers/psp_audio.c
+++ b/audio/drivers/psp_audio.c
@@ -40,7 +40,7 @@
#define SceUID uint32_t
#endif
-#include "../audio_driver.h"
+#include "../../retroarch.h"
typedef struct psp_audio
{
diff --git a/audio/drivers/pulse.c b/audio/drivers/pulse.c
index fd27ca7b8f..a319e10ebf 100644
--- a/audio/drivers/pulse.c
+++ b/audio/drivers/pulse.c
@@ -23,7 +23,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
typedef struct
diff --git a/audio/drivers/roar.c b/audio/drivers/roar.c
index 815e5ade96..26b72fb993 100644
--- a/audio/drivers/roar.c
+++ b/audio/drivers/roar.c
@@ -23,7 +23,7 @@
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
typedef struct
diff --git a/audio/drivers/rsound.c b/audio/drivers/rsound.c
index c6241c51d5..8f5ea9ff10 100644
--- a/audio/drivers/rsound.c
+++ b/audio/drivers/rsound.c
@@ -21,7 +21,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "rsound.h"
typedef struct rsd
diff --git a/audio/drivers/rwebaudio.c b/audio/drivers/rwebaudio.c
index 3e819b2049..8723e29a55 100644
--- a/audio/drivers/rwebaudio.c
+++ b/audio/drivers/rwebaudio.c
@@ -18,7 +18,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
/* forward declarations */
unsigned RWebAudioSampleRate(void);
diff --git a/audio/drivers/sdl_audio.c b/audio/drivers/sdl_audio.c
index b6aebceb8b..5726bd7371 100644
--- a/audio/drivers/sdl_audio.c
+++ b/audio/drivers/sdl_audio.c
@@ -14,20 +14,20 @@
* If not, see .
*/
+#include
+#include
+#include
+#include
+
#include
#include
#include
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
-#include
-#include
-#include
-#include
-
#include "SDL.h"
#include "SDL_audio.h"
diff --git a/audio/drivers/switch_audio.c b/audio/drivers/switch_audio.c
index a43d97c78b..26b8b42a95 100644
--- a/audio/drivers/switch_audio.c
+++ b/audio/drivers/switch_audio.c
@@ -20,7 +20,7 @@
#include
#include "switch_audio_compat.h"
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#ifdef HAVE_LIBNX
diff --git a/audio/drivers/switch_thread_audio.c b/audio/drivers/switch_thread_audio.c
index 3bb8ba38fe..8fb07019d8 100644
--- a/audio/drivers/switch_thread_audio.c
+++ b/audio/drivers/switch_thread_audio.c
@@ -28,7 +28,7 @@
#endif
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#include "../../tasks/tasks_internal.h"
diff --git a/audio/drivers/tinyalsa.c b/audio/drivers/tinyalsa.c
index eb34f5784a..8625bbd58b 100644
--- a/audio/drivers/tinyalsa.c
+++ b/audio/drivers/tinyalsa.c
@@ -64,7 +64,7 @@
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
/* Implementation tinyalsa pcm */
diff --git a/audio/drivers/wasapi.c b/audio/drivers/wasapi.c
index 8348256af8..7d66371e9c 100644
--- a/audio/drivers/wasapi.c
+++ b/audio/drivers/wasapi.c
@@ -41,7 +41,7 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0
#include
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
#include "../../configuration.h"
diff --git a/audio/drivers/wiiu_audio.c b/audio/drivers/wiiu_audio.c
index c13d7cf9bb..7dea64c3e5 100644
--- a/audio/drivers/wiiu_audio.c
+++ b/audio/drivers/wiiu_audio.c
@@ -21,10 +21,10 @@
#include
#include
-#include "wiiu/wiiu_dbg.h"
-#include "wiiu/system/memory.h"
+#include "../../wiiu/wiiu_dbg.h"
+#include "../../wiiu/system/memory.h"
-#include "audio/audio_driver.h"
+#include "../../retroarch.h"
typedef struct
{
diff --git a/audio/drivers/xaudio.c b/audio/drivers/xaudio.c
index 83df3c9972..5ee0fb6a7a 100644
--- a/audio/drivers/xaudio.c
+++ b/audio/drivers/xaudio.c
@@ -36,7 +36,7 @@
#include "xaudio.h"
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#include "../../verbosity.h"
typedef struct xaudio2 xaudio2_t;
diff --git a/audio/drivers/xenon360_audio.c b/audio/drivers/xenon360_audio.c
index fdcd585572..bf0ad4267e 100644
--- a/audio/drivers/xenon360_audio.c
+++ b/audio/drivers/xenon360_audio.c
@@ -21,7 +21,7 @@
#include
-#include "../audio_driver.h"
+#include "../../retroarch.h"
#define SOUND_FREQUENCY 48000
#define MAX_BUFFER 2048
diff --git a/command.c b/command.c
index 16c755c937..acebb1ce92 100755
--- a/command.c
+++ b/command.c
@@ -74,7 +74,6 @@
#include "driver.h"
#include "input/input_driver.h"
#include "frontend/frontend_driver.h"
-#include "audio/audio_driver.h"
#include "record/record_driver.h"
#include "file_path_special.h"
#include "autosave.h"
diff --git a/configuration.c b/configuration.c
index 17f44acb2f..e94edd2c59 100644
--- a/configuration.c
+++ b/configuration.c
@@ -33,7 +33,6 @@
#endif
#include "file_path_special.h"
-#include "audio/audio_driver.h"
#include "gfx/video_driver.h"
#include "input/input_driver.h"
#include "configuration.h"
diff --git a/core_impl.c b/core_impl.c
index c43d4202eb..21e554fede 100644
--- a/core_impl.c
+++ b/core_impl.c
@@ -42,7 +42,7 @@
#include "managers/state_manager.h"
#include "verbosity.h"
#include "gfx/video_driver.h"
-#include "audio/audio_driver.h"
+#include "retroarch.h"
#include "tasks/tasks_internal.h"
#ifdef HAVE_RUNAHEAD
diff --git a/dynamic.c b/dynamic.c
index 7b0990410c..583a12eab3 100644
--- a/dynamic.c
+++ b/dynamic.c
@@ -52,7 +52,6 @@
#include "dynamic.h"
#include "command.h"
-#include "audio/audio_driver.h"
#include "record/record_driver.h"
#include "driver.h"
#include "performance_counters.h"
diff --git a/frontend/drivers/platform_ctr.c b/frontend/drivers/platform_ctr.c
index 71c827c446..c6871af90a 100644
--- a/frontend/drivers/platform_ctr.c
+++ b/frontend/drivers/platform_ctr.c
@@ -46,7 +46,6 @@
#include "../../paths.h"
#include "retroarch.h"
#include "file_path_special.h"
-#include "audio/audio_driver.h"
#include "ctr/ctr_debug.h"
#include "ctr/exec-3dsx/exec_3dsx.h"
diff --git a/frontend/drivers/platform_switch.c b/frontend/drivers/platform_switch.c
index 2774b8f9b7..fdc5f56926 100644
--- a/frontend/drivers/platform_switch.c
+++ b/frontend/drivers/platform_switch.c
@@ -30,14 +30,14 @@
#include
#endif
+#include
+
#include "../frontend_driver.h"
#include "../../verbosity.h"
#include "../../defaults.h"
#include "../../paths.h"
#include "../../retroarch.h"
#include "../../file_path_special.h"
-#include "../../audio/audio_driver.h"
-#include
#ifndef IS_SALAMANDER
#ifdef HAVE_MENU
diff --git a/gfx/video_driver.c b/gfx/video_driver.c
index 2bebde5025..03fa524212 100644
--- a/gfx/video_driver.c
+++ b/gfx/video_driver.c
@@ -32,7 +32,6 @@
#include
#include
-#include "../audio/audio_driver.h"
#include "../menu/menu_shader.h"
#ifdef HAVE_CONFIG_H
diff --git a/griffin/griffin.c b/griffin/griffin.c
index e93ad86c44..32b46a330c 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -890,7 +890,6 @@ DRIVERS
#include "../gfx/video_display_server.c"
#include "../gfx/video_coord_array.c"
#include "../input/input_driver.c"
-#include "../audio/audio_driver.c"
#include "../libretro-common/audio/audio_mixer.c"
/*============================================================
diff --git a/list_special.c b/list_special.c
index fe4815404b..345aeb6b3e 100644
--- a/list_special.c
+++ b/list_special.c
@@ -40,7 +40,6 @@
#include "core_info.h"
#include "gfx/video_driver.h"
#include "input/input_driver.h"
-#include "audio/audio_driver.h"
#include "record/record_driver.h"
#include "midi/midi_driver.h"
#include "configuration.h"
diff --git a/managers/state_manager.c b/managers/state_manager.c
index 66ae8c1513..0b35a276c6 100644
--- a/managers/state_manager.c
+++ b/managers/state_manager.c
@@ -32,7 +32,6 @@
#include "../core.h"
#include "../retroarch.h"
#include "../verbosity.h"
-#include "../audio/audio_driver.h"
#ifdef HAVE_NETWORKING
#include "../network/netplay/netplay.h"
diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c
index 831050c47c..1f6e385744 100644
--- a/menu/cbs/menu_cbs_get_value.c
+++ b/menu/cbs/menu_cbs_get_value.c
@@ -30,7 +30,6 @@
#include "../../tasks/tasks_internal.h"
#include "../../input/input_driver.h"
-#include "../../audio/audio_driver.h"
#include "../../core.h"
#include "../../core_info.h"
#include "../../configuration.h"
diff --git a/menu/cbs/menu_cbs_left.c b/menu/cbs/menu_cbs_left.c
index e8373889e0..04abaac5d3 100644
--- a/menu/cbs/menu_cbs_left.c
+++ b/menu/cbs/menu_cbs_left.c
@@ -36,7 +36,6 @@
#include "../../managers/cheat_manager.h"
#include "../../file_path_special.h"
#include "../../driver.h"
-#include "../../audio/audio_driver.h"
#include "../../gfx/video_driver.h"
#include "../../retroarch.h"
#include "../../network/netplay/netplay.h"
diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c
index 6cd4e6e19c..e3128cfe91 100644
--- a/menu/cbs/menu_cbs_ok.c
+++ b/menu/cbs/menu_cbs_ok.c
@@ -49,7 +49,6 @@
#include "../menu_content.h"
#include "../menu_shader.h"
-#include "../../audio/audio_driver.h"
#include "../../core.h"
#include "../../configuration.h"
#include "../../core_info.h"
diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c
index 1d16f9043c..709ca06c65 100644
--- a/menu/cbs/menu_cbs_right.c
+++ b/menu/cbs/menu_cbs_right.c
@@ -30,7 +30,6 @@
#include "../menu_setting.h"
#include "../menu_shader.h"
-#include "../../audio/audio_driver.h"
#include "../../configuration.h"
#include "../../core.h"
#include "../../core_info.h"
diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c
index 0c1f5f2079..d9f8e49689 100644
--- a/menu/cbs/menu_cbs_start.c
+++ b/menu/cbs/menu_cbs_start.c
@@ -28,7 +28,6 @@
#include "../menu_setting.h"
#include "../menu_shader.h"
-#include "../../audio/audio_driver.h"
#include "../../configuration.h"
#include "../../core.h"
#include "../../core_info.h"
diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c
index ce4a3a8825..9cac95fe16 100644
--- a/menu/cbs/menu_cbs_sublabel.c
+++ b/menu/cbs/menu_cbs_sublabel.c
@@ -15,20 +15,21 @@
#include
-#include "../../audio/audio_driver.h"
+#include
+#include
+#include
+
#include "../menu_driver.h"
#include "../menu_cbs.h"
+#include "../../retroarch.h"
+
#ifdef HAVE_CHEEVOS
#include "../../cheevos-new/cheevos.h"
#endif
#include "../../core_info.h"
#include "../../verbosity.h"
-#include
-#include
-#include
-
#ifndef BIND_ACTION_SUBLABEL
#define BIND_ACTION_SUBLABEL(cbs, name) \
cbs->action_sublabel = name; \
diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c
index 1a140e1a64..34deb8ed7f 100644
--- a/menu/cbs/menu_cbs_title.c
+++ b/menu/cbs/menu_cbs_title.c
@@ -19,11 +19,11 @@
#include
-#include "../../audio/audio_driver.h"
-
#include "../menu_driver.h"
#include "../menu_cbs.h"
+#include "../../retroarch.h"
+
#ifndef BIND_ACTION_GET_TITLE
#define BIND_ACTION_GET_TITLE(cbs, name) \
cbs->action_get_title = name; \
diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c
index 7340880aff..c2eb68ef9a 100644
--- a/menu/menu_displaylist.c
+++ b/menu/menu_displaylist.c
@@ -69,7 +69,6 @@
#include "widgets/menu_dialog.h"
#include "widgets/menu_filebrowser.h"
-#include "../audio/audio_driver.h"
#include "../configuration.h"
#include "../file_path_special.h"
#include "../defaults.h"
diff --git a/menu/menu_driver.h b/menu/menu_driver.h
index dcdfa94c78..16f44cf80c 100644
--- a/menu/menu_driver.h
+++ b/menu/menu_driver.h
@@ -33,7 +33,7 @@
#include "menu_input.h"
#include "menu_entries.h"
-#include "../audio/audio_driver.h"
+#include "../retroarch.h"
#include "../file_path_special.h"
#include "../gfx/font_driver.h"
#include "../gfx/video_coord_array.h"
diff --git a/menu/menu_setting.c b/menu/menu_setting.c
index e58a450ec8..339184936a 100644
--- a/menu/menu_setting.c
+++ b/menu/menu_setting.c
@@ -76,7 +76,6 @@
#include "../list_special.h"
#include "../wifi/wifi_driver.h"
#include "../record/record_driver.h"
-#include "../audio/audio_driver.h"
#include "../input/input_driver.h"
#include "../midi/midi_driver.h"
#include "../tasks/tasks_internal.h"
diff --git a/retroarch.c b/retroarch.c
index e922cc70df..c9476e9b2a 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -46,7 +46,10 @@
#include
#include
#include
+#include
+#include
#include
+#include
#include
#include
#include
@@ -115,7 +118,6 @@
#include "verbosity.h"
#include "frontend/frontend_driver.h"
-#include "audio/audio_driver.h"
#ifdef HAVE_THREADS
#include "../gfx/video_thread_wrapper.h"
#endif
@@ -130,6 +132,7 @@
#include "managers/core_option_manager.h"
#include "managers/cheat_manager.h"
#include "managers/state_manager.h"
+#include "tasks/task_audio_mixer.h"
#include "tasks/task_content.h"
#include "tasks/tasks_internal.h"
#include "performance_counters.h"
@@ -143,6 +146,8 @@
#include "runahead/run_ahead.h"
#endif
+#include "audio/audio_thread_wrapper.h"
+
#define _PSUPP(var, name, desc) printf(" %s:\n\t\t%s: %s\n", name, desc, var ? "yes" : "no")
#define FAIL_CPU(simd_type) do { \
@@ -301,6 +306,1777 @@ extern bool input_driver_flushing_input;
static char launch_arguments[4096];
+/* Audio */
+
+#define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024)
+
+#define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac"
+
+/**
+ * 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))
+
+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
+#ifdef __CELLOS_LV2__
+ &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,
+#endif
+#ifdef SWITCH
+ &audio_switch_thread,
+ &audio_switch,
+#endif
+ &audio_null,
+ NULL,
+};
+
+static struct audio_mixer_stream audio_mixer_streams[AUDIO_MIXER_MAX_SYSTEM_STREAMS] = {{0}};
+
+static size_t audio_driver_chunk_size = 0;
+static size_t audio_driver_chunk_nonblock_size = 0;
+static size_t audio_driver_chunk_block_size = 0;
+
+static size_t audio_driver_rewind_ptr = 0;
+static size_t audio_driver_rewind_size = 0;
+
+static int16_t *audio_driver_rewind_buf = NULL;
+static int16_t *audio_driver_output_samples_conv_buf = NULL;
+
+static unsigned audio_driver_free_samples_buf[AUDIO_BUFFER_FREE_SAMPLES_COUNT];
+static uint64_t audio_driver_free_samples_count = 0;
+
+static size_t audio_driver_buffer_size = 0;
+static size_t audio_driver_data_ptr = 0;
+
+static bool audio_driver_control = false;
+static bool audio_driver_mixer_mute_enable = false;
+static bool audio_driver_mute_enable = false;
+static bool audio_driver_use_float = false;
+static bool audio_driver_active = false;
+static bool audio_mixer_active = false;
+
+static float audio_driver_rate_control_delta = 0.0f;
+static float audio_driver_input = 0.0f;
+static float audio_driver_volume_gain = 0.0f;
+static float audio_driver_mixer_volume_gain = 0.0f;
+
+static float *audio_driver_input_data = NULL;
+static float *audio_driver_output_samples_buf = NULL;
+
+static double audio_source_ratio_original = 0.0f;
+static double audio_source_ratio_current = 0.0f;
+
+static struct retro_audio_callback audio_callback = {0};
+
+static retro_dsp_filter_t *audio_driver_dsp = NULL;
+static struct string_list *audio_driver_devices_list = NULL;
+static const retro_resampler_t *audio_driver_resampler = NULL;
+
+static void *audio_driver_resampler_data = NULL;
+static const audio_driver_t *current_audio = NULL;
+static void *audio_driver_context_audio_data = NULL;
+
+static bool audio_suspended = false;
+static bool audio_is_threaded = false;
+
+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);
+
+static enum resampler_quality audio_driver_get_resampler_quality(void)
+{
+ settings_t *settings = config_get_ptr();
+
+ if (!settings)
+ return RESAMPLER_QUALITY_DONTCARE;
+
+ return (enum resampler_quality)settings->uints.audio_resampler_quality;
+}
+
+audio_mixer_stream_t *audio_driver_mixer_get_stream(unsigned i)
+{
+ if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
+ return NULL;
+ return &audio_mixer_streams[i];
+}
+
+const char *audio_driver_mixer_get_stream_name(unsigned i)
+{
+ if (i > (AUDIO_MIXER_MAX_SYSTEM_STREAMS-1))
+ return "N/A";
+ if (!string_is_empty(audio_mixer_streams[i].name))
+ return audio_mixer_streams[i].name;
+ return "N/A";
+}
+
+/**
+ * compute_audio_buffer_statistics:
+ *
+ * Computes audio buffer statistics.
+ *
+ **/
+bool compute_audio_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;
+ unsigned samples = MIN(
+ (unsigned)audio_driver_free_samples_count,
+ AUDIO_BUFFER_FREE_SAMPLES_COUNT);
+
+ if (!stats || samples < 3)
+ return false;
+
+ stats->samples = (unsigned)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 += audio_driver_free_samples_buf[i];
+
+ avg = (unsigned)accum / (samples - 1);
+
+ for (i = 1; i < samples; i++)
+ {
+ int diff = avg - 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
+ / audio_driver_buffer_size) * 100.0;
+ stats->std_deviation_percentage = ((float)stddev
+ / audio_driver_buffer_size) * 100.0;
+#endif
+
+ low_water_size = (unsigned)(audio_driver_buffer_size * 3 / 4);
+ high_water_size = (unsigned)(audio_driver_buffer_size / 4);
+
+ for (i = 1; i < samples; i++)
+ {
+ if (audio_driver_free_samples_buf[i] >= low_water_size)
+ low_water_count++;
+ else if (audio_driver_free_samples_buf[i] <= high_water_size)
+ high_water_count++;
+ }
+
+ stats->close_to_underrun = (100.0 * low_water_count) / (samples - 1);
+ stats->close_to_blocking = (100.0 * high_water_count) / (samples - 1);
+
+ return true;
+}
+
+static void report_audio_buffer_statistics(void)
+{
+ audio_statistics_t audio_stats = {0.0f};
+ if (!compute_audio_buffer_statistics(&audio_stats))
+ return;
+
+#ifdef DEBUG
+ 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
+}
+
+/**
+ * audio_driver_find_handle:
+ * @idx : index of driver to get handle to.
+ *
+ * Returns: handle to audio driver at index. Can be NULL
+ * if nothing found.
+ **/
+const void *audio_driver_find_handle(int idx)
+{
+ const void *drv = audio_drivers[idx];
+ if (!drv)
+ return NULL;
+ return drv;
+}
+
+/**
+ * audio_driver_find_ident:
+ * @idx : index of driver to get handle to.
+ *
+ * Returns: Human-readable identifier of audio driver at index. Can be NULL
+ * if nothing found.
+ **/
+const char *audio_driver_find_ident(int idx)
+{
+ const audio_driver_t *drv = audio_drivers[idx];
+ if (!drv)
+ return NULL;
+ return drv->ident;
+}
+
+/**
+ * config_get_audio_driver_options:
+ *
+ * Get an enumerated list of all audio driver names, separated by '|'.
+ *
+ * Returns: string listing of all audio driver names, separated by '|'.
+ **/
+const char *config_get_audio_driver_options(void)
+{
+ return char_list_new_special(STRING_LIST_AUDIO_DRIVERS, NULL);
+}
+
+static void audio_driver_deinit_resampler(void)
+{
+ if (audio_driver_resampler && audio_driver_resampler_data)
+ audio_driver_resampler->free(audio_driver_resampler_data);
+ audio_driver_resampler = NULL;
+ audio_driver_resampler_data = NULL;
+}
+
+
+static bool audio_driver_deinit_internal(void)
+{
+ settings_t *settings = config_get_ptr();
+
+ if (current_audio && current_audio->free)
+ {
+ if (audio_driver_context_audio_data)
+ current_audio->free(audio_driver_context_audio_data);
+ audio_driver_context_audio_data = NULL;
+ }
+
+ if (audio_driver_output_samples_conv_buf)
+ free(audio_driver_output_samples_conv_buf);
+ audio_driver_output_samples_conv_buf = NULL;
+
+ audio_driver_data_ptr = 0;
+
+ if (audio_driver_rewind_buf)
+ free(audio_driver_rewind_buf);
+ audio_driver_rewind_buf = NULL;
+
+ audio_driver_rewind_size = 0;
+
+ if (settings && !settings->bools.audio_enable)
+ {
+ audio_driver_active = false;
+ return false;
+ }
+
+ audio_driver_deinit_resampler();
+
+ if (audio_driver_input_data)
+ free(audio_driver_input_data);
+ audio_driver_input_data = NULL;
+
+ if (audio_driver_output_samples_buf)
+ free(audio_driver_output_samples_buf);
+ audio_driver_output_samples_buf = NULL;
+
+ command_event(CMD_EVENT_DSP_FILTER_DEINIT, NULL);
+
+ report_audio_buffer_statistics();
+
+ return true;
+}
+
+static void audio_driver_mixer_deinit(void)
+{
+ unsigned i;
+
+ 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();
+}
+
+static bool audio_driver_free_devices_list(void)
+{
+ if (!current_audio || !current_audio->device_list_free
+ || !audio_driver_context_audio_data)
+ return false;
+ current_audio->device_list_free(audio_driver_context_audio_data,
+ audio_driver_devices_list);
+ audio_driver_devices_list = NULL;
+ return true;
+}
+
+static bool audio_driver_deinit(void)
+{
+ audio_driver_mixer_deinit();
+ audio_driver_free_devices_list();
+
+ if (!audio_driver_deinit_internal())
+ return false;
+ return true;
+}
+
+
+static void audio_driver_mixer_init(unsigned audio_out_rate)
+{
+ audio_mixer_init(audio_out_rate);
+}
+
+static bool audio_driver_find_driver(void)
+{
+ int i;
+ driver_ctx_info_t drv;
+ settings_t *settings = config_get_ptr();
+
+ drv.label = "audio_driver";
+ drv.s = settings->arrays.audio_driver;
+
+ driver_ctl(RARCH_DRIVER_CTL_FIND_INDEX, &drv);
+
+ i = (int)drv.len;
+
+ if (i >= 0)
+ current_audio = (const audio_driver_t*)audio_driver_find_handle(i);
+ else
+ {
+ if (verbosity_is_enabled())
+ {
+ unsigned d;
+ RARCH_ERR("Couldn't find any audio driver named \"%s\"\n",
+ settings->arrays.audio_driver);
+ RARCH_LOG_OUTPUT("Available audio drivers are:\n");
+ for (d = 0; audio_driver_find_handle(d); d++)
+ RARCH_LOG_OUTPUT("\t%s\n", audio_driver_find_ident(d));
+ RARCH_WARN("Going to default to first audio driver...\n");
+ }
+
+ current_audio = (const audio_driver_t*)audio_driver_find_handle(0);
+
+ if (!current_audio)
+ retroarch_fail(1, "audio_driver_find()");
+ }
+
+ return true;
+}
+
+
+static bool audio_driver_init_internal(bool audio_cb_inited)
+{
+ unsigned new_rate = 0;
+ float *aud_inp_data = NULL;
+ float *samples_buf = NULL;
+ int16_t *conv_buf = NULL;
+ int16_t *rewind_buf = NULL;
+ size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2;
+ settings_t *settings = config_get_ptr();
+ /* Accomodate rewind since at some point we might have two full buffers. */
+ size_t outsamples_max = AUDIO_CHUNK_SIZE_NONBLOCKING * 2 * AUDIO_MAX_RATIO *
+ settings->floats.slowmotion_ratio;
+
+ convert_s16_to_float_init_simd();
+ convert_float_to_s16_init_simd();
+
+ conv_buf = (int16_t*)malloc(outsamples_max
+ * sizeof(int16_t));
+ /* Used for recording even if audio isn't enabled. */
+ retro_assert(conv_buf != NULL);
+
+ if (!conv_buf)
+ goto error;
+
+ audio_driver_output_samples_conv_buf = conv_buf;
+ audio_driver_chunk_block_size = AUDIO_CHUNK_SIZE_BLOCKING;
+ audio_driver_chunk_nonblock_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
+ audio_driver_chunk_size = audio_driver_chunk_block_size;
+
+ /* Needs to be able to hold full content of a full max_bufsamples
+ * in addition to its own. */
+ rewind_buf = (int16_t*)malloc(max_bufsamples * sizeof(int16_t));
+ retro_assert(rewind_buf != NULL);
+
+ if (!rewind_buf)
+ goto error;
+
+ audio_driver_rewind_buf = rewind_buf;
+ audio_driver_rewind_size = max_bufsamples;
+
+ if (!settings->bools.audio_enable)
+ {
+ audio_driver_active = false;
+ return false;
+ }
+
+ audio_driver_find_driver();
+#ifdef HAVE_THREADS
+ if (audio_cb_inited)
+ {
+ audio_is_threaded = true;
+ RARCH_LOG("[Audio]: Starting threaded audio driver ...\n");
+ if (!audio_init_thread(
+ ¤t_audio,
+ &audio_driver_context_audio_data,
+ *settings->arrays.audio_device
+ ? settings->arrays.audio_device : NULL,
+ settings->uints.audio_out_rate, &new_rate,
+ settings->uints.audio_latency,
+ settings->uints.audio_block_frames,
+ current_audio))
+ {
+ RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
+ retroarch_fail(1, "audio_driver_init_internal()");
+ }
+ }
+ else
+#endif
+ {
+ audio_is_threaded = false;
+ audio_driver_context_audio_data =
+ current_audio->init(*settings->arrays.audio_device ?
+ settings->arrays.audio_device : NULL,
+ settings->uints.audio_out_rate,
+ settings->uints.audio_latency,
+ settings->uints.audio_block_frames,
+ &new_rate);
+ }
+
+ if (new_rate != 0)
+ {
+ configuration_set_int(settings, settings->uints.audio_out_rate, new_rate);
+ }
+
+ if (!audio_driver_context_audio_data)
+ {
+ RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n");
+ audio_driver_active = false;
+ }
+
+ audio_driver_use_float = false;
+ if ( audio_driver_active
+ && current_audio->use_float(audio_driver_context_audio_data))
+ audio_driver_use_float = true;
+
+ if (!settings->bools.audio_sync && audio_driver_active)
+ {
+ command_event(CMD_EVENT_AUDIO_SET_NONBLOCKING_STATE, NULL);
+ audio_driver_chunk_size = audio_driver_chunk_nonblock_size;
+ }
+
+ if (audio_driver_input <= 0.0f)
+ {
+ /* Should never happen. */
+ RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n",
+ audio_driver_input, settings->uints.audio_out_rate);
+ audio_driver_input = settings->uints.audio_out_rate;
+ }
+
+ audio_source_ratio_original = audio_source_ratio_current =
+ (double)settings->uints.audio_out_rate / audio_driver_input;
+
+ if (!retro_resampler_realloc(
+ &audio_driver_resampler_data,
+ &audio_driver_resampler,
+ settings->arrays.audio_resampler,
+ audio_driver_get_resampler_quality(),
+ audio_source_ratio_original))
+ {
+ RARCH_ERR("Failed to initialize resampler \"%s\".\n",
+ settings->arrays.audio_resampler);
+ audio_driver_active = false;
+ }
+
+ aud_inp_data = (float*)malloc(max_bufsamples * sizeof(float));
+ retro_assert(aud_inp_data != NULL);
+
+ if (!aud_inp_data)
+ goto error;
+
+ audio_driver_input_data = aud_inp_data;
+ audio_driver_data_ptr = 0;
+
+ retro_assert(settings->uints.audio_out_rate <
+ audio_driver_input * AUDIO_MAX_RATIO);
+
+ samples_buf = (float*)malloc(outsamples_max * sizeof(float));
+
+ retro_assert(samples_buf != NULL);
+
+ if (!samples_buf)
+ goto error;
+
+ audio_driver_output_samples_buf = samples_buf;
+ audio_driver_control = false;
+
+ if (
+ !audio_cb_inited
+ && audio_driver_active
+ && settings->bools.audio_rate_control
+ )
+ {
+ /* Audio rate control requires write_avail
+ * and buffer_size to be implemented. */
+ if (current_audio->buffer_size)
+ {
+ audio_driver_buffer_size =
+ current_audio->buffer_size(audio_driver_context_audio_data);
+ 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);
+
+ audio_driver_free_samples_count = 0;
+
+ audio_driver_mixer_init(settings->uints.audio_out_rate);
+
+ /* Threaded driver is initially stopped. */
+ if (
+ audio_driver_active
+ && audio_cb_inited
+ )
+ audio_driver_start(false);
+
+ return true;
+
+error:
+ return audio_driver_deinit();
+}
+
+void audio_driver_set_nonblocking_state(bool enable)
+{
+ settings_t *settings = config_get_ptr();
+ if (
+ audio_driver_active
+ && audio_driver_context_audio_data
+ )
+ current_audio->set_nonblock_state(
+ audio_driver_context_audio_data,
+ settings->bools.audio_sync ? enable : true);
+
+ audio_driver_chunk_size = enable ?
+ audio_driver_chunk_nonblock_size :
+ audio_driver_chunk_block_size;
+}
+
+/**
+ * audio_driver_flush:
+ * @data : pointer to audio buffer.
+ * @right : amount of samples to write.
+ *
+ * Writes audio samples to audio driver. Will first
+ * perform DSP processing (if enabled) and resampling.
+ **/
+static void audio_driver_flush(const int16_t *data, size_t samples,
+ bool is_slowmotion)
+{
+ struct resampler_data src_data;
+ float audio_volume_gain = !audio_driver_mute_enable ?
+ audio_driver_volume_gain : 0.0f;
+
+ src_data.data_out = NULL;
+ src_data.output_frames = 0;
+
+ convert_s16_to_float(audio_driver_input_data, data, samples,
+ audio_volume_gain);
+
+ src_data.data_in = audio_driver_input_data;
+ src_data.input_frames = samples >> 1;
+
+ if (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 = audio_driver_input_data;
+ dsp_data.input_frames = (unsigned)(samples >> 1);
+
+ retro_dsp_filter_process(audio_driver_dsp, &dsp_data);
+
+ if (dsp_data.output)
+ {
+ src_data.data_in = dsp_data.output;
+ src_data.input_frames = dsp_data.output_frames;
+ }
+ }
+
+ src_data.data_out = audio_driver_output_samples_buf;
+
+ if (audio_driver_control)
+ {
+ /* Readjust the audio input rate. */
+ int half_size = (int)(audio_driver_buffer_size / 2);
+ int avail =
+ (int)current_audio->write_avail(audio_driver_context_audio_data);
+ int delta_mid = avail - half_size;
+ double direction = (double)delta_mid / half_size;
+ double adjust = 1.0 + audio_driver_rate_control_delta * direction;
+ unsigned write_idx = audio_driver_free_samples_count++ &
+ (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
+
+ audio_driver_free_samples_buf
+ [write_idx] = avail;
+ audio_source_ratio_current =
+ 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) / audio_driver_buffer_size));
+ RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
+ audio_source_ratio_current,
+ audio_source_ratio_original);
+ }
+#endif
+ }
+
+ src_data.ratio = audio_source_ratio_current;
+
+ if (is_slowmotion)
+ {
+ settings_t *settings = config_get_ptr();
+ src_data.ratio *= settings->floats.slowmotion_ratio;
+ }
+
+ audio_driver_resampler->process(audio_driver_resampler_data, &src_data);
+
+ if (audio_mixer_active)
+ {
+ bool override = audio_driver_mixer_mute_enable ? true :
+ (audio_driver_mixer_volume_gain != 1.0f) ? true : false;
+ float mixer_gain = !audio_driver_mixer_mute_enable ?
+ audio_driver_mixer_volume_gain : 0.0f;
+ audio_mixer_mix(audio_driver_output_samples_buf,
+ src_data.output_frames, mixer_gain, override);
+ }
+
+ {
+ const void *output_data = audio_driver_output_samples_buf;
+ unsigned output_frames = (unsigned)src_data.output_frames;
+
+ if (audio_driver_use_float)
+ output_frames *= sizeof(float);
+ else
+ {
+ convert_float_to_s16(audio_driver_output_samples_conv_buf,
+ (const float*)output_data, output_frames * 2);
+
+ output_data = audio_driver_output_samples_conv_buf;
+ output_frames *= sizeof(int16_t);
+ }
+
+ if (current_audio->write(audio_driver_context_audio_data,
+ output_data, output_frames * 2) < 0)
+ audio_driver_active = false;
+ }
+}
+
+/**
+ * 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)
+{
+ if (audio_suspended)
+ return;
+
+ audio_driver_output_samples_conv_buf[audio_driver_data_ptr++] = left;
+ audio_driver_output_samples_conv_buf[audio_driver_data_ptr++] = right;
+
+ if (audio_driver_data_ptr < audio_driver_chunk_size)
+ return;
+
+ if (recording_data)
+ recording_push_audio(audio_driver_output_samples_conv_buf,
+ audio_driver_data_ptr);
+
+ if (!(runloop_paused ||
+ !audio_driver_active ||
+ !audio_driver_input_data ||
+ !audio_driver_output_samples_buf))
+ audio_driver_flush(audio_driver_output_samples_conv_buf,
+ audio_driver_data_ptr, runloop_slowmotion);
+
+ audio_driver_data_ptr = 0;
+}
+
+static void audio_driver_menu_sample(void)
+{
+ static int16_t samples_buf[1024] = {0};
+ struct retro_system_av_info *av_info = video_viewport_get_system_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;
+ bool check_flush = !(
+ runloop_paused ||
+ !audio_driver_active ||
+ !audio_driver_input_data ||
+ !audio_driver_output_samples_buf);
+
+ while (sample_count > 1024)
+ {
+ if (recording_data)
+ recording_push_audio(samples_buf, 1024);
+ if (check_flush)
+ audio_driver_flush(samples_buf, 1024, runloop_slowmotion);
+ sample_count -= 1024;
+ }
+ if (recording_data)
+ recording_push_audio(samples_buf, sample_count);
+ if (check_flush)
+ audio_driver_flush(samples_buf, sample_count, runloop_slowmotion);
+}
+
+/**
+ * audio_driver_sample_batch:
+ * @data : pointer to audio buffer.
+ * @frames : amount of audio frames to push.
+ *
+ * Batched audio sample render callback function.
+ *
+ * Returns: amount of frames sampled. Will be equal to @frames
+ * unless @frames exceeds (AUDIO_CHUNK_SIZE_NONBLOCKING / 2).
+ **/
+size_t audio_driver_sample_batch(const int16_t *data, size_t frames)
+{
+ if (frames > (AUDIO_CHUNK_SIZE_NONBLOCKING >> 1))
+ frames = AUDIO_CHUNK_SIZE_NONBLOCKING >> 1;
+
+ if (audio_suspended)
+ return frames;
+
+ if (recording_data)
+ recording_push_audio(data, frames << 1);
+
+ if (!(
+ runloop_paused ||
+ !audio_driver_active ||
+ !audio_driver_input_data ||
+ !audio_driver_output_samples_buf))
+ audio_driver_flush(data, frames << 1, runloop_slowmotion);
+
+ return frames;
+}
+
+/**
+ * audio_driver_sample_rewind:
+ * @left : value of the left audio channel.
+ * @right : value of the right audio channel.
+ *
+ * Audio sample render callback function (rewind version).
+ * This callback function will be used instead of
+ * audio_driver_sample when rewinding is activated.
+ **/
+void audio_driver_sample_rewind(int16_t left, int16_t right)
+{
+ if (audio_driver_rewind_ptr == 0)
+ return;
+
+ audio_driver_rewind_buf[--audio_driver_rewind_ptr] = right;
+ audio_driver_rewind_buf[--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).
+ **/
+size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames)
+{
+ size_t i;
+ size_t samples = frames << 1;
+
+ for (i = 0; i < samples; i++)
+ {
+ if (audio_driver_rewind_ptr > 0)
+ audio_driver_rewind_buf[--audio_driver_rewind_ptr] = data[i];
+ }
+
+ return frames;
+}
+
+void audio_driver_dsp_filter_free(void)
+{
+ if (audio_driver_dsp)
+ retro_dsp_filter_free(audio_driver_dsp);
+ audio_driver_dsp = NULL;
+}
+
+void audio_driver_dsp_filter_init(const char *device)
+{
+ struct string_list *plugs = NULL;
+#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
+ char *basedir = (char*)calloc(PATH_MAX_LENGTH, sizeof(*basedir));
+ char *ext_name = (char*)calloc(PATH_MAX_LENGTH, sizeof(*ext_name));
+ size_t str_size = PATH_MAX_LENGTH * sizeof(char);
+ fill_pathname_basedir(basedir, device, str_size);
+
+ if (!frontend_driver_get_core_extension(ext_name, str_size))
+ goto error;
+
+ plugs = dir_list_new(basedir, ext_name, false, true, false, false);
+ if (!plugs)
+ goto error;
+#endif
+ audio_driver_dsp = retro_dsp_filter_new(
+ device, plugs, audio_driver_input);
+ if (!audio_driver_dsp)
+ goto error;
+
+#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
+ free(basedir);
+ free(ext_name);
+#endif
+
+ return;
+
+error:
+#if defined(HAVE_DYLIB) && !defined(HAVE_FILTERS_BUILTIN)
+ free(basedir);
+ free(ext_name);
+#endif
+ if (!audio_driver_dsp)
+ RARCH_ERR("[DSP]: Failed to initialize DSP filter \"%s\".\n", device);
+}
+
+void audio_driver_set_buffer_size(size_t bufsize)
+{
+ audio_driver_buffer_size = bufsize;
+}
+
+static void audio_driver_monitor_adjust_system_rates(void)
+{
+ float timing_skew;
+ settings_t *settings = config_get_ptr();
+ float video_refresh_rate = settings->floats.video_refresh_rate;
+ float max_timing_skew = settings->floats.audio_max_timing_skew;
+ struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
+ const struct retro_system_timing *info =
+ (const struct retro_system_timing*)&av_info->timing;
+
+ if (info->sample_rate <= 0.0)
+ return;
+
+ timing_skew = fabs(1.0f - info->fps / video_refresh_rate);
+ audio_driver_input = info->sample_rate;
+
+ if (timing_skew <= max_timing_skew && !settings->bools.vrr_runloop_enable)
+ audio_driver_input *= (video_refresh_rate / info->fps);
+
+ RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n",
+ audio_driver_input);
+}
+
+void audio_driver_setup_rewind(void)
+{
+ unsigned i;
+
+ /* Push audio ready to be played. */
+ audio_driver_rewind_ptr = audio_driver_rewind_size;
+
+ for (i = 0; i < audio_driver_data_ptr; i += 2)
+ {
+ if (audio_driver_rewind_ptr > 0)
+ audio_driver_rewind_buf[--audio_driver_rewind_ptr] =
+ audio_driver_output_samples_conv_buf[i + 1];
+
+ if (audio_driver_rewind_ptr > 0)
+ audio_driver_rewind_buf[--audio_driver_rewind_ptr] =
+ audio_driver_output_samples_conv_buf[i + 0];
+ }
+
+ audio_driver_data_ptr = 0;
+}
+
+
+bool audio_driver_get_devices_list(void **data)
+{
+ struct string_list**ptr = (struct string_list**)data;
+ if (!ptr)
+ return false;
+ *ptr = audio_driver_devices_list;
+ return true;
+}
+
+bool audio_driver_mixer_extension_supported(const char *ext)
+{
+ union string_list_elem_attr attr;
+ unsigned i;
+ bool ret = false;
+ struct string_list *str_list = string_list_new();
+
+ attr.i = 0;
+
+#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_free(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_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_mixer_streams[i].name))
+ free(audio_mixer_streams[i].name);
+
+ audio_mixer_streams[i].name = NULL;
+ audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
+ audio_mixer_streams[i].volume = 0.0f;
+ audio_mixer_streams[i].buf = NULL;
+ audio_mixer_streams[i].stop_cb = NULL;
+ audio_mixer_streams[i].handle = NULL;
+ 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)
+{
+ int idx = audio_mixer_find_index(sound);
+
+ switch (reason)
+ {
+ case AUDIO_MIXER_SOUND_FINISHED:
+ if (idx >= 0)
+ {
+ unsigned i = (unsigned)idx;
+ audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
+ 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)
+{
+ 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_mixer_streams[i].name))
+ free(audio_mixer_streams[i].name);
+
+ if (i < AUDIO_MIXER_MAX_STREAMS)
+ audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER;
+ else
+ audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_SYSTEM;
+
+ audio_mixer_streams[i].name = NULL;
+ audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
+ audio_mixer_streams[i].volume = 0.0f;
+ audio_mixer_streams[i].buf = NULL;
+ audio_mixer_streams[i].stop_cb = NULL;
+ audio_mixer_streams[i].handle = NULL;
+ audio_mixer_streams[i].voice = NULL;
+
+ i++;
+
+ for (; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
+ {
+ if (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 = (type == AUDIO_STREAM_TYPE_USER) ? 0 : AUDIO_MIXER_MAX_STREAMS;
+ unsigned count = (type == AUDIO_STREAM_TYPE_USER) ? AUDIO_MIXER_MAX_STREAMS : AUDIO_MIXER_MAX_SYSTEM_STREAMS;
+ for (; i < count; i++)
+ {
+ if (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)
+{
+ 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;
+ 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);
+ 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, stop_cb);
+ break;
+ case AUDIO_STREAM_STATE_PLAYING:
+ voice = audio_mixer_play(handle, looped, params->volume, 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, stop_cb);
+ break;
+ default:
+ break;
+ }
+
+ audio_mixer_active = true;
+
+ audio_mixer_streams[free_slot].name = !string_is_empty(params->basename) ? strdup(params->basename) : NULL;
+ audio_mixer_streams[free_slot].buf = buf;
+ audio_mixer_streams[free_slot].handle = handle;
+ audio_mixer_streams[free_slot].voice = voice;
+ audio_mixer_streams[free_slot].stream_type = params->stream_type;
+ audio_mixer_streams[free_slot].type = params->type;
+ audio_mixer_streams[free_slot].state = params->state;
+ audio_mixer_streams[free_slot].volume = params->volume;
+ audio_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_mixer_streams[i].state;
+}
+
+static void audio_driver_mixer_play_stream_internal(unsigned i, unsigned type)
+{
+ bool set_state = false;
+
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return;
+
+ switch (audio_mixer_streams[i].state)
+ {
+ case AUDIO_STREAM_STATE_STOPPED:
+ audio_mixer_streams[i].voice = audio_mixer_play(audio_mixer_streams[i].handle,
+ (type == AUDIO_STREAM_STATE_PLAYING_LOOPED) ? true : false,
+ 1.0f, audio_mixer_streams[i].stop_cb);
+ set_state = true;
+ break;
+ case AUDIO_STREAM_STATE_PLAYING:
+ case AUDIO_STREAM_STATE_PLAYING_LOOPED:
+ case AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL:
+ case AUDIO_STREAM_STATE_NONE:
+ break;
+ }
+
+ if (set_state)
+ audio_mixer_streams[i].state = (enum audio_mixer_state)type;
+}
+
+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_menu_sounds(void)
+{
+ settings_t *settings = config_get_ptr();
+ char *sounds_path = NULL;
+ char *sounds_fallback_path = NULL;
+ const char *path_ok = NULL;
+ const char *path_cancel = NULL;
+ const char *path_notice = NULL;
+ const char *path_bgm = NULL;
+ struct string_list *list = NULL;
+ struct string_list *list_fallback = NULL;
+ unsigned i = 0;
+
+ sounds_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
+ sounds_fallback_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
+ sounds_path[0] = sounds_fallback_path[0] = '\0';
+
+ fill_pathname_join(
+ sounds_fallback_path,
+ settings->paths.directory_assets,
+ "sounds",
+ PATH_MAX_LENGTH * sizeof(char)
+ );
+
+ fill_pathname_application_special(sounds_path, PATH_MAX_LENGTH * sizeof(char), 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);
+ char basename_noext[PATH_MAX_LENGTH];
+
+ basename_noext[0] = '\0';
+
+ fill_pathname_base_noext(basename_noext, path, sizeof(basename_noext));
+
+ if (audio_driver_mixer_extension_supported(ext))
+ {
+ if (string_is_equal_noncase(basename_noext, "ok"))
+ path_ok = path;
+ if (string_is_equal_noncase(basename_noext, "cancel"))
+ path_cancel = path;
+ if (string_is_equal_noncase(basename_noext, "notice"))
+ path_notice = path;
+ if (string_is_equal_noncase(basename_noext, "bgm"))
+ path_bgm = path;
+ }
+ }
+
+ if (path_ok && settings->bools.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 && settings->bools.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 && settings->bools.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 && settings->bools.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);
+
+end:
+ if (list)
+ string_list_free(list);
+ if (list_fallback)
+ string_list_free(list_fallback);
+ if (sounds_path)
+ free(sounds_path);
+ if (sounds_fallback_path)
+ free(sounds_fallback_path);
+}
+
+void audio_driver_mixer_play_stream(unsigned i)
+{
+ audio_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_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_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_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_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_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_mixer_streams[i].volume = vol;
+
+ voice = 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;
+
+ if (i >= AUDIO_MIXER_MAX_SYSTEM_STREAMS)
+ return;
+
+ switch (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 = audio_mixer_streams[i].voice;
+
+ if (voice)
+ audio_mixer_stop(voice);
+ audio_mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
+ audio_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_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_mixer_streams[i].handle;
+ if (handle)
+ audio_mixer_destroy(handle);
+
+ if (!string_is_empty(audio_mixer_streams[i].name))
+ free(audio_mixer_streams[i].name);
+
+ audio_mixer_streams[i].state = AUDIO_STREAM_STATE_NONE;
+ audio_mixer_streams[i].stop_cb = NULL;
+ audio_mixer_streams[i].volume = 0.0f;
+ audio_mixer_streams[i].handle = NULL;
+ audio_mixer_streams[i].voice = NULL;
+ audio_mixer_streams[i].name = NULL;
+ }
+}
+
+bool audio_driver_set_callback(const void *data)
+{
+ const struct retro_audio_callback *cb = (const struct retro_audio_callback*)data;
+
+ if (cb)
+ audio_callback = *cb;
+
+ return true;
+}
+
+bool audio_driver_enable_callback(void)
+{
+ if (!audio_callback.callback)
+ return false;
+ if (audio_callback.set_state)
+ audio_callback.set_state(true);
+ return true;
+}
+
+bool audio_driver_disable_callback(void)
+{
+ if (!audio_callback.callback)
+ return false;
+
+ if (audio_callback.set_state)
+ audio_callback.set_state(false);
+ return true;
+}
+
+/* Sets audio monitor rate to new value. */
+static void audio_driver_monitor_set_rate(void)
+{
+ settings_t *settings = config_get_ptr();
+ double new_src_ratio = (double)settings->uints.audio_out_rate /
+ audio_driver_input;
+
+ audio_source_ratio_original = new_src_ratio;
+ audio_source_ratio_current = new_src_ratio;
+}
+
+bool audio_driver_callback(void)
+{
+ if (!audio_callback.callback)
+ return false;
+
+ if (audio_callback.callback)
+ audio_callback.callback();
+
+ return true;
+}
+
+bool audio_driver_has_callback(void)
+{
+ if (audio_callback.callback)
+ return true;
+ return false;
+}
+
+bool audio_driver_toggle_mute(void)
+{
+ audio_driver_mute_enable = !audio_driver_mute_enable;
+ return true;
+}
+
+bool audio_driver_mixer_toggle_mute(void)
+{
+ audio_driver_mixer_mute_enable = !audio_driver_mixer_mute_enable;
+ return true;
+}
+
+static INLINE bool audio_driver_alive(void)
+{
+ if ( current_audio
+ && current_audio->alive
+ && audio_driver_context_audio_data)
+ return current_audio->alive(audio_driver_context_audio_data);
+ return false;
+}
+
+bool audio_driver_start(bool is_shutdown)
+{
+ if (!current_audio || !current_audio->start
+ || !audio_driver_context_audio_data)
+ goto error;
+ if (!current_audio->start(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));
+ audio_driver_active = false;
+ return false;
+}
+
+bool audio_driver_stop(void)
+{
+ if (!current_audio || !current_audio->stop
+ || !audio_driver_context_audio_data)
+ return false;
+ if (!audio_driver_alive())
+ return false;
+ return current_audio->stop(audio_driver_context_audio_data);
+}
+
+static void audio_driver_unset_callback(void)
+{
+ audio_callback.callback = NULL;
+ audio_callback.set_state = NULL;
+}
+
+void audio_driver_frame_is_reverse(void)
+{
+ /* We just rewound. Flush rewind audio buffer. */
+ if (recording_data)
+ recording_push_audio(
+ audio_driver_rewind_buf + audio_driver_rewind_ptr,
+ audio_driver_rewind_size - audio_driver_rewind_ptr);
+
+ if (!(
+ runloop_paused ||
+ !audio_driver_active ||
+ !audio_driver_input_data ||
+ !audio_driver_output_samples_buf))
+ audio_driver_flush(
+ audio_driver_rewind_buf + audio_driver_rewind_ptr,
+ audio_driver_rewind_size - audio_driver_rewind_ptr,
+ runloop_slowmotion);
+}
+
+static void audio_driver_destroy_data(void)
+{
+ audio_driver_context_audio_data = NULL;
+}
+
+void audio_driver_suspend(void)
+{
+ audio_suspended = true;
+}
+
+bool audio_driver_is_suspended(void)
+{
+ return audio_suspended;
+}
+
+void audio_driver_resume(void)
+{
+ audio_suspended = false;
+}
+
+void audio_driver_set_active(void)
+{
+ audio_driver_active = true;
+}
+
+bool audio_driver_is_active(void)
+{
+ return audio_driver_active;
+}
+
+static void audio_driver_destroy(void)
+{
+ audio_driver_active = false;
+ current_audio = NULL;
+}
+
+void audio_set_bool(enum audio_action action, bool val)
+{
+ switch (action)
+ {
+ case AUDIO_ACTION_MIXER:
+ audio_mixer_active = val;
+ break;
+ case AUDIO_ACTION_NONE:
+ default:
+ break;
+ }
+}
+
+void audio_set_float(enum audio_action action, float val)
+{
+ switch (action)
+ {
+ case AUDIO_ACTION_VOLUME_GAIN:
+ audio_driver_volume_gain = db_to_gain(val);
+ break;
+ case AUDIO_ACTION_MIXER_VOLUME_GAIN:
+ audio_driver_mixer_volume_gain = db_to_gain(val);
+ break;
+ case AUDIO_ACTION_RATE_CONTROL_DELTA:
+ audio_driver_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_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:
+ return &audio_driver_mixer_mute_enable;
+ case AUDIO_ACTION_MUTE_ENABLE:
+ return &audio_driver_mute_enable;
+ case AUDIO_ACTION_NONE:
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static const char* audio_driver_get_ident(void)
+{
+ if (!current_audio)
+ return NULL;
+
+ return current_audio->ident;
+}
+
/* BSV Movie */
struct bsv_state
@@ -1406,6 +3182,19 @@ static bool driver_update_system_av_info(const struct retro_system_av_info *info
return true;
}
+bool audio_driver_new_devices_list(void)
+{
+ if (!current_audio || !current_audio->device_list_new
+ || !audio_driver_context_audio_data)
+ return false;
+ audio_driver_devices_list = (struct string_list*)
+ current_audio->device_list_new(audio_driver_context_audio_data);
+ if (!audio_driver_devices_list)
+ return false;
+ return true;
+}
+
+
/**
* drivers_init:
* @flags : Bitmask of drivers to initialize.
@@ -1446,7 +3235,7 @@ void drivers_init(int flags)
/* Initialize audio driver */
if (flags & DRIVER_AUDIO_MASK)
{
- audio_driver_init();
+ audio_driver_init_internal(audio_callback.callback != NULL);
audio_driver_new_devices_list();
}
diff --git a/retroarch.h b/retroarch.h
index 7e8521c1e3..fed19aec63 100644
--- a/retroarch.h
+++ b/retroarch.h
@@ -26,6 +26,9 @@
#include
#include
+#include
+
+#include "audio/audio_defines.h"
#include "core_type.h"
#include "core.h"
@@ -445,6 +448,265 @@ void rarch_log_file_deinit(void);
enum retro_language rarch_get_language_from_iso(const char *lang);
+/* Audio */
+
+typedef struct audio_mixer_stream
+{
+ audio_mixer_sound_t *handle;
+ audio_mixer_voice_t *voice;
+ audio_mixer_stop_cb_t stop_cb;
+ enum audio_mixer_stream_type stream_type;
+ enum audio_mixer_type type;
+ enum audio_mixer_state state;
+ float volume;
+ void *buf;
+ char *name;
+ size_t bufsize;
+} audio_mixer_stream_t;
+
+typedef struct audio_mixer_stream_params
+{
+ float volume;
+ enum audio_mixer_slot_selection_type slot_selection_type;
+ unsigned slot_selection_idx;
+ enum audio_mixer_stream_type stream_type;
+ enum audio_mixer_type type;
+ enum audio_mixer_state state;
+ void *buf;
+ char *basename;
+ size_t bufsize;
+ audio_mixer_stop_cb_t cb;
+} audio_mixer_stream_params_t;
+
+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;
+
+void audio_driver_suspend(void);
+
+bool audio_driver_is_suspended(void);
+
+void audio_driver_resume(void);
+
+void audio_driver_set_active(void);
+
+bool audio_driver_is_active(void);
+
+bool audio_driver_enable_callback(void);
+
+bool audio_driver_disable_callback(void);
+
+/**
+ * audio_driver_find_handle:
+ * @index : index of driver to get handle to.
+ *
+ * Returns: handle to audio driver at index. Can be NULL
+ * if nothing found.
+ **/
+const void *audio_driver_find_handle(int index);
+
+/**
+ * audio_driver_find_ident:
+ * @index : index of driver to get handle to.
+ *
+ * Returns: Human-readable identifier of audio driver at index. Can be NULL
+ * if nothing found.
+ **/
+const char *audio_driver_find_ident(int index);
+
+void audio_driver_set_nonblocking_state(bool enable);
+
+/**
+ * config_get_audio_driver_options:
+ *
+ * Get an enumerated list of all audio driver names, separated by '|'.
+ *
+ * Returns: string listing of all audio driver names, separated by '|'.
+ **/
+const char* config_get_audio_driver_options(void);
+
+void audio_driver_sample(int16_t left, int16_t right);
+
+size_t audio_driver_sample_batch(const int16_t *data, size_t frames);
+
+void audio_driver_sample_rewind(int16_t left, int16_t right);
+
+size_t audio_driver_sample_batch_rewind(const int16_t *data, size_t frames);
+
+bool audio_driver_mixer_extension_supported(const char *ext);
+
+void audio_driver_dsp_filter_free(void);
+
+void 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_set_callback(const void *data);
+
+bool audio_driver_callback(void);
+
+bool audio_driver_has_callback(void);
+
+bool audio_driver_toggle_mute(void);
+
+bool audio_driver_start(bool is_shutdown);
+
+bool audio_driver_stop(void);
+
+void audio_driver_frame_is_reverse(void);
+
+void audio_set_float(enum audio_action action, float val);
+
+void audio_set_bool(enum audio_action action, bool val);
+
+void audio_unset_bool(enum audio_action action, bool val);
+
+float *audio_get_float_ptr(enum audio_action action);
+
+bool *audio_get_bool_ptr(enum audio_action action);
+
+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);
+
+bool compute_audio_buffer_statistics(audio_statistics_t *stats);
+
+void audio_driver_load_menu_sounds(void);
+
+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;
+extern audio_driver_t audio_switch;
+extern audio_driver_t audio_switch_thread;
+extern audio_driver_t audio_rwebaudio;
+extern audio_driver_t audio_null;
+
/* BSV Movie */
enum rarch_movie_type
diff --git a/runahead/run_ahead.c b/runahead/run_ahead.c
index cdb1d3d2e8..1881935710 100644
--- a/runahead/run_ahead.c
+++ b/runahead/run_ahead.c
@@ -11,7 +11,6 @@
#include "../core.h"
#include "../dynamic.h"
-#include "../audio/audio_driver.h"
#include "../gfx/video_driver.h"
#include "../configuration.h"
#include "../retroarch.h"
diff --git a/tasks/task_audio_mixer.c b/tasks/task_audio_mixer.c
index bd0096501d..28b00e3c1a 100644
--- a/tasks/task_audio_mixer.c
+++ b/tasks/task_audio_mixer.c
@@ -28,9 +28,8 @@
#include
#include
-#include "../audio/audio_driver.h"
-
#include "../file_path_special.h"
+#include "../retroarch.h"
#include "../verbosity.h"
#include "task_file_transfer.h"
diff --git a/tasks/task_audio_mixer.h b/tasks/task_audio_mixer.h
index 62e442e125..9f27c81384 100644
--- a/tasks/task_audio_mixer.h
+++ b/tasks/task_audio_mixer.h
@@ -28,7 +28,7 @@
#include "../config.h"
#endif
-#include "../audio/audio_driver.h"
+#include "../retroarch.h"
RETRO_BEGIN_DECLS