update audio options to select among 4 opts.

This commit is contained in:
Tortuga Veloz 2026-02-10 09:46:09 +01:00
parent 98da5553ff
commit ac123c4cab
8 changed files with 90 additions and 46 deletions

View file

@ -71,31 +71,55 @@
</div> </div>
<div class="config-option" data-event-mouseover="set_cur_config_index(3)"> <div class="config-option" data-event-mouseover="set_cur_config_index(3)">
<label class="config-option__title">Surround Sound (5.1)</label> <label class="config-option__title">Audio Mode</label>
<div class="config-option__list"> <div class="config-option__list">
<input <input
type="radio" type="radio"
data-event-blur="set_cur_config_index(-1)" data-event-blur="set_cur_config_index(-1)"
data-event-focus="set_cur_config_index(3)" data-event-focus="set_cur_config_index(3)"
name="surround" name="audio_mode"
data-checked="surround_sound_enabled" data-checked="audio_mode"
value="1" value="Stereo"
id="surround_on" id="audio_stereo"
style="nav-up: #lhb_on" style="nav-up: #lhb_on"
/> />
<label class="config-option__tab-label" for="surround_on">On</label> <label class="config-option__tab-label" for="audio_stereo">Stereo</label>
<input <input
type="radio" type="radio"
data-event-blur="set_cur_config_index(-1)" data-event-blur="set_cur_config_index(-1)"
data-event-focus="set_cur_config_index(3)" data-event-focus="set_cur_config_index(3)"
name="surround" name="audio_mode"
data-checked="surround_sound_enabled" data-checked="audio_mode"
value="0" value="Mono"
id="surround_off" id="audio_mono"
style="nav-up: #lhb_on" style="nav-up: #lhb_on"
/> />
<label class="config-option__tab-label" for="surround_off">Off</label> <label class="config-option__tab-label" for="audio_mono">Mono</label>
<input
type="radio"
data-event-blur="set_cur_config_index(-1)"
data-event-focus="set_cur_config_index(3)"
name="audio_mode"
data-checked="audio_mode"
value="Headphones"
id="audio_headphones"
style="nav-up: #lhb_on"
/>
<label class="config-option__tab-label" for="audio_headphones">Headphones</label>
<input
type="radio"
data-event-blur="set_cur_config_index(-1)"
data-event-focus="set_cur_config_index(3)"
name="audio_mode"
data-checked="audio_mode"
value="Surround"
id="audio_surround"
style="nav-up: #lhb_on"
/>
<label class="config-option__tab-label" for="audio_surround">Surround</label>
</div> </div>
</div> </div>
</div> </div>
@ -111,7 +135,7 @@
Toggles whether or not the low-health beeping sound plays. Toggles whether or not the low-health beeping sound plays.
</p> </p>
<p data-if="cur_config_index == 3"> <p data-if="cur_config_index == 3">
Enables 5.1 surround sound output using matrix decoding. Requires a surround sound system or virtual surround headphones. Sets the audio output mode. <b>Stereo</b> outputs standard stereo audio. <b>Mono</b> outputs mono audio. <b>Headphones</b> optimizes audio for headphone listening. <b>Surround</b> enables 5.1 surround sound output using matrix decoding.
</p> </p>
</div> </div>
</div> </div>

View file

@ -87,6 +87,25 @@ namespace zelda64 {
AnalogCamMode get_analog_cam_mode(); AnalogCamMode get_analog_cam_mode();
void set_analog_cam_mode(AnalogCamMode mode); void set_analog_cam_mode(AnalogCamMode mode);
// Audio mode setting - mirrors the game's AudioOption enum
enum class AudioMode {
Stereo,
Mono,
Headphones,
Surround,
OptionCount
};
NLOHMANN_JSON_SERIALIZE_ENUM(zelda64::AudioMode, {
{zelda64::AudioMode::Stereo, "Stereo"},
{zelda64::AudioMode::Mono, "Mono"},
{zelda64::AudioMode::Headphones, "Headphones"},
{zelda64::AudioMode::Surround, "Surround"}
});
AudioMode get_audio_mode();
void set_audio_mode(AudioMode mode);
void open_quit_game_prompt(); void open_quit_game_prompt();
}; };

View file

