121 lines
3.1 KiB
C#
121 lines
3.1 KiB
C#
using Sandbox;
|
|
using Sandbox.Audio;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using VeloX.Audio;
|
|
using static VeloX.EngineStream;
|
|
|
|
namespace VeloX;
|
|
|
|
public class EngineStreamPlayer( EngineStream stream ) : IDisposable
|
|
{
|
|
|
|
private static readonly Mixer EngineMixer = Mixer.FindMixerByName( "Engine" );
|
|
public EngineStream Stream { get; set; } = stream;
|
|
|
|
public EngineState EngineState { get; set; }
|
|
public bool EngineSoundPaused => EngineState != EngineState.Running;
|
|
|
|
public float Throttle { get; set; }
|
|
public bool IsRedlining { get; set; }
|
|
public float RPMPercent { get; set; }
|
|
|
|
private float _wobbleTime;
|
|
|
|
public readonly Dictionary<Layer, SoundHandle> EngineSounds = [];
|
|
|
|
public void Update( float deltaTime, Vector3 position, bool isLocal = false )
|
|
{
|
|
|
|
var globalPitch = 1.0f;
|
|
|
|
// Gear wobble effect
|
|
if ( _wobbleTime > 0 )
|
|
{
|
|
_wobbleTime -= deltaTime * (0.1f + Throttle);
|
|
globalPitch += MathF.Cos( _wobbleTime * Stream.Parameters.WobbleFrequency ) * _wobbleTime * (1 - _wobbleTime) * Stream.Parameters.WobbleStrength;
|
|
}
|
|
|
|
globalPitch *= Stream.Parameters.Pitch;
|
|
|
|
// Redline effect
|
|
var redlineVolume = 1.0f;
|
|
if ( IsRedlining )
|
|
{
|
|
redlineVolume = 1 - Stream.Parameters.RedlineStrength +
|
|
MathF.Cos( RealTime.Now * Stream.Parameters.RedlineFrequency ) *
|
|
Stream.Parameters.RedlineStrength;
|
|
|
|
}
|
|
// Process layers
|
|
foreach ( var (id, layer) in Stream.Layers )
|
|
{
|
|
EngineSounds.TryGetValue( layer, out var channel );
|
|
|
|
if ( !channel.IsValid() && layer.AudioPath.IsValid() )
|
|
{
|
|
channel = Sound.PlayFile( layer.AudioPath );
|
|
EngineSounds[layer] = channel;
|
|
}
|
|
|
|
if ( !channel.IsValid() || channel.Paused && (EngineSoundPaused || layer.IsMuted) )
|
|
continue;
|
|
|
|
// Reset controller outputs
|
|
float layerVolume = 1.0f;
|
|
float layerPitch = 1.0f;
|
|
|
|
// Apply all controllers
|
|
foreach ( var controller in layer.Controllers )
|
|
{
|
|
var inputValue = controller.InputParameter switch
|
|
{
|
|
Controller.InputTypes.Throttle => Throttle,
|
|
Controller.InputTypes.RpmFraction => RPMPercent,
|
|
_ => 0.0f
|
|
};
|
|
|
|
var normalized = Math.Clamp( inputValue, controller.InputRange.Min, controller.InputRange.Max );
|
|
var outputValue = controller.InputRange.Remap(
|
|
normalized,
|
|
controller.OutputRange.Min,
|
|
controller.OutputRange.Max
|
|
);
|
|
|
|
// Apply to correct parameter
|
|
switch ( controller.OutputParameter )
|
|
{
|
|
case Controller.OutputTypes.Volume:
|
|
layerVolume *= outputValue;
|
|
break;
|
|
case Controller.OutputTypes.Pitch:
|
|
layerPitch *= outputValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Apply redline effect if needed
|
|
layerVolume *= layer.UseRedline ? redlineVolume : 1.0f;
|
|
layerPitch *= globalPitch;
|
|
// Update audio channel
|
|
channel.Pitch = layerPitch;
|
|
channel.Volume = layerVolume * Stream.Parameters.Volume;
|
|
channel.Position = position;
|
|
channel.ListenLocal = isLocal;
|
|
channel.Paused = EngineSoundPaused || layer.IsMuted;
|
|
channel.FollowParent = true;
|
|
channel.TargetMixer = EngineMixer;
|
|
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach ( var item in EngineSounds )
|
|
{
|
|
item.Value?.Stop();
|
|
item.Value?.Dispose();
|
|
}
|
|
}
|
|
}
|