diff --git a/assets/config_menu/sound.rml b/assets/config_menu/sound.rml index 8284d71..badadce 100644 --- a/assets/config_menu/sound.rml +++ b/assets/config_menu/sound.rml @@ -7,30 +7,47 @@
+ +
+ + +
+
+
-
+
-

+

+ Controls the main volume of the game. +

+

Controls the overall volume of background music.

-

+

Toggles whether or not the low-health beeping sound plays.

diff --git a/include/recomp_sound.h b/include/recomp_sound.h index 04408e0..f33ed4a 100644 --- a/include/recomp_sound.h +++ b/include/recomp_sound.h @@ -3,6 +3,8 @@ namespace recomp { void reset_sound_settings(); + void set_main_volume(int volume); + int get_main_volume(); void set_bgm_volume(int volume); int get_bgm_volume(); void set_low_health_beeps_enabled(bool enabled); diff --git a/src/game/config.cpp b/src/game/config.cpp index 7c37d2a..2ea2646 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -344,6 +344,7 @@ void load_controls_config(const std::filesystem::path& path) { void save_sound_config(const std::filesystem::path& path) { nlohmann::json config_json{}; + config_json["main_volume"] = recomp::get_main_volume(); config_json["bgm_volume"] = recomp::get_bgm_volume(); config_json["low_health_beeps"] = recomp::get_low_health_beeps_enabled(); @@ -357,8 +358,8 @@ void load_sound_config(const std::filesystem::path& path) { config_file >> config_json; - recomp::reset_sound_settings(); + call_if_key_exists(recomp::set_main_volume, config_json, "main_volume"); call_if_key_exists(recomp::set_bgm_volume, config_json, "bgm_volume"); call_if_key_exists(recomp::set_low_health_beeps_enabled, config_json, "low_health_beeps"); } diff --git a/src/game/recomp_api.cpp b/src/game/recomp_api.cpp index 84d7000..5563501 100644 --- a/src/game/recomp_api.cpp +++ b/src/game/recomp_api.cpp @@ -78,7 +78,6 @@ extern "C" void recomp_get_targeting_mode(uint8_t* rdram, recomp_context* ctx) { _return(ctx, static_cast(recomp::get_targeting_mode())); } - extern "C" void recomp_get_bgm_volume(uint8_t* rdram, recomp_context* ctx) { _return(ctx, recomp::get_bgm_volume() / 100.0f); } diff --git a/src/main/main.cpp b/src/main/main.cpp index 42b382f..e2a60f5 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -23,6 +23,7 @@ #include "recomp_input.h" #include "recomp_config.h" #include "recomp_game.h" +#include "recomp_sound.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -191,9 +192,10 @@ void queue_samples(int16_t* audio_data, size_t sample_count) { // Convert the audio from 16-bit values to floats and swap the audio channels into the // swap buffer to correct for the address xor caused by endianness handling. + float cur_main_volume = recomp::get_main_volume() / 100.0f; // Get the current main volume, normalized to 0.0-1.0. for (size_t i = 0; i < sample_count; i += input_channels) { - swap_buffer[i + 0 + duplicated_input_frames * input_channels] = audio_data[i + 1] * (0.5f / 32768.0f); - swap_buffer[i + 1 + duplicated_input_frames * input_channels] = audio_data[i + 0] * (0.5f / 32768.0f); + swap_buffer[i + 0 + duplicated_input_frames * input_channels] = audio_data[i + 1] * (0.5f / 32768.0f) * cur_main_volume; + swap_buffer[i + 1 + duplicated_input_frames * input_channels] = audio_data[i + 0] * (0.5f / 32768.0f) * cur_main_volume; } // TODO handle cases where a chunk is smaller than the duplicated frame count. diff --git a/src/ui/ui_config.cpp b/src/ui/ui_config.cpp index 1891fec..a436120 100644 --- a/src/ui/ui_config.cpp +++ b/src/ui/ui_config.cpp @@ -354,10 +354,12 @@ void recomp::set_autosave_mode(recomp::AutosaveMode mode) { } struct SoundOptionsContext { + std::atomic main_volume; // Option to control the volume of all sound std::atomic bgm_volume; std::atomic low_health_beeps_enabled; // RmlUi doesn't seem to like "true"/"false" strings for setting variants so an int is used here instead. void reset() { bgm_volume = 100; + main_volume = 100; low_health_beeps_enabled = (int)true; } SoundOptionsContext() { @@ -374,6 +376,17 @@ void recomp::reset_sound_settings() { } } +void recomp::set_main_volume(int volume) { + sound_options_context.main_volume.store(volume); + if (sound_options_model_handle) { + sound_options_model_handle.DirtyVariable("main_volume"); + } +} + +int recomp::get_main_volume() { + return sound_options_context.main_volume.load(); +} + void recomp::set_bgm_volume(int volume) { sound_options_context.bgm_volume.store(volume); if (sound_options_model_handle) { @@ -852,6 +865,7 @@ public: sound_options_model_handle = constructor.GetModelHandle(); + bind_atomic(constructor, sound_options_model_handle, "main_volume", &sound_options_context.main_volume); bind_atomic(constructor, sound_options_model_handle, "bgm_volume", &sound_options_context.bgm_volume); bind_atomic(constructor, sound_options_model_handle, "low_health_beeps_enabled", &sound_options_context.low_health_beeps_enabled); }