summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris <f1ana@users.noreply.github.com>2026-09-28 23:27:11 -0400
committerGitHub <noreply@github.com>2026-09-29 03:27:11 +0000
commitb9bcc5e9015908df811401deb528aa5559fae3d9 (patch)
treed8c8cc05fa67c0013ecef0dd6bd70e4b63aa2bd9
parentaa25eb4d5669446efd56e16497c186d69d646b71 (diff)
Fix audio thread race on CVar reads during preset apply (#7265)
-rw-r--r--soh/soh/Enhancements/audio/AudioSettings.cpp34
-rw-r--r--soh/soh/Enhancements/audio/AudioSettings.h17
-rw-r--r--soh/src/code/audio_playback.c5
-rw-r--r--soh/src/code/audio_synthesis.c3
4 files changed, 56 insertions, 3 deletions
diff --git a/soh/soh/Enhancements/audio/AudioSettings.cpp b/soh/soh/Enhancements/audio/AudioSettings.cpp
new file mode 100644
index 000000000..f351f3648
--- /dev/null
+++ b/soh/soh/Enhancements/audio/AudioSettings.cpp
@@ -0,0 +1,34 @@
+#include "AudioSettings.h"
+
+#include <atomic>
+
+#include <libultraship/bridge/consolevariablebridge.h>
+
+#include "soh/cvar_prefixes.h"
+#include "soh/ShipInit.hpp"
+
+static std::atomic<float> sMasterVolume{ 40.0f / 100.0f };
+static std::atomic<int32_t> sOctaveDrop{ 0 };
+static std::atomic<int32_t> sMirroredWorld{ 0 };
+
+float AudioSettings_GetMasterVolume(void) {
+ return sMasterVolume.load(std::memory_order_relaxed);
+}
+
+int32_t AudioSettings_GetOctaveDrop(void) {
+ return sOctaveDrop.load(std::memory_order_relaxed);
+}
+
+int32_t AudioSettings_GetMirroredWorld(void) {
+ return sMirroredWorld.load(std::memory_order_relaxed);
+}
+
+static void RefreshAudioSettings() {
+ sMasterVolume.store((float)CVarGetInteger(CVAR_SETTING("Volume.Master"), 40) / 100.0f, std::memory_order_relaxed);
+ sOctaveDrop.store(CVarGetInteger(CVAR_AUDIO("ExperimentalOctaveDrop"), 0), std::memory_order_relaxed);
+ sMirroredWorld.store(CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0), std::memory_order_relaxed);
+}
+
+static RegisterShipInitFunc initAudioSettings(RefreshAudioSettings,
+ { CVAR_SETTING("Volume.Master"), CVAR_AUDIO("ExperimentalOctaveDrop"),
+ CVAR_ENHANCEMENT("MirroredWorld") });
diff --git a/soh/soh/Enhancements/audio/AudioSettings.h b/soh/soh/Enhancements/audio/AudioSettings.h
new file mode 100644
index 000000000..7e2d99e14
--- /dev/null
+++ b/soh/soh/Enhancements/audio/AudioSettings.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// cvars used by the audio thread should go here
+// direct use can result in a race condition with the main thread
+float AudioSettings_GetMasterVolume(void);
+int32_t AudioSettings_GetOctaveDrop(void);
+int32_t AudioSettings_GetMirroredWorld(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/soh/src/code/audio_playback.c b/soh/src/code/audio_playback.c
index ba250252c..cffe35e1c 100644
--- a/soh/src/code/audio_playback.c
+++ b/soh/src/code/audio_playback.c
@@ -1,5 +1,6 @@
#include "global.h"
#include "soh/ResourceManagerHelpers.h"
+#include "soh/Enhancements/audio/AudioSettings.h"
extern bool gUseLegacySD;
@@ -94,7 +95,7 @@ void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) {
vel = 0.0f > vel ? 0.0f : vel;
vel = 1.0f < vel ? 1.0f : vel;
- float master_vol = (float)CVarGetInteger(CVAR_SETTING("Volume.Master"), 40) / 100.0f;
+ float master_vol = AudioSettings_GetMasterVolume();
sub->targetVolLeft = (s32)((vel * volLeft) * (0x1000 - 0.001f)) * master_vol;
sub->targetVolRight = (s32)((vel * volRight) * (0x1000 - 0.001f)) * master_vol;
@@ -120,7 +121,7 @@ void Audio_NoteSetResamplingRate(NoteSubEu* noteSubEu, f32 resamplingRateInput)
} else {
noteSubEu->bitField1.hasTwoParts = true;
if (3.99996f < resamplingRateInput) {
- if (CVarGetInteger(CVAR_AUDIO("ExperimentalOctaveDrop"), 0) || noteSubEu->bitField1.isSyntheticWave) {
+ if (AudioSettings_GetOctaveDrop() || noteSubEu->bitField1.isSyntheticWave) {
resamplingRate = resamplingRateInput * 0.5f;
while (resamplingRate > 1.99998f) {
diff --git a/soh/src/code/audio_synthesis.c b/soh/src/code/audio_synthesis.c
index 7b2db2267..4fed4e939 100644
--- a/soh/src/code/audio_synthesis.c
+++ b/soh/src/code/audio_synthesis.c
@@ -1,6 +1,7 @@
#include <libultraship/libultra.h>
#include "global.h"
#include "soh/mixer.h"
+#include "soh/Enhancements/audio/AudioSettings.h"
#define DEFAULT_LEN_1CH 0x1A0
#define DEFAULT_LEN_2CH 0x340
@@ -654,7 +655,7 @@ Acmd* AudioSynth_DoOneAudioUpdate(s16* aiBuf, s32 aiBufLen, Acmd* cmd, s32 updat
}
updateIndex = aiBufLen * 2;
- if (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0)) {
+ if (AudioSettings_GetMirroredWorld()) {
aInterleave(cmd++, DMEM_TEMP, DMEM_RIGHT_CH, DMEM_LEFT_CH, updateIndex);
} else {
aInterleave(cmd++, DMEM_TEMP, DMEM_LEFT_CH, DMEM_RIGHT_CH, updateIndex);