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
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.
///