Files
Lorenz Junglas 9d072e6d89 Audio Optimizations (#3847)
- Auto-cleanup idle voice handles: Voice sound handles are now killed when player hasn't been talking for a while
- Audio Occlusion refactor: Moved occlusion calculation to a dedicated SoundOcclusionSystem GameObjectSystem for better organization
  - This now performs really well, so we could look into improving our occlusion calculation: proper damping when sound is transferred via wall, path tracing for occlusion etc. (will open a separate issue)
- Fix mixer early return bug: Fixed issue where mixer could return early, potentially skipping sounds
- Voice Component lipsync toggle: Added option to enable/disable lipsync processing on VoiceComponent
- Cheaper HRTF for voice audio: Disabled expensive bilinear interpolation for voice and certain other sounds in Steam Audio
- Editor MixerDetail perf: Skip frame updates on MixerDetail widget when not visible
- Reduced allocations in audio systems: Optimized away List and LINQ allocations in SoundOcclusionSystem, Listener, and SoundHandle.Source
- MP3 decoder buffer optimization: Improved buffer handling in native CAudioMixerWaveMP3 to reduce overhead

Depending on scenario can reduces audio frame time by up to 30%.
This should also drastically improve performance for games that use VOIP.
2026-01-20 18:48:09 +01:00

84 lines
2.4 KiB
C#

namespace Sandbox.Audio;
/// <summary>
/// A source for the "direct" group of effects. This gets added to the SteamAudio scene and
/// is simulated for things like occlusion.
/// </summary>
class SteamAudioSource : IDisposable
{
private DirectSource _direct;
private BinauralEffect _binauralEffect;
internal SteamAudioSource()
{
_direct = new DirectSource();
_binauralEffect = new BinauralEffect();
}
~SteamAudioSource()
{
Dispose();
}
public void Dispose()
{
GC.SuppressFinalize( this );
_direct?.Dispose();
_direct = default;
_binauralEffect?.Dispose();
_binauralEffect = default;
}
/// <summary>
/// Buffers should be mono in, mono out
/// </summary>
public void ApplyDirectMix( in Listener listener, MultiChannelBuffer input, MultiChannelBuffer output, float occlusionMultiplier, float inputGain )
{
_direct.Apply( listener, input, output, occlusionMultiplier, inputGain );
}
/// <summary>
/// Buffers should be mono in, stereo out
/// </summary>
public void ApplyBinauralMix( Vector3 direction, float spatialBlend, bool useNearestInterpolation, MultiChannelBuffer input, MultiChannelBuffer output )
{
_binauralEffect.Apply( direction, spatialBlend, useNearestInterpolation, input, output );
}
/// <summary>
/// Called by the sound handle at the appropriate times to update the native source
/// </summary>
internal void UpdateFrom( SoundHandle handle, PhysicsWorld world = default, Vector3 listenerPos = default )
{
_direct.ListenLocal = handle.ListenLocal;
_direct.Distance = handle.Distance;
_direct.Falloff = handle.Falloff;
_direct.DistanceAttenuation = handle.DistanceAttenuation;
_direct.AirAbsorption = handle.AirAbsorption;
_direct.Transmission = handle.Transmission;
_direct.Occlusion = handle.Occlusion;
_direct.OcclusionSize = handle.OcclusionRadius;
_direct.Update( handle.Transform, listenerPos, handle.TargetMixer ?? Mixer.Default, world );
}
/// <summary>
/// Time tracking for occlusion updates, managed by SoundOcclusionSystem
/// </summary>
internal RealTimeUntil TimeUntilNextOcclusionCalc
{
get => _direct.TimeUntilNextOcclusionCalc;
set => _direct.TimeUntilNextOcclusionCalc = value;
}
/// <summary>
/// Set the target occlusion value. Called by SoundOcclusionSystem after computing occlusion.
/// </summary>
internal void SetTargetOcclusion( float value )
{
_direct.SetTargetOcclusion( value );
}
}