@ -1,6 +1,8 @@
#ifndef __ZELDA_SOUND_H__ #ifndef __ZELDA_SOUND_H__
#define __ZELDA_SOUND_H__ #define __ZELDA_SOUND_H__
#include "zelda_config.h"
namespace zelda64 { namespace zelda64 {
void reset_sound_settings(); void reset_sound_settings();
void set_main_volume(int volume); void set_main_volume(int volume);
@ -9,8 +11,8 @@ namespace zelda64 {
int get_bgm_volume(); int get_bgm_volume();
void set_low_health_beeps_enabled(bool enabled); void set_low_health_beeps_enabled(bool enabled);
bool get_low_health_beeps_enabled(); bool get_low_health_beeps_enabled();
void set_surround_sound_enabled(bool enabled); AudioMode get_audio_mode();
bool get_surround_sound_enabled(); void set_audio_mode(AudioMode mode);
} }
#endif #endif

View file

@ -369,9 +369,7 @@ RECOMP_PATCH void LifeMeter_UpdateSizeAndBeep(PlayState* play) {
} }
extern s8 sSoundMode; extern s8 sSoundMode;
// @recomp Surround sound output is now controlled by the recomp's config menu // @recomp Patched to sync audio channels with the game's audio setting
// (Sound -> Surround Sound 5.1), not by the in-game audio setting.
// This function still controls the game's internal sound processing mode.
RECOMP_PATCH void Audio_SetFileSelectSettings(s8 audioSetting) { RECOMP_PATCH void Audio_SetFileSelectSettings(s8 audioSetting) {
s8 soundMode; s8 soundMode;
@ -379,23 +377,29 @@ RECOMP_PATCH void Audio_SetFileSelectSettings(s8 audioSetting) {
case SAVE_AUDIO_STEREO: case SAVE_AUDIO_STEREO:
soundMode = SOUNDMODE_STEREO; soundMode = SOUNDMODE_STEREO;
sSoundMode = SOUNDMODE_STEREO; sSoundMode = SOUNDMODE_STEREO;
// @recomp Sync audio output to stereo
recomp_set_audio_channels(AUDIO_CHANNELS_STEREO);
break; break;
case SAVE_AUDIO_MONO: case SAVE_AUDIO_MONO:
soundMode = SOUNDMODE_MONO; soundMode = SOUNDMODE_MONO;
sSoundMode = SOUNDMODE_MONO; sSoundMode = SOUNDMODE_MONO;
// @recomp Sync audio output to stereo (mono is handled by the game's audio engine)
recomp_set_audio_channels(AUDIO_CHANNELS_STEREO);
break; break;
case SAVE_AUDIO_HEADSET: case SAVE_AUDIO_HEADSET:
soundMode = SOUNDMODE_HEADSET; soundMode = SOUNDMODE_HEADSET;
sSoundMode = SOUNDMODE_HEADSET; sSoundMode = SOUNDMODE_HEADSET;
// @recomp Sync audio output to stereo (headset mode is handled by the game's audio engine)
recomp_set_audio_channels(AUDIO_CHANNELS_STEREO);
break; break;
case SAVE_AUDIO_SURROUND: case SAVE_AUDIO_SURROUND:
soundMode = SOUNDMODE_SURROUND; soundMode = SOUNDMODE_SURROUND;
// @recomp Use external surround mode - the actual 5.1 output is handled
// by the matrix decoder when enabled in the recomp's config menu
sSoundMode = SOUNDMODE_SURROUND_EXTERNAL; sSoundMode = SOUNDMODE_SURROUND_EXTERNAL;
// @recomp Enable 5.1 matrix surround output when game's surround option is selected
recomp_set_audio_channels(AUDIO_CHANNELS_MATRIX_51);
break; break;
default: default:

View file

@ -460,7 +460,7 @@ bool save_sound_config(const std::filesystem::path& path) {
config_json["main_volume"] = zelda64::get_main_volume(); config_json["main_volume"] = zelda64::get_main_volume();
config_json["bgm_volume"] = zelda64::get_bgm_volume(); config_json["bgm_volume"] = zelda64::get_bgm_volume();
config_json["low_health_beeps"] = zelda64::get_low_health_beeps_enabled(); config_json["low_health_beeps"] = zelda64::get_low_health_beeps_enabled();
config_json["surround_sound"] = zelda64::get_surround_sound_enabled(); config_json["audio_mode"] = zelda64::get_audio_mode();
return save_json_with_backups(path, config_json); return save_json_with_backups(path, config_json);
} }
@ -475,7 +475,7 @@ bool load_sound_config(const std::filesystem::path& path) {
call_if_key_exists(zelda64::set_main_volume, config_json, "main_volume"); call_if_key_exists(zelda64::set_main_volume, config_json, "main_volume");
call_if_key_exists(zelda64::set_bgm_volume, config_json, "bgm_volume"); call_if_key_exists(zelda64::set_bgm_volume, config_json, "bgm_volume");
call_if_key_exists(zelda64::set_low_health_beeps_enabled, config_json, "low_health_beeps"); call_if_key_exists(zelda64::set_low_health_beeps_enabled, config_json, "low_health_beeps");
call_if_key_exists(zelda64::set_surround_sound_enabled, config_json, "surround_sound"); call_if_key_exists(zelda64::set_audio_mode, config_json, "audio_mode");
return true; return true;
} }

View file

@ -183,11 +183,11 @@ extern "C" void recomp_set_right_analog_suppressed(uint8_t* rdram, recomp_contex
recomp::set_right_analog_suppressed(suppressed); recomp::set_right_analog_suppressed(suppressed);
} }
// Surround sound support // Surround sound support - called by the game when audio settings change
extern "C" void recomp_set_audio_channels(uint8_t* rdram, recomp_context* ctx) { extern "C" void recomp_set_audio_channels(uint8_t* rdram, recomp_context* ctx) {
s32 channels = _arg<0, s32>(rdram, ctx); s32 channels = _arg<0, s32>(rdram, ctx);
// Validate input // Validate input and update the audio backend
if (channels >= 0 && channels < audioMax) { if (channels >= 0 && channels < audioMax) {
set_audio_channels(static_cast<AudioChannelsSetting>(channels)); set_audio_channels(static_cast<AudioChannelsSetting>(channels));
} }

View file

@ -257,12 +257,6 @@ void queue_samples(int16_t* audio_data, size_t sample_count) {
// Handle surround sound matrix decoding // Handle surround sound matrix decoding
if (audio_channel_setting == audioMatrix51 && sound_matrix_decoder) { if (audio_channel_setting == audioMatrix51 && sound_matrix_decoder) {
static int surround_frame_count = 0;
if (surround_frame_count < 5) {
printf("Audio: Processing surround frame %d: %zu stereo frames, offset=%u, resampled=%zu\n",
++surround_frame_count, frames_after_discard,
input_channels * discarded_output_frames / 2, resampled_stereo_frames);
}
// Process stereo through the matrix decoder to get 5.1 surround // Process stereo through the matrix decoder to get 5.1 surround
auto [surround_samples, surround_sample_count] = sound_matrix_decoder->Process(stereo_samples, frames_after_discard); auto [surround_samples, surround_sample_count] = sound_matrix_decoder->Process(stereo_samples, frames_after_discard);

View file

@ -365,12 +365,12 @@ struct SoundOptionsContext {
std::atomic<int> main_volume; // Option to control the volume of all sound std::atomic<int> main_volume; // Option to control the volume of all sound
std::atomic<int> bgm_volume; std::atomic<int> bgm_volume;
std::atomic<int> low_health_beeps_enabled; // RmlUi doesn't seem to like "true"/"false" strings for setting variants so an int is used here instead. std::atomic<int> low_health_beeps_enabled; // RmlUi doesn't seem to like "true"/"false" strings for setting variants so an int is used here instead.
std::atomic<int> surround_sound_enabled; // Enable 5.1 surround sound matrix decoding zelda64::AudioMode audio_mode; // Audio output mode (Stereo, Mono, Headphones, Surround)
void reset() { void reset() {
bgm_volume = 100; bgm_volume = 100;
main_volume = 100; main_volume = 100;
low_health_beeps_enabled = (int)true; low_health_beeps_enabled = (int)true;
surround_sound_enabled = (int)false; audio_mode = zelda64::AudioMode::Stereo;
} }
SoundOptionsContext() { SoundOptionsContext() {
reset(); reset();
@ -422,18 +422,18 @@ bool zelda64::get_low_health_beeps_enabled() {
// Forward declaration from main.cpp // Forward declaration from main.cpp
void set_audio_channels(AudioChannelsSetting channels); void set_audio_channels(AudioChannelsSetting channels);
void zelda64::set_surround_sound_enabled(bool enabled) { void zelda64::set_audio_mode(zelda64::AudioMode mode) {
printf("UI: Setting surround sound to %s\n", enabled ? "enabled" : "disabled"); printf("UI: Setting audio mode to %d\n", (int)mode);
sound_options_context.surround_sound_enabled.store((int)enabled); sound_options_context.audio_mode = mode;
if (sound_options_model_handle) { if (sound_options_model_handle) {
sound_options_model_handle.DirtyVariable("surround_sound_enabled"); sound_options_model_handle.DirtyVariable("audio_mode");
} }
// Update audio backend // Update audio backend - only Surround mode uses 5.1 matrix decoding
set_audio_channels(enabled ? audioMatrix51 : audioStereo); set_audio_channels(mode == zelda64::AudioMode::Surround ? audioMatrix51 : audioStereo);
} }
bool zelda64::get_surround_sound_enabled() { zelda64::AudioMode zelda64::get_audio_mode() {
return (bool)sound_options_context.surround_sound_enabled.load(); return sound_options_context.audio_mode;
} }
struct DebugContext { struct DebugContext {
@ -960,14 +960,15 @@ public:
bind_atomic(constructor, sound_options_model_handle, "bgm_volume", &sound_options_context.bgm_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); bind_atomic(constructor, sound_options_model_handle, "low_health_beeps_enabled", &sound_options_context.low_health_beeps_enabled);
// Custom binding for surround sound that calls the setter to update audio channels // Custom binding for audio mode that calls the setter to update audio channels
constructor.BindFunc("surround_sound_enabled", constructor.BindFunc("audio_mode",
[](Rml::Variant& out) { [](Rml::Variant& out) { get_option(sound_options_context.audio_mode, out); },
out = sound_options_context.surround_sound_enabled.load();
},
[](const Rml::Variant& in) { [](const Rml::Variant& in) {
bool enabled = in.Get<int>() != 0; zelda64::AudioMode mode = zelda64::AudioMode::OptionCount;
zelda64::set_surround_sound_enabled(enabled); from_json(in.Get<std::string>(), mode);
if (mode != zelda64::AudioMode::OptionCount) {
zelda64::set_audio_mode(mode);
}
} }
); );
} }