From 978e546fa4d5d4c2e8bbfd336e92d6977fb63153 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Mon, 22 Jun 2026 23:02:29 +1000 Subject: [PATCH 1/2] Expose OpenAL doppler factor Title. --- Robust.Client/Audio/AudioManager.Public.cs | 30 ++++++++++--- Robust.Client/Audio/AudioManager.cs | 1 + Robust.Client/Audio/HeadlessAudioManager.cs | 47 ++++++++++++++++++++- Robust.Client/Audio/IAudioManager.cs | 10 +++++ Robust.Shared/CVars.cs | 6 +++ 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/Robust.Client/Audio/AudioManager.Public.cs b/Robust.Client/Audio/AudioManager.Public.cs index 095c12acd..682286ed8 100644 --- a/Robust.Client/Audio/AudioManager.Public.cs +++ b/Robust.Client/Audio/AudioManager.Public.cs @@ -2,7 +2,9 @@ using System.IO; using System.Numerics; using System.Threading; +using JetBrains.Annotations; using OpenTK.Audio.OpenAL; +using Robust.Shared; using Robust.Client.Audio.Sources; using Robust.Client.Graphics; using Robust.Shared.Audio; @@ -16,6 +18,12 @@ internal partial class AudioManager { private float _zOffset; + /// + public float MasterGain { get; private set; } + + /// + public float DopplerFactor { get; private set; } = 1f; + public void SetZOffset(float offset) { _zOffset = offset; @@ -229,13 +237,11 @@ public AudioStream LoadAudioRaw(ReadOnlySpan samples, int channels, int s public void SetMasterGain(float newGain) { - if (newGain < 0f) - { - OpenALSawmill.Error("Tried to set master gain below 0, clamping to 0"); - AL.Listener(ALListenerf.Gain, 0f); - return; - } + if (!float.IsFinite(newGain)) + newGain = 0f; + newGain = MathF.Max(newGain, 0f); + MasterGain = newGain; #region Platform hack for MacOS // HACK/BUG: Apple's OpenAL implementation has a bug where values of 0f for listener gain don't actually @@ -251,6 +257,18 @@ public void SetMasterGain(float newGain) AL.Listener(ALListenerf.Gain, newGain); } + private void SetDopplerFactor(float value) + { + if (!float.IsFinite(value)) + value = 0f; + + value = MathF.Max(value, 0f); + + DopplerFactor = value; + AL.DopplerFactor(value); + _checkAlError(); + } + public void SetAttenuation(Attenuation attenuation) { switch (attenuation) diff --git a/Robust.Client/Audio/AudioManager.cs b/Robust.Client/Audio/AudioManager.cs index 63fc5fdc0..aa8ed2172 100644 --- a/Robust.Client/Audio/AudioManager.cs +++ b/Robust.Client/Audio/AudioManager.cs @@ -143,6 +143,7 @@ private void InitializeAudio() IsEfxSupported = HasAlDeviceExtension("ALC_EXT_EFX"); _cfg.OnValueChanged(CVars.AudioMasterVolume, SetMasterGain, true); + _cfg.OnValueChanged(CVars.AudioDopplerFactor, SetDopplerFactor, true); _reload.Register("/Audio", "*.ogg"); _reload.Register("/Audio", "*.wav"); diff --git a/Robust.Client/Audio/HeadlessAudioManager.cs b/Robust.Client/Audio/HeadlessAudioManager.cs index 46c2cc8e4..0694f0f2c 100644 --- a/Robust.Client/Audio/HeadlessAudioManager.cs +++ b/Robust.Client/Audio/HeadlessAudioManager.cs @@ -1,8 +1,11 @@ using System; using System.IO; using System.Numerics; +using Robust.Shared; using Robust.Shared.Audio; using Robust.Shared.Audio.AudioLoading; +using Robust.Shared.Configuration; +using Robust.Shared.IoC; using Robust.Shared.Audio.Sources; using Robust.Shared.Maths; @@ -11,13 +14,51 @@ namespace Robust.Client.Audio; /// /// Headless client audio. /// -internal sealed class HeadlessAudioManager : IAudioInternal +internal sealed partial class HeadlessAudioManager : IAudioInternal { + [Dependency] private IConfigurationManager _cfg = default!; + private int _audioBuffer; + private float _masterGain; + private float _dopplerFactor = 1f; + + /// + public float MasterGain => _masterGain; + + /// + public float DopplerFactor + { + get => _dopplerFactor; + set => SetDopplerFactor(value, true); + } /// public void InitializePostWindowing() { + _cfg.OnValueChanged(CVars.AudioDopplerFactor, SetDopplerFactorFromCVar, true); + } + + private void SetDopplerFactorFromCVar(float value) + { + SetDopplerFactor(value, false); + } + + private void SetDopplerFactor(float value, bool updateCVar) + { + var original = _dopplerFactor; + + if (!float.IsFinite(value)) + value = 0f; + + value = MathF.Max(value, 0f); + + if (MathHelper.CloseTo(original, value)) + return; + + if (updateCVar) + _cfg.SetCVar(CVars.AudioDopplerFactor, value, true); + + _dopplerFactor = value; } /// @@ -60,6 +101,10 @@ public void SetRotation(Angle angle) /// public void SetMasterGain(float newGain) { + if (!float.IsFinite(newGain)) + newGain = 0f; + + _masterGain = MathF.Max(newGain, 0f); } /// diff --git a/Robust.Client/Audio/IAudioManager.cs b/Robust.Client/Audio/IAudioManager.cs index ce65d1d0c..99d1aa00d 100644 --- a/Robust.Client/Audio/IAudioManager.cs +++ b/Robust.Client/Audio/IAudioManager.cs @@ -10,6 +10,16 @@ namespace Robust.Client.Audio; [NotContentImplementable] public interface IAudioManager { + /// + /// OpenAL master gain for audio. + /// + float MasterGain { get; } + + /// + /// OpenAL Doppler factor for audio. + /// + float DopplerFactor { get; } + IAudioSource? CreateAudioSource(AudioStream stream); AudioStream LoadAudioOggVorbis(Stream stream, string? name = null); diff --git a/Robust.Shared/CVars.cs b/Robust.Shared/CVars.cs index b1eaac8f2..b3ee85bcc 100644 --- a/Robust.Shared/CVars.cs +++ b/Robust.Shared/CVars.cs @@ -1300,6 +1300,12 @@ protected CVars() public static readonly CVarDef AudioMasterVolume = CVarDef.Create("audio.mastervolume", 0.50f, CVar.ARCHIVE | CVar.CLIENTONLY); + /// + /// OpenAL doppler factor for positional audio. + /// + public static readonly CVarDef AudioDopplerFactor = + CVarDef.Create("audio.doppler_factor", 1f, CVar.SERVER | CVar.REPLICATED); + /// /// Maximum raycast distance for audio occlusion. /// From b3f25a5e2f7b92620378f4939cedf5bdc716a21c Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Mon, 22 Jun 2026 23:04:28 +1000 Subject: [PATCH 2/2] Doppler --- RELEASE-NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index c6a5fa90c..0c2397c9f 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -39,7 +39,7 @@ END TEMPLATE--> ### New features -*None yet* +* Added doppler factor as a CVar. ### Bugfixes