mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2026-03-21 18:41:47 +00:00
Add Enhanced Surround option.
This commit is contained in:
parent
ac123c4cab
commit
177fe6a4e5
8 changed files with 153 additions and 2 deletions
|
|
@ -117,11 +117,40 @@
|
|||
data-checked="audio_mode"
|
||||
value="Surround"
|
||||
id="audio_surround"
|
||||
style="nav-up: #lhb_on"
|
||||
style="nav-up: #lhb_on; nav-down: #enhanced_surround_on"
|
||||
/>
|
||||
<label class="config-option__tab-label" for="audio_surround">Surround</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-option" data-event-mouseover="set_cur_config_index(4)">
|
||||
<label class="config-option__title">Enhanced Surround</label>
|
||||
<div class="config-option__list">
|
||||
<input
|
||||
type="radio"
|
||||
data-event-blur="set_cur_config_index(-1)"
|
||||
data-event-focus="set_cur_config_index(4)"
|
||||
name="enhanced_surround"
|
||||
data-checked="enhanced_surround_enabled"
|
||||
value="1"
|
||||
id="enhanced_surround_on"
|
||||
style="nav-up: #audio_surround"
|
||||
/>
|
||||
<label class="config-option__tab-label" for="enhanced_surround_on">On</label>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
data-event-blur="set_cur_config_index(-1)"
|
||||
data-event-focus="set_cur_config_index(4)"
|
||||
name="enhanced_surround"
|
||||
data-checked="enhanced_surround_enabled"
|
||||
value="0"
|
||||
id="enhanced_surround_off"
|
||||
style="nav-up: #audio_surround"
|
||||
/>
|
||||
<label class="config-option__tab-label" for="enhanced_surround_off">Off</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Descriptions -->
|
||||
<div class="config__wrapper">
|
||||
|
|
@ -137,6 +166,9 @@
|
|||
<p data-if="cur_config_index == 3">
|
||||
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 data-if="cur_config_index == 4">
|
||||
When enabled with Surround mode, adds pan-based rear channel separation. Sounds panned left go to the rear-left speaker, sounds panned right go to the rear-right speaker, creating improved spatial separation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ namespace zelda64 {
|
|||
{zelda64::AudioMode::Surround, "Surround"}
|
||||
});
|
||||
|
||||
// Enhanced surround - adds pan-based rear channel separation
|
||||
bool get_enhanced_surround_enabled();
|
||||
void set_enhanced_surround_enabled(bool enabled);
|
||||
|
||||
AudioMode get_audio_mode();
|
||||
void set_audio_mode(AudioMode mode);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ DECLARE_FUNC(u32, recomp_get_low_health_beeps_enabled);
|
|||
// Audio channel settings: 0 = Stereo, 1 = 5.1 Matrix, 2 = 5.1 Raw
|
||||
DECLARE_FUNC(void, recomp_set_audio_channels, s32 channels);
|
||||
DECLARE_FUNC(s32, recomp_get_audio_channels);
|
||||
DECLARE_FUNC(s32, recomp_get_enhanced_surround_enabled);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -408,3 +408,96 @@ RECOMP_PATCH void Audio_SetFileSelectSettings(s8 audioSetting) {
|
|||
|
||||
SEQCMD_SET_SOUND_MODE(soundMode);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Enhanced Surround Sound - Pan-based RL/RR steering
|
||||
// ============================================================================
|
||||
|
||||
// DMEM address constants for audio synthesis (from synthesis.c)
|
||||
#define DMEM_SURROUND_TEMP 0x4B0
|
||||
#define DMEM_HAAS_TEMP 0x5B0
|
||||
#define DMEM_LEFT_CH 0x930
|
||||
#define DMEM_RIGHT_CH 0xAD0
|
||||
#define DMEM_WET_LEFT_CH 0xC70
|
||||
#define DMEM_WET_RIGHT_CH 0xE10
|
||||
|
||||
// Forward declarations
|
||||
void AudioSynth_DMemMove(Acmd* cmd, s32 dmemIn, s32 dmemOut, size_t size);
|
||||
extern f32 gDefaultPanVolume[];
|
||||
|
||||
// @recomp Patched to add enhanced surround with pan-based RL/RR channel steering
|
||||
// When enhanced surround is enabled, sounds panned left go more to Rear Left,
|
||||
// and sounds panned right go more to Rear Right, creating better spatial separation.
|
||||
RECOMP_PATCH Acmd* AudioSynth_ApplySurroundEffect(Acmd* cmd, NoteSampleState* sampleState, NoteSynthesisState* synthState,
|
||||
s32 numSamplesPerUpdate, s32 haasDmem, s32 flags) {
|
||||
s32 wetGain;
|
||||
u16 dryGain;
|
||||
s64 dmem = DMEM_SURROUND_TEMP;
|
||||
f32 decayGain;
|
||||
|
||||
AudioSynth_DMemMove(cmd++, haasDmem, DMEM_HAAS_TEMP, numSamplesPerUpdate * SAMPLE_SIZE);
|
||||
dryGain = synthState->surroundEffectGain;
|
||||
|
||||
if (flags == A_INIT) {
|
||||
aClearBuffer(cmd++, dmem, sizeof(synthState->synthesisBuffers->surroundEffectState));
|
||||
synthState->surroundEffectGain = 0;
|
||||
} else {
|
||||
aLoadBuffer(cmd++, synthState->synthesisBuffers->surroundEffectState, dmem,
|
||||
sizeof(synthState->synthesisBuffers->surroundEffectState));
|
||||
|
||||
// @recomp Check if enhanced surround is enabled for pan-based RL/RR steering
|
||||
if (recomp_get_enhanced_surround_enabled()) {
|
||||
// === Matrix surround encoding: steer surround to RL or RR based on pan ===
|
||||
// Calculate pan position: 0.0 = full left, 0.5 = center, 1.0 = full right
|
||||
f32 sumVol = sampleState->targetVolLeft + sampleState->targetVolRight;
|
||||
f32 panPosition = 0.5f; // default: center (mono surround)
|
||||
if (sumVol > 0.0f) {
|
||||
panPosition = (f32)sampleState->targetVolRight / sumVol;
|
||||
}
|
||||
|
||||
// The L/R balance determines RL vs RR steering:
|
||||
// - L dominant (leftGain > rightGain): surround goes more to Rear Left
|
||||
// - R dominant (rightGain > leftGain): surround goes more to Rear Right
|
||||
// - Equal: mono surround to both
|
||||
s16 leftGain = (s16)(dryGain * (1.0f - panPosition));
|
||||
s16 rightGain = (s16)(dryGain * panPosition);
|
||||
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, leftGain, dmem, DMEM_LEFT_CH);
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, (rightGain ^ 0xFFFF), dmem, DMEM_RIGHT_CH);
|
||||
|
||||
wetGain = (dryGain * synthState->curReverbVol) >> 7;
|
||||
s16 wetLeftGain = (s16)(wetGain * (1.0f - panPosition));
|
||||
s16 wetRightGain = (s16)(wetGain * panPosition);
|
||||
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, wetLeftGain, dmem, DMEM_WET_LEFT_CH);
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, (wetRightGain ^ 0xFFFF), dmem, DMEM_WET_RIGHT_CH);
|
||||
// === End matrix surround encoding ===
|
||||
} else {
|
||||
// Original behavior: mono surround to both channels
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, dryGain, dmem, DMEM_LEFT_CH);
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, (dryGain ^ 0xFFFF), dmem, DMEM_RIGHT_CH);
|
||||
|
||||
wetGain = (dryGain * synthState->curReverbVol) >> 7;
|
||||
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, wetGain, dmem, DMEM_WET_LEFT_CH);
|
||||
aMix(cmd++, (numSamplesPerUpdate * (s32)SAMPLE_SIZE) >> 4, (wetGain ^ 0xFFFF), dmem, DMEM_WET_RIGHT_CH);
|
||||
}
|
||||
}
|
||||
|
||||
aSaveBuffer(cmd++, DMEM_SURROUND_TEMP + (numSamplesPerUpdate * SAMPLE_SIZE),
|
||||
synthState->synthesisBuffers->surroundEffectState,
|
||||
sizeof(synthState->synthesisBuffers->surroundEffectState));
|
||||
|
||||
decayGain = (sampleState->targetVolLeft + sampleState->targetVolRight) * (1.0f / 0x2000);
|
||||
|
||||
if (decayGain > 1.0f) {
|
||||
decayGain = 1.0f;
|
||||
}
|
||||
|
||||
decayGain = decayGain * gDefaultPanVolume[127 - sampleState->surroundEffectIndex];
|
||||
synthState->surroundEffectGain = ((decayGain * 0x7FFF) + synthState->surroundEffectGain) / 2;
|
||||
|
||||
AudioSynth_DMemMove(cmd++, DMEM_HAAS_TEMP, haasDmem, numSamplesPerUpdate * SAMPLE_SIZE);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,3 +55,4 @@ recomp_get_actor_data = 0x8F0000D0;
|
|||
recomp_get_actor_spawn_index = 0x8F0000D4;
|
||||
recomp_set_audio_channels = 0x8F0000D8;
|
||||
recomp_get_audio_channels = 0x8F0000DC;
|
||||
recomp_get_enhanced_surround_enabled = 0x8F0000E0;
|
||||
|
|
|
|||
|
|
@ -461,6 +461,7 @@ bool save_sound_config(const std::filesystem::path& path) {
|
|||
config_json["bgm_volume"] = zelda64::get_bgm_volume();
|
||||
config_json["low_health_beeps"] = zelda64::get_low_health_beeps_enabled();
|
||||
config_json["audio_mode"] = zelda64::get_audio_mode();
|
||||
config_json["enhanced_surround"] = zelda64::get_enhanced_surround_enabled();
|
||||
|
||||
return save_json_with_backups(path, config_json);
|
||||
}
|
||||
|
|
@ -476,6 +477,7 @@ bool load_sound_config(const std::filesystem::path& path) {
|
|||
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_audio_mode, config_json, "audio_mode");
|
||||
call_if_key_exists(zelda64::set_enhanced_surround_enabled, config_json, "enhanced_surround");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,3 +196,7 @@ extern "C" void recomp_set_audio_channels(uint8_t* rdram, recomp_context* ctx) {
|
|||
extern "C" void recomp_get_audio_channels(uint8_t* rdram, recomp_context* ctx) {
|
||||
_return(ctx, static_cast<s32>(get_audio_channels()));
|
||||
}
|
||||
|
||||
extern "C" void recomp_get_enhanced_surround_enabled(uint8_t* rdram, recomp_context* ctx) {
|
||||
_return(ctx, zelda64::get_enhanced_surround_enabled() ? 1 : 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,11 +366,13 @@ struct SoundOptionsContext {
|
|||
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.
|
||||
zelda64::AudioMode audio_mode; // Audio output mode (Stereo, Mono, Headphones, Surround)
|
||||
std::atomic<int> enhanced_surround_enabled; // Pan-based rear channel separation
|
||||
void reset() {
|
||||
bgm_volume = 100;
|
||||
main_volume = 100;
|
||||
low_health_beeps_enabled = (int)true;
|
||||
audio_mode = zelda64::AudioMode::Stereo;
|
||||
enhanced_surround_enabled = (int)false;
|
||||
}
|
||||
SoundOptionsContext() {
|
||||
reset();
|
||||
|
|
@ -428,7 +430,7 @@ void zelda64::set_audio_mode(zelda64::AudioMode mode) {
|
|||
if (sound_options_model_handle) {
|
||||
sound_options_model_handle.DirtyVariable("audio_mode");
|
||||
}
|
||||
// Update audio backend - only Surround mode uses 5.1 matrix decoding
|
||||
// Update audio backend - Surround mode uses 5.1 matrix decoding
|
||||
set_audio_channels(mode == zelda64::AudioMode::Surround ? audioMatrix51 : audioStereo);
|
||||
}
|
||||
|
||||
|
|
@ -436,6 +438,17 @@ zelda64::AudioMode zelda64::get_audio_mode() {
|
|||
return sound_options_context.audio_mode;
|
||||
}
|
||||
|
||||
void zelda64::set_enhanced_surround_enabled(bool enabled) {
|
||||
sound_options_context.enhanced_surround_enabled.store((int)enabled);
|
||||
if (sound_options_model_handle) {
|
||||
sound_options_model_handle.DirtyVariable("enhanced_surround_enabled");
|
||||
}
|
||||
}
|
||||
|
||||
bool zelda64::get_enhanced_surround_enabled() {
|
||||
return (bool)sound_options_context.enhanced_surround_enabled.load();
|
||||
}
|
||||
|
||||
struct DebugContext {
|
||||
Rml::DataModelHandle model_handle;
|
||||
std::vector<std::string> area_names;
|
||||
|
|
@ -959,6 +972,7 @@ public:
|
|||
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);
|
||||
bind_atomic(constructor, sound_options_model_handle, "enhanced_surround_enabled", &sound_options_context.enhanced_surround_enabled);
|
||||
|
||||
// Custom binding for audio mode that calls the setter to update audio channels
|
||||
constructor.BindFunc("audio_mode",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue