Vehicle/VehicleController.Audio.cs
using Sandbox;

namespace Bugges.VehicleController;

partial class VehicleController : Component
{
	private const string AUDIO = "Audio";

	[Order( 0 )]
	[Property, FeatureEnabled( AUDIO )]
	private bool IsAudioEnabled { get; set; } = false;

	[Property( Title = "Engine Start" ), Feature( AUDIO )]
	private SoundPointComponent Audio_EngineStart { get; set; }

	[Property( Title = "Engine Stop" ), Feature( AUDIO )]
	private SoundPointComponent Audio_EngineStop { get; set; }

	[Property( Title = "Engine Idle" ), Feature( AUDIO )]
	private SoundPointComponent Audio_EngineIdle { get; set; }

	[Property( Title = "Engine Low RPM" ), Feature( AUDIO )]
	private SoundPointComponent Audio_EngineLowRPM { get; set; }

	[Property( Title = "Engine Hight RPM" ), Feature( AUDIO )]
	private SoundPointComponent Audio_EngineHighRPM { get; set; }

	[Property( Title = "Gear Switch" ), Feature( AUDIO )]
	private SoundPointComponent Audio_GearSwitch { get; set; }


	private void InitAudio()
	{
		OnGearChanged += PlayGearAudio;
		OnEngineStart += StartEngineAudio;
		OnEngineStop += StopEngineAudio;
	}

	private void PlayGearAudio( int gear )
	{
		if ( gear == -1 ) return;
		PlayGearAudio();
	}

	private void PlayGearAudio()
		=> Audio_GearSwitch?.StartSound();

	private async void StartEngineAudio()
	{
		Audio_EngineStart?.StartSound();
		await Task.DelaySeconds( Engine_StartDelay );

		Audio_EngineIdle?.StartSound();
		Audio_EngineLowRPM?.StartSound();
		Audio_EngineHighRPM?.StartSound();
	}

	private void StopEngineAudio()
	{
		Audio_EngineStop?.StartSound();
		Audio_EngineIdle?.StopSound();
		Audio_EngineLowRPM?.StopSound();
		Audio_EngineHighRPM?.StopSound();
	}

	private void UpdateEngineAudio()
	{
		if ( !IsEngineOn ) return;

		float rpm = float.Max( CurrentRPM, Engine_IdleRPM );
		CalculateVolumes( rpm, out float idleVolume, out float lowRpmVolume, out float highRpmVolume );

		if ( Audio_EngineIdle is not null )
		{
			Audio_EngineIdle.Volume = float.Lerp( Audio_EngineIdle.Volume, idleVolume, 1f - float.Exp( -10f * Time.Delta ) );
			Audio_EngineIdle.Pitch = float.Clamp( rpm / Engine_HighRPM, 0.8f, 2.0f );
		}

		if ( Audio_EngineLowRPM is not null )
		{
			Audio_EngineLowRPM.Volume = float.Lerp( Audio_EngineLowRPM.Volume, lowRpmVolume, 1f - float.Exp( -10f * Time.Delta ) );
			Audio_EngineLowRPM.Pitch = float.Clamp( rpm / Engine_LowRPM, 0.5f, 2.5f );
		}

		if ( Audio_EngineHighRPM is not null )
		{
			Audio_EngineHighRPM.Volume = float.Lerp( Audio_EngineHighRPM.Volume, highRpmVolume, 1f - float.Exp( -10f * Time.Delta ) );
			Audio_EngineHighRPM.Pitch = float.Clamp( rpm / Engine_HighRPM, 0.6f, 3.5f );
		}
	}

	private void CalculateVolumes( float rpm, out float idleVolume, out float lowRpmVolume, out float highRpmVolume )
	{
		if ( !IsAccelerating() )
		{
			idleVolume = 1f;
			lowRpmVolume = 0f;
			highRpmVolume = 0f;
			return;
		}

		idleVolume = 0.2f;
		if ( rpm < Engine_LowRPM )
		{
			lowRpmVolume = 1f;
			highRpmVolume = 0f;
			return;
		}

		if ( rpm > Engine_HighRPM )
		{
			highRpmVolume = 1f;
			lowRpmVolume = 0f;
			return;
		}

		float t = float.Clamp( (rpm - Engine_LowRPM) / (Engine_HighRPM - Engine_LowRPM), 0f, 1f );
		lowRpmVolume = 1f - t;
		highRpmVolume = t;
	}

	private void UpdateSkidAudio( Wheel wheel, SceneTraceResult trace )
	{
		if ( wheel.Audio_SkidMark is null ) return;

		if ( !wheel.IsSkidding || !trace.Hit )
		{
			wheel.Audio_SkidMark.Volume -= wheel.Audio_SkidMark.Volume * (1f - float.Exp( -10f * Time.Delta ));
			return;
		}

		Vector3 contactPoint = GetWheelContactPoint( wheel, trace );
		Vector3 tireVelocity = Body.GetVelocityAtPoint( contactPoint );

		float sidewaysVelocity = float.Abs( Vector3.Dot( wheel.Outwards, tireVelocity ) );

		float slipIntensity = sidewaysVelocity;
		if ( wheel.IsBraking ) slipIntensity = float.Max( slipIntensity, tireVelocity.Length );

		float normalizedSlip = float.Clamp( (slipIntensity - 100f) / 500f, 0.0f, 1.0f );

		float targetVolume = normalizedSlip * wheel.Audio_SkidMark.SoundEvent.Volume.GetValue();
		float targetPitch = float.Lerp( 0.8f, 1.3f, normalizedSlip );

		float expFactor = 1f - float.Exp( -10f * Time.Delta );

		wheel.Audio_SkidMark.Volume += (targetVolume - wheel.Audio_SkidMark.Volume) * expFactor;
		wheel.Audio_SkidMark.Pitch += (targetPitch - wheel.Audio_SkidMark.Pitch) * expFactor;
	}
}