From 7aa94e952eabf8ecacdb5df3227126babd803353 Mon Sep 17 00:00:00 2001 From: Adam Coulter Date: Mon, 27 Jul 2026 23:17:47 +1000 Subject: [PATCH 1/5] [audio] Load the OpenAL implementation macOS actually ships Every platform other than Windows asked for "libopenal.so", which is the Linux spelling, so the OpenAL mixer never loaded on macOS and the game silently fell back to the system one - losing 3D audio with it. Apple ships OpenAL as a framework, and the loader resolves it only by full path; neither the bare library name nor a relative framework path is found. Ask for it by path, and leave the custom library setting for anyone who has a newer implementation installed. Co-Authored-By: Claude Opus 4.8 --- src/bstone/src/bstone_oal_audio_mixer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bstone/src/bstone_oal_audio_mixer.cpp b/src/bstone/src/bstone_oal_audio_mixer.cpp index 52bea64a..e01b0d91 100644 --- a/src/bstone/src/bstone_oal_audio_mixer.cpp +++ b/src/bstone/src/bstone_oal_audio_mixer.cpp @@ -1004,6 +1004,12 @@ const char* OalAudioMixer::get_oal_default_library_file_name() return #if _WIN32 "OpenAL32.dll" +#elif defined(__APPLE__) + // Apple ships OpenAL as a framework, and the loader only finds it by its + // full path: neither the bare library name nor a relative framework path + // resolves. Someone with a newer implementation installed can still point + // at it with the custom library setting. + "/System/Library/Frameworks/OpenAL.framework/OpenAL" #else "libopenal.so" #endif // _WIN32 From 6dda2016287eb92f43b051d453fe6db9225cc36a Mon Sep 17 00:00:00 2001 From: Adam Coulter Date: Tue, 28 Jul 2026 01:10:26 +1000 Subject: [PATCH 2/5] [audio] Keep auto-detection off Apple's silent OpenAL Apple's OpenAL framework (deprecated since macOS 10.15) initializes cleanly, accepts buffers, and reports every source as playing, yet renders silence for some of them on modern macOS. The same mixer code renders those sounds correctly through openal-soft, verified by capturing its wave-backend output, so the framework itself is at fault and a successful OpenAL start-up proves nothing on this platform. Auto-detection on macOS therefore goes straight to the system mixer. OpenAL remains available by explicit choice. Co-Authored-By: Claude Opus 5 --- src/bstone/src/id_sd.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bstone/src/id_sd.cpp b/src/bstone/src/id_sd.cpp index 1df5e3a0..1843d8f0 100644 --- a/src/bstone/src/id_sd.cpp +++ b/src/bstone/src/id_sd.cpp @@ -492,8 +492,18 @@ void sd_startup() if (user_driver_type == AudioDriverType::auto_detect) { +#if defined(__APPLE__) + // Apple's OpenAL framework initializes cleanly and reports every + // source as playing, yet renders silence for some of them on modern + // macOS, so a successful OpenAL start-up proves nothing here and + // auto-detection goes straight to the system mixer. OpenAL remains + // available by explicit choice, which prefers openal-soft when that + // is installed. + driver_types.emplace_back(AudioDriverType::system); +#else driver_types.emplace_back(AudioDriverType::openal); driver_types.emplace_back(AudioDriverType::system); +#endif } else { From 0318917b9333b58ae232b55fbf544825ae2986b6 Mon Sep 17 00:00:00 2001 From: Adam Coulter Date: Tue, 28 Jul 2026 01:10:26 +1000 Subject: [PATCH 3/5] [audio] Prefer openal-soft when choosing the OpenAL library An explicitly requested OpenAL driver on macOS now tries the Homebrew openal-soft locations before falling back to Apple's deprecated framework, and the log records which library actually got used. Co-Authored-By: Claude Opus 5 --- src/bstone/src/bstone_oal_audio_mixer.cpp | 30 +++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/bstone/src/bstone_oal_audio_mixer.cpp b/src/bstone/src/bstone_oal_audio_mixer.cpp index e01b0d91..35fe752a 100644 --- a/src/bstone/src/bstone_oal_audio_mixer.cpp +++ b/src/bstone/src/bstone_oal_audio_mixer.cpp @@ -1029,10 +1029,36 @@ void OalAudioMixer::initialize_oal(const AudioMixerInitParam& param) std::string oal_library_string{}; const std::string_view oal_library = sd_get_oal_library(); if (oal_library.empty()) - oal_library_string = get_oal_default_library_file_name(); + { +#if defined(__APPLE__) + // Apple's own framework is deprecated and renders silence for some + // sources on modern macOS, so an installed openal-soft gets first + // refusal before falling back to it. + static constexpr const char* candidate_library_file_names[] = { + "/opt/homebrew/opt/openal-soft/lib/libopenal.dylib", // Homebrew, Apple Silicon. + "/usr/local/opt/openal-soft/lib/libopenal.dylib", // Homebrew, Intel. + }; + for (const char* candidate_library_file_name : candidate_library_file_names) + { + try + { + oal_loader_ = make_oal_loader(candidate_library_file_name); + oal_library_string = candidate_library_file_name; + break; + } + catch (...) + { + } + } +#endif // __APPLE__ + if (oal_loader_ == nullptr) + oal_library_string = get_oal_default_library_file_name(); + } else oal_library_string.append(oal_library.data(), oal_library.size()); - oal_loader_ = make_oal_loader(oal_library_string.c_str()); + if (oal_loader_ == nullptr) + oal_loader_ = make_oal_loader(oal_library_string.c_str()); + log(std::string{"Using library: \""} + oal_library_string + '\"'); oal_loader_->load_alc_symbols(); detect_alc_extensions(); log_oal_devices(); From 9547de9c8315d807b484c8c4323b94170794b012 Mon Sep 17 00:00:00 2001 From: Adam Coulter Date: Fri, 31 Jul 2026 23:37:52 +1000 Subject: [PATCH 4/5] [audio] Brace single-statement bodies Co-Authored-By: Claude Opus 5 --- src/bstone/src/bstone_oal_audio_mixer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bstone/src/bstone_oal_audio_mixer.cpp b/src/bstone/src/bstone_oal_audio_mixer.cpp index 35fe752a..7de58993 100644 --- a/src/bstone/src/bstone_oal_audio_mixer.cpp +++ b/src/bstone/src/bstone_oal_audio_mixer.cpp @@ -1052,12 +1052,16 @@ void OalAudioMixer::initialize_oal(const AudioMixerInitParam& param) } #endif // __APPLE__ if (oal_loader_ == nullptr) + { oal_library_string = get_oal_default_library_file_name(); + } } else oal_library_string.append(oal_library.data(), oal_library.size()); if (oal_loader_ == nullptr) + { oal_loader_ = make_oal_loader(oal_library_string.c_str()); + } log(std::string{"Using library: \""} + oal_library_string + '\"'); oal_loader_->load_alc_symbols(); detect_alc_extensions(); From dcefff087d61d88c3e0e39ae9ce98674d2dc3c5c Mon Sep 17 00:00:00 2001 From: Adam Coulter Date: Tue, 4 Aug 2026 14:05:09 +1000 Subject: [PATCH 5/5] [audio] Brace the other half of the statement The one branch was braced and the other was not, in a statement this change had already rewritten. Co-Authored-By: Claude Opus 5 --- src/bstone/src/bstone_oal_audio_mixer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bstone/src/bstone_oal_audio_mixer.cpp b/src/bstone/src/bstone_oal_audio_mixer.cpp index 7de58993..49a59a9d 100644 --- a/src/bstone/src/bstone_oal_audio_mixer.cpp +++ b/src/bstone/src/bstone_oal_audio_mixer.cpp @@ -1057,7 +1057,9 @@ void OalAudioMixer::initialize_oal(const AudioMixerInitParam& param) } } else + { oal_library_string.append(oal_library.data(), oal_library.size()); + } if (oal_loader_ == nullptr) { oal_loader_ = make_oal_loader(oal_library_string.c_str());