diff --git a/CHANGES.md b/CHANGES.md index 40801c5014..550c51d995 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,7 @@ - MENU: New "ozone" menu driver. - MENU: Only show CRT SwitchRes if video display server is implemented (Windows/Linux for now) - MENU: User Interface -> Appearance -> 'Menu Font Green/Blue Color' settings now work properly. +- MENU: Add option to enable in-menu sound effects - MENU/QT/WIMP: Allow building with MSVC2017 - MENU/QT/WIMP: Add detailed file browser table - MENU/QT/WIMP: New grid view implementation that is faster and loads thumbnails on-demand diff --git a/audio/audio_driver.c b/audio/audio_driver.c index 9290dc41b1..6814a8adbc 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include "../config.h" @@ -35,6 +36,7 @@ #include "../gfx/video_driver.h" #include "../record/record_driver.h" #include "../frontend/frontend_driver.h" +#include "../tasks/tasks_internal.h" #include "../command.h" #include "../driver.h" @@ -42,9 +44,17 @@ #include "../retroarch.h" #include "../verbosity.h" #include "../list_special.h" +#include "../file_path_special.h" +#include "../content.h" + +#ifdef HAVE_THREADS +#include +#endif #define AUDIO_BUFFER_FREE_SAMPLES_COUNT (8 * 1024) +#define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac" + /** * db_to_gain: * @db : Decibels. @@ -185,11 +195,34 @@ 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; + +#ifdef HAVE_THREADS +static slock_t* s_audio_driver_lock = NULL; +#endif 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 void audio_driver_lock(void) +{ +#ifdef HAVE_THREADS + if (s_audio_driver_lock) + slock_lock(s_audio_driver_lock); +#endif +} + +static void audio_driver_unlock(void) +{ +#ifdef HAVE_THREADS + if (s_audio_driver_lock) + slock_unlock(s_audio_driver_lock); +#endif +} enum resampler_quality audio_driver_get_resampler_quality(void) { @@ -447,6 +480,7 @@ static bool audio_driver_init_internal(bool audio_cb_inited) #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, @@ -465,6 +499,7 @@ static bool audio_driver_init_internal(bool audio_cb_inited) else #endif { + audio_is_threaded = false; audio_driver_context_audio_data = current_audio->init(*settings->arrays.audio_device ? settings->arrays.audio_device : NULL, @@ -507,6 +542,15 @@ static bool audio_driver_init_internal(bool audio_cb_inited) audio_source_ratio_original = audio_source_ratio_current = (double)settings->uints.audio_out_rate / audio_driver_input; +#ifdef HAVE_THREADS + if (s_audio_driver_lock) + slock_free(s_audio_driver_lock); + s_audio_driver_lock = slock_new(); +#endif + + audio_resampler_lock_init(); + audio_resampler_lock(); + if (!retro_resampler_realloc( &audio_driver_resampler_data, &audio_driver_resampler, @@ -519,6 +563,8 @@ static bool audio_driver_init_internal(bool audio_cb_inited) audio_driver_active = false; } + audio_resampler_unlock(); + aud_inp_data = (float*)malloc(max_bufsamples * sizeof(float)); retro_assert(aud_inp_data != NULL); @@ -589,9 +635,13 @@ void audio_driver_set_nonblocking_state(bool enable) audio_driver_context_audio_data, settings->bools.audio_sync ? enable : true); + audio_driver_lock(); + audio_driver_chunk_size = enable ? audio_driver_chunk_nonblock_size : audio_driver_chunk_block_size; + + audio_driver_unlock(); } /** @@ -609,6 +659,7 @@ static void audio_driver_flush(const int16_t *data, size_t samples) bool is_paused = false; bool is_idle = false; bool is_slowmotion = false; + bool is_active = false; const void *output_data = NULL; unsigned output_frames = 0; float audio_volume_gain = !audio_driver_mute_enable ? @@ -617,9 +668,13 @@ static void audio_driver_flush(const int16_t *data, size_t samples) src_data.data_out = NULL; src_data.output_frames = 0; + recording_driver_lock(); + if (recording_data) recording_push_audio(data, samples); + recording_driver_unlock(); + runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); @@ -629,9 +684,13 @@ static void audio_driver_flush(const int16_t *data, size_t samples) !audio_driver_output_samples_buf) return; + audio_driver_lock(); + convert_s16_to_float(audio_driver_input_data, data, samples, audio_volume_gain); + audio_driver_unlock(); + src_data.data_in = audio_driver_input_data; src_data.input_frames = samples >> 1; @@ -695,9 +754,15 @@ static void audio_driver_flush(const int16_t *data, size_t samples) src_data.ratio *= settings->floats.slowmotion_ratio; } - audio_driver_resampler->process(audio_driver_resampler_data, &src_data); + audio_driver_lock(); - if (audio_mixer_active) + audio_resampler_lock(); + audio_driver_resampler->process(audio_driver_resampler_data, &src_data); + audio_resampler_unlock(); + + is_active = audio_mixer_active; + + if (is_active) { bool override = audio_driver_mixer_mute_enable ? true : (audio_driver_mixer_volume_gain != 1.0f) ? true : false; @@ -707,6 +772,8 @@ static void audio_driver_flush(const int16_t *data, size_t samples) src_data.output_frames, mixer_gain, override); } + audio_driver_unlock(); + output_data = audio_driver_output_samples_buf; output_frames = (unsigned)src_data.output_frames; @@ -721,9 +788,13 @@ static void audio_driver_flush(const int16_t *data, size_t samples) output_frames *= sizeof(int16_t); } + audio_driver_lock(); + if (current_audio->write(audio_driver_context_audio_data, output_data, output_frames * 2) < 0) audio_driver_active = false; + + audio_driver_unlock(); } /** @@ -735,14 +806,24 @@ static void audio_driver_flush(const int16_t *data, size_t samples) **/ void audio_driver_sample(int16_t left, int16_t right) { + audio_driver_lock(); + if (audio_suspended) + { + audio_driver_unlock(); 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) + { + audio_driver_unlock(); return; + } + + audio_driver_unlock(); audio_driver_flush(audio_driver_output_samples_conv_buf, audio_driver_data_ptr); @@ -753,9 +834,8 @@ void audio_driver_sample(int16_t left, int16_t right) 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 = + 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; while (sample_count > 1024) @@ -966,10 +1046,13 @@ bool audio_driver_find_driver(void) void audio_driver_deinit_resampler(void) { + audio_resampler_lock(); 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; + audio_resampler_unlock(); + audio_resampler_lock_free(); } bool audio_driver_free_devices_list(void) @@ -1095,6 +1178,28 @@ static void audio_mixer_play_stop_cb( } } +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) { @@ -1113,9 +1218,9 @@ static void audio_mixer_play_stop_sequential_cb( free(audio_mixer_streams[i].name); if (i < AUDIO_MIXER_MAX_STREAMS) - audio_mixer_streams[i].type = AUDIO_STREAM_TYPE_USER; + audio_mixer_streams[i].stream_type = AUDIO_STREAM_TYPE_USER; else - audio_mixer_streams[i].type = AUDIO_STREAM_TYPE_SYSTEM; + 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; @@ -1243,17 +1348,22 @@ bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params) break; } + audio_driver_lock(); + audio_mixer_active = true; - audio_mixer_streams[free_slot].name = !string_is_empty(params->basename) ? strdup(params->basename) : NULL; + 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].type = params->stream_type; + 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; + audio_driver_unlock(); + return true; } @@ -1291,12 +1401,128 @@ static void audio_driver_mixer_play_stream_internal(unsigned i, unsigned type) audio_mixer_streams[i].state = (enum audio_mixer_state)type; } +static void audio_driver_load_menu_bgm_callback(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; + int 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; @@ -1421,6 +1647,9 @@ bool audio_driver_deinit(void) { audio_driver_mixer_deinit(); audio_driver_free_devices_list(); + slock_free(s_audio_driver_lock); + s_audio_driver_lock = NULL; + if (!audio_driver_deinit_internal()) return false; return true; diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 2e1f59e344..d6649e6c4b 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -37,7 +37,16 @@ RETRO_BEGIN_DECLS #define AUDIO_MIXER_MAX_STREAMS 16 -#define AUDIO_MIXER_MAX_SYSTEM_STREAMS (AUDIO_MIXER_MAX_STREAMS+4) +#define AUDIO_MIXER_MAX_SYSTEM_STREAMS (AUDIO_MIXER_MAX_STREAMS + 4) + +/* do not define more than (MAX_SYSTEM_STREAMS - MAX_STREAMS) */ +enum audio_mixer_system_slot +{ + AUDIO_MIXER_SYSTEM_SLOT_OK = AUDIO_MIXER_MAX_STREAMS, + AUDIO_MIXER_SYSTEM_SLOT_CANCEL, + AUDIO_MIXER_SYSTEM_SLOT_NOTICE, + AUDIO_MIXER_SYSTEM_SLOT_BGM +}; enum audio_action { @@ -315,6 +324,10 @@ 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); @@ -335,6 +348,8 @@ 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; diff --git a/config.def.h b/config.def.h index 2ed6bfb5ab..167c78cf16 100644 --- a/config.def.h +++ b/config.def.h @@ -508,6 +508,13 @@ static const bool video_3ds_lcd_bottom = true; /* Will enable audio or not. */ static const bool audio_enable = true; +/* Enable menu audio sounds. */ +static const bool audio_enable_menu = false; +static const bool audio_enable_menu_ok = false; +static const bool audio_enable_menu_cancel = false; +static const bool audio_enable_menu_notice = false; +static const bool audio_enable_menu_bgm = false; + /* Output samplerate. */ #ifdef GEKKO static const unsigned out_rate = 32000; diff --git a/configuration.c b/configuration.c index 45e69835f2..ef846ff1e8 100644 --- a/configuration.c +++ b/configuration.c @@ -1395,7 +1395,11 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("keyboard_gamepad_enable", &settings->bools.input_keyboard_gamepad_enable, true, true, false); SETTING_BOOL("core_set_supports_no_game_enable", &settings->bools.set_supports_no_game_enable, true, true, false); SETTING_BOOL("audio_enable", &settings->bools.audio_enable, true, audio_enable, false); - SETTING_BOOL("audio_enable_menu", &settings->bools.audio_enable_menu, true, false, false); + SETTING_BOOL("audio_enable_menu", &settings->bools.audio_enable_menu, true, audio_enable_menu, false); + SETTING_BOOL("audio_enable_menu_ok", &settings->bools.audio_enable_menu_ok, true, audio_enable_menu_ok, false); + SETTING_BOOL("audio_enable_menu_cancel", &settings->bools.audio_enable_menu_cancel, true, audio_enable_menu_cancel, false); + SETTING_BOOL("audio_enable_menu_notice", &settings->bools.audio_enable_menu_notice, true, audio_enable_menu_notice, false); + SETTING_BOOL("audio_enable_menu_bgm", &settings->bools.audio_enable_menu_bgm, true, audio_enable_menu_bgm, false); SETTING_BOOL("audio_mute_enable", audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE), true, false, false); SETTING_BOOL("audio_mixer_mute_enable", audio_get_bool_ptr(AUDIO_ACTION_MIXER_MUTE_ENABLE), true, false, false); SETTING_BOOL("location_allow", &settings->bools.location_allow, true, false, false); diff --git a/configuration.h b/configuration.h index cbe6f7888f..2763078bd4 100644 --- a/configuration.h +++ b/configuration.h @@ -110,6 +110,10 @@ typedef struct settings /* Audio */ bool audio_enable; bool audio_enable_menu; + bool audio_enable_menu_ok; + bool audio_enable_menu_cancel; + bool audio_enable_menu_notice; + bool audio_enable_menu_bgm; bool audio_sync; bool audio_rate_control; bool audio_wasapi_exclusive_mode; diff --git a/file_path_special.c b/file_path_special.c index 70769b97da..ca106bf89a 100644 --- a/file_path_special.c +++ b/file_path_special.c @@ -51,6 +51,10 @@ #include #include +#ifdef HAVE_MENU +#include +#endif + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -238,6 +242,70 @@ void fill_pathname_application_special(char *s, free(s1); } } +#endif + break; + case APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS: + { +#ifdef HAVE_MENU + settings_t *settings = config_get_ptr(); + const char *menu_ident = settings->arrays.menu_driver; + char *s1 = (char*)calloc(1, PATH_MAX_LENGTH * sizeof(char)); + + if (string_is_equal(menu_ident, "xmb")) + { + fill_pathname_application_special(s1, PATH_MAX_LENGTH * sizeof(char), APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB); + + if (!string_is_empty(s1)) + strlcat(s1, "/sounds", PATH_MAX_LENGTH * sizeof(char)); + } + else if (string_is_equal(menu_ident, "glui")) + { + fill_pathname_application_special(s1, PATH_MAX_LENGTH * sizeof(char), APPLICATION_SPECIAL_DIRECTORY_ASSETS_MATERIALUI); + + if (!string_is_empty(s1)) + strlcat(s1, "/sounds", PATH_MAX_LENGTH * sizeof(char)); + } + else if (string_is_equal(menu_ident, "ozone")) + { + fill_pathname_application_special(s1, PATH_MAX_LENGTH * sizeof(char), APPLICATION_SPECIAL_DIRECTORY_ASSETS_OZONE); + + if (!string_is_empty(s1)) + strlcat(s1, "/sounds", PATH_MAX_LENGTH * sizeof(char)); + } + + if (string_is_empty(s1)) + { + fill_pathname_join( + s1, + settings->paths.directory_assets, + "sounds", + PATH_MAX_LENGTH * sizeof(char) + ); + } + + strlcpy(s, s1, len); + free(s1); +#endif + } + + break; + case APPLICATION_SPECIAL_DIRECTORY_ASSETS_OZONE: +#ifdef HAVE_OZONE + { + char *s1 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + settings_t *settings = config_get_ptr(); + + s1[0] = '\0'; + + fill_pathname_join( + s1, + settings->paths.directory_assets, + "ozone", + PATH_MAX_LENGTH * sizeof(char) + ); + strlcpy(s, s1, len); + free(s1); + } #endif break; case APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB: diff --git a/file_path_special.h b/file_path_special.h index d98a6b3971..ec9c5c27ee 100644 --- a/file_path_special.h +++ b/file_path_special.h @@ -111,6 +111,8 @@ enum application_special_type APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH, APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_FONT, APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_ICONS, + APPLICATION_SPECIAL_DIRECTORY_ASSETS_OZONE, + APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS, APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES, APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS }; diff --git a/frontend/frontend.c b/frontend/frontend.c index 3c954f20f1..effe00f8b4 100644 --- a/frontend/frontend.c +++ b/frontend/frontend.c @@ -38,6 +38,7 @@ #include "../paths.h" #include "../retroarch.h" #include "../verbosity.h" +#include "../record/record_driver.h" #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) #include @@ -91,6 +92,7 @@ void main_exit(void *args) driver_ctl(RARCH_DRIVER_CTL_DEINIT, NULL); ui_companion_driver_free(); frontend_driver_free(); + recording_driver_lock_free(); #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) CoUninitialize(); diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 3d29a3c182..3e05c64d70 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -1422,6 +1422,8 @@ bool video_driver_cached_frame(void) { void *recording = recording_driver_get_data_ptr(); + recording_driver_lock(); + /* Cannot allow recording when pushing duped frames. */ recording_data = NULL; @@ -1433,6 +1435,8 @@ bool video_driver_cached_frame(void) recording_data = recording; + recording_driver_unlock(); + return true; } diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 0dcb5bb540..7343eeded8 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -305,6 +305,8 @@ MSG_HASH(MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST, "deferred_audio_settings_list") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_AUDIO_MIXER_SETTINGS_LIST, "deferred_audio_mixer_settings_list") +MSG_HASH(MENU_ENUM_LABEL_DEFERRED_MENU_SOUNDS_LIST, + "deferred_menu_sounds_list") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_CONFIGURATION_SETTINGS_LIST, "deferred_configuration_settings_list") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST, @@ -1609,6 +1611,8 @@ MSG_HASH(MENU_ENUM_LABEL_AUDIO_ENABLE_MENU, "audio_enable_menu") MSG_HASH(MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS, "audio_mixer_settings") +MSG_HASH(MENU_ENUM_LABEL_MENU_SOUNDS, + "menu_sounds") MSG_HASH(MENU_ENUM_LABEL_DEFERRED_MIXER_STREAM_SETTINGS_LIST, "deferred_mixer_stream_settings_list") MSG_HASH(MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS, @@ -1769,3 +1773,11 @@ MSG_HASH(MENU_ENUM_LABEL_VIDEO_3DS_LCD_BOTTOM, "video_3ds_lcd_bottom") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_USE_OLD_FORMAT, "playlist_use_old_format") +MSG_HASH(MENU_ENUM_LABEL_MENU_SOUND_OK, + "menu_sound_ok") +MSG_HASH(MENU_ENUM_LABEL_MENU_SOUND_CANCEL, + "menu_sound_cancel") +MSG_HASH(MENU_ENUM_LABEL_MENU_SOUND_NOTICE, + "menu_sound_notice") +MSG_HASH(MENU_ENUM_LABEL_MENU_SOUND_BGM, + "menu_sound_bgm") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 1632690f8a..073cdefb27 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -8112,3 +8112,23 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_USE_OLD_FORMAT, "Save playlists using old format" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SOUNDS, + "Menu Sounds" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SOUND_OK, + "Enable OK sound" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SOUND_CANCEL, + "Enable cancel sound" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SOUND_NOTICE, + "Enable notice sound" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_MENU_SOUND_BGM, + "Enable BGM sound" + ) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index f0022f957a..03e1a4eabf 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -188,7 +188,7 @@ struct audio_mixer_voice } types; }; -static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0}; +static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {{0}}; static unsigned s_rate = 0; #ifdef HAVE_THREADS @@ -318,6 +318,8 @@ void audio_mixer_init(unsigned rate) s_voices[i].type = AUDIO_MIXER_TYPE_NONE; #ifdef HAVE_THREADS + if (s_locker) + slock_free(s_locker); s_locker = slock_new(); #endif } @@ -551,17 +553,18 @@ static bool audio_mixer_play_ogg( if (!ogg_buffer) { - resamp->free(resampler_data); + if (resamp && resampler_data) + resamp->free(resampler_data); goto error; } /* "system" menu sounds may reuse the same voice without freeing anything first, so do that here if needed */ - if (voice->types.ogg.buffer) - memalign_free(voice->types.ogg.buffer); if (voice->types.ogg.stream) stb_vorbis_close(voice->types.ogg.stream); if (voice->types.ogg.resampler && voice->types.ogg.resampler_data) voice->types.ogg.resampler->free(voice->types.ogg.resampler_data); + if (voice->types.ogg.buffer) + memalign_free(voice->types.ogg.buffer); voice->types.ogg.resampler = resamp; voice->types.ogg.resampler_data = resampler_data; @@ -635,10 +638,11 @@ static bool audio_mixer_play_mod( goto error; } - if (voice->types.mod.buffer) - memalign_free(voice->types.mod.buffer); + /* FIXME: stopping and then starting a mod stream will crash here in dispose_replay (ASAN says struct replay is misaligned?) */ if (voice->types.mod.stream) dispose_replay(voice->types.mod.stream); + if (voice->types.mod.buffer) + memalign_free(voice->types.mod.buffer); voice->types.mod.buffer = (int*)mod_buffer; voice->types.mod.buf_samples = buf_samples; @@ -696,12 +700,12 @@ static bool audio_mixer_play_flac( goto error; } - if (voice->types.flac.buffer) - memalign_free(voice->types.flac.buffer); if (voice->types.flac.stream) drflac_close(voice->types.flac.stream); if (voice->types.flac.resampler && voice->types.flac.resampler_data) voice->types.flac.resampler->free(voice->types.flac.resampler_data); + if (voice->types.flac.buffer) + memalign_free(voice->types.flac.buffer); voice->types.flac.resampler = resamp; voice->types.flac.resampler_data = resampler_data; @@ -761,15 +765,16 @@ static bool audio_mixer_play_mp3( if (!mp3_buffer) { - resamp->free(resampler_data); + if (resamp && resampler_data) + resamp->free(resampler_data); goto error; } /* "system" menu sounds may reuse the same voice without freeing anything first, so do that here if needed */ - if (voice->types.mp3.buffer) - memalign_free(voice->types.mp3.buffer); if (voice->types.mp3.resampler && voice->types.mp3.resampler_data) voice->types.mp3.resampler->free(voice->types.mp3.resampler_data); + if (voice->types.mp3.buffer) + memalign_free(voice->types.mp3.buffer); voice->types.mp3.resampler = resamp; voice->types.mp3.resampler_data = resampler_data; @@ -801,6 +806,8 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, slock_lock(s_locker); #endif + audio_resampler_lock(); + for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++) { if (voice->type != AUDIO_MIXER_TYPE_NONE) @@ -849,6 +856,8 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, else voice = NULL; + audio_resampler_unlock(); + #ifdef HAVE_THREADS slock_unlock(s_locker); #endif @@ -863,13 +872,13 @@ void audio_mixer_stop(audio_mixer_voice_t* voice) if (voice) { - stop_cb = voice->stop_cb; - sound = voice->sound; - #ifdef HAVE_THREADS slock_lock(s_locker); #endif + stop_cb = voice->stop_cb; + sound = voice->sound; + voice->type = AUDIO_MIXER_TYPE_NONE; #ifdef HAVE_THREADS @@ -971,7 +980,9 @@ again: info.ratio = voice->types.ogg.ratio; if (voice->types.ogg.resampler) + { voice->types.ogg.resampler->process(voice->types.ogg.resampler_data, &info); + } else memcpy(voice->types.ogg.buffer, temp_buffer, temp_samples * sizeof(float)); voice->types.ogg.position = 0; @@ -1118,7 +1129,9 @@ again: info.ratio = voice->types.flac.ratio; if (voice->types.flac.resampler) + { voice->types.flac.resampler->process(voice->types.flac.resampler_data, &info); + } else memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float)); voice->types.flac.position = 0; @@ -1231,6 +1244,8 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo slock_lock(s_locker); #endif + audio_resampler_lock(); + for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++) { float volume = (override) ? volume_override : voice->volume; @@ -1265,10 +1280,6 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo } } -#ifdef HAVE_THREADS - slock_unlock(s_locker); -#endif - for (j = 0, sample = buffer; j < num_frames; j++, sample++) { if (*sample < -1.0f) @@ -1276,6 +1287,12 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo else if (*sample > 1.0f) *sample = 1.0f; } + + audio_resampler_unlock(); + +#ifdef HAVE_THREADS + slock_unlock(s_locker); +#endif } float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice) diff --git a/libretro-common/audio/resampler/audio_resampler.c b/libretro-common/audio/resampler/audio_resampler.c index 8d27f06932..dc3df93d3a 100644 --- a/libretro-common/audio/resampler/audio_resampler.c +++ b/libretro-common/audio/resampler/audio_resampler.c @@ -28,6 +28,14 @@ #include