diff --git a/config.def.h b/config.def.h index ce317ce203..a9702808c9 100644 --- a/config.def.h +++ b/config.def.h @@ -803,6 +803,10 @@ static const bool audio_enable_menu_bgm = false; #define DEFAULT_WASAPI_SH_BUFFER_LENGTH -16 #endif +/* Automatically mute audio when fast forward + * is enabled */ +#define DEFAULT_AUDIO_FASTFORWARD_MUTE false + /* MISC */ /* Enables displaying the current frames per second. */ diff --git a/configuration.c b/configuration.c index 1216e85341..7ddc5c13af 100644 --- a/configuration.c +++ b/configuration.c @@ -1432,6 +1432,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, #ifdef HAVE_AUDIOMIXER SETTING_BOOL("audio_mixer_mute_enable", audio_get_bool_ptr(AUDIO_ACTION_MIXER_MUTE_ENABLE), true, false, false); #endif + SETTING_BOOL("audio_fastforward_mute", &settings->bools.audio_fastforward_mute, true, DEFAULT_AUDIO_FASTFORWARD_MUTE, false); SETTING_BOOL("location_allow", &settings->bools.location_allow, true, false, false); SETTING_BOOL("video_font_enable", &settings->bools.video_font_enable, true, DEFAULT_FONT_ENABLE, false); SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, true, false); diff --git a/configuration.h b/configuration.h index d5199ebd9f..0363cb7121 100644 --- a/configuration.h +++ b/configuration.h @@ -131,6 +131,7 @@ typedef struct settings bool audio_rate_control; bool audio_wasapi_exclusive_mode; bool audio_wasapi_float_format; + bool audio_fastforward_mute; /* Input */ bool input_remap_binds_enable; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index f8fd00b7c1..b14c5e66f3 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -102,6 +102,10 @@ MSG_HASH( MENU_ENUM_LABEL_AUDIO_MUTE, "audio_mute_enable" ) +MSG_HASH( + MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, + "audio_fastforward_mute" + ) MSG_HASH( MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE, "audio_output_rate" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index b8253f46fc..6e5daa7aaa 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -1664,6 +1664,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Mute/unmute mixer audio." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, + "Mute When Fast-Forwarding" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE, + "Automatically mute audio when using fast-forward." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, "Volume Gain (dB)" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index b215df055f..6aff97f596 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -250,6 +250,7 @@ default_sublabel_macro(action_bind_sublabel_audio_mute, MENU_ #ifdef HAVE_AUDIOMIXER default_sublabel_macro(action_bind_sublabel_audio_mixer_mute, MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE) #endif +default_sublabel_macro(action_bind_sublabel_audio_fastforward_mute, MENU_ENUM_SUBLABEL_AUDIO_FASTFORWARD_MUTE) default_sublabel_macro(action_bind_sublabel_camera_allow, MENU_ENUM_SUBLABEL_CAMERA_ALLOW) default_sublabel_macro(action_bind_sublabel_location_allow, MENU_ENUM_SUBLABEL_LOCATION_ALLOW) default_sublabel_macro(action_bind_sublabel_input_max_users, MENU_ENUM_SUBLABEL_INPUT_MAX_USERS) @@ -2697,6 +2698,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_mixer_mute); #endif break; + case MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_fastforward_mute); + break; case MENU_ENUM_LABEL_AUDIO_LATENCY: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_latency); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 5b545d56c9..09186cb435 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4652,6 +4652,10 @@ unsigned menu_displaylist_build_list( MENU_ENUM_LABEL_AUDIO_MIXER_MUTE, PARSE_ONLY_BOOL, false) == 0) count++; + if (menu_displaylist_parse_settings_enum(list, + MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, + PARSE_ONLY_BOOL, false) == 0) + count++; if (menu_displaylist_parse_settings_enum(list, MENU_ENUM_LABEL_AUDIO_VOLUME, PARSE_ONLY_FLOAT, false) == 0) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index e383905927..58ebff44f6 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -10843,6 +10843,21 @@ static bool setting_append_list( SD_FLAG_LAKKA_ADVANCED ); #endif + CONFIG_BOOL( + list, list_info, + &settings->bools.audio_fastforward_mute, + MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, + MENU_ENUM_LABEL_VALUE_AUDIO_FASTFORWARD_MUTE, + DEFAULT_AUDIO_FASTFORWARD_MUTE, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE + ); CONFIG_FLOAT( list, list_info, diff --git a/msg_hash.h b/msg_hash.h index 4a8f2c295d..5c68f629fc 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1500,6 +1500,7 @@ enum msg_hash_enums MENU_LABEL(AUDIO_DSP_PLUGIN), MENU_LABEL(AUDIO_MUTE), MENU_LABEL(AUDIO_MIXER_MUTE), + MENU_LABEL(AUDIO_FASTFORWARD_MUTE), MENU_LABEL(AUDIO_SYNC), MENU_LABEL(AUDIO_VOLUME), MENU_LABEL(AUDIO_MIXER_VOLUME), diff --git a/retroarch.c b/retroarch.c index 39766a5e47..223ad7c15e 100644 --- a/retroarch.c +++ b/retroarch.c @@ -21075,12 +21075,14 @@ error: * perform DSP processing (if enabled) and resampling. **/ static void audio_driver_flush(const int16_t *data, size_t samples, - bool is_slowmotion) + bool is_slowmotion, bool is_fastmotion) { struct resampler_data src_data; float slowmotion_ratio = configuration_settings->floats.slowmotion_ratio; - float audio_volume_gain = !audio_driver_mute_enable ? - audio_driver_volume_gain : 0.0f; + bool audio_fastforward_mute = configuration_settings->bools.audio_fastforward_mute; + float audio_volume_gain = (audio_driver_mute_enable || + (audio_fastforward_mute && is_fastmotion)) ? + 0.0f : audio_driver_volume_gain; src_data.data_out = NULL; src_data.output_frames = 0; @@ -21148,6 +21150,23 @@ static void audio_driver_flush(const int16_t *data, size_t samples, if (is_slowmotion) src_data.ratio *= slowmotion_ratio; + /* Note: Ideally we would divide by the user-configured + * 'fastforward_ratio' when fast forward is enabled, + * but in practice this doesn't work: + * - 'fastforward_ratio' is only a limit. If the host + * cannot push frames fast enough, the actual ratio + * will be lower - and crackling will ensue + * - Most of the time 'fastforward_ratio' will be + * zero (unlimited) + * So what we would need to do is measure the time since + * the last audio flush operation, and calculate a 'real' + * fast-forward ratio - but this doesn't work either. + * The measurement is inaccurate and the frame-by-frame + * fluctuations are too large, so crackling is unavoidable. + * Since it's going to crackle anyway, there's no point + * trying to do anything. Just leave the ratio as-is, + * and hope for the best... */ + audio_driver_resampler->process(audio_driver_resampler_data, &src_data); #ifdef HAVE_AUDIOMIXER @@ -21216,7 +21235,7 @@ static void audio_driver_sample(int16_t left, int16_t right) !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, runloop_slowmotion, runloop_fastmotion); audio_driver_data_ptr = 0; } @@ -21247,7 +21266,7 @@ static void audio_driver_menu_sample(void) recording_driver->push_audio(recording_data, &ffemu_data); } if (check_flush) - audio_driver_flush(samples_buf, 1024, runloop_slowmotion); + audio_driver_flush(samples_buf, 1024, runloop_slowmotion, runloop_fastmotion); sample_count -= 1024; } if (recording_data && recording_driver && recording_driver->push_audio) @@ -21260,7 +21279,7 @@ static void audio_driver_menu_sample(void) recording_driver->push_audio(recording_data, &ffemu_data); } if (check_flush) - audio_driver_flush(samples_buf, sample_count, runloop_slowmotion); + audio_driver_flush(samples_buf, sample_count, runloop_slowmotion, runloop_fastmotion); } #endif @@ -21297,7 +21316,7 @@ static size_t audio_driver_sample_batch(const int16_t *data, size_t frames) !audio_driver_active || !audio_driver_input_data || !audio_driver_output_samples_buf)) - audio_driver_flush(data, frames << 1, runloop_slowmotion); + audio_driver_flush(data, frames << 1, runloop_slowmotion, runloop_fastmotion); return frames; } @@ -22101,7 +22120,7 @@ void audio_driver_frame_is_reverse(void) audio_driver_flush( audio_driver_rewind_buf + audio_driver_rewind_ptr, audio_driver_rewind_size - audio_driver_rewind_ptr, - runloop_slowmotion); + runloop_slowmotion, runloop_fastmotion); } void audio_set_float(enum audio_action action, float val)