using System; using System.Collections.Generic; using Sandbox; namespace SFXR; [Title( "ADSR Envelope" )] [Category( "SFXR Effects" )] [Icon( "mail_outline" )] public class SFXREnvelope : SFXREffect { /// /// Time the sound takes to reach its peak amplitude /// (Default: 0) /// [Property, Range( 0, 10 )] public float Attack { get; set; } = 0; /// /// The time taken for the sound to fade to the sustain level /// [Property, Range( 0, 10 )] public float Decay { get; set; } = 0; /// /// The level maintained until release is triggered /// (Default: 1) /// [Property, Range( 0, 1 )] public float Sustain { get; set; } = 1f; /// /// The time taken for the sound to fade to zero after the sustain /// (Default: 0.3) /// [Property, Range( 0, 10 )] public float SustainTime { get; set; } = 0.3f; /// /// The time taken for the sound to fade to zero after the release /// (Default: 0.4) /// [Property, Range( 0, 10 )] public float Release { get; set; } = 0.4f; /// /// Returns the amplitude of the envelope at a given time /// /// Time in seconds /// Amplitude of the envelope at the given time public float GetAmplitude( float time ) { return GetCurve().Evaluate( time / GetLength() ); } public override short[] Apply( short[] samples, SFXRComponent sound ) { // Calculate the envelope amplitude for each sample for ( int i = 0; i < samples.Length; i++ ) { float t = i / (float)sound.SampleRate; float amplitude = GetAmplitude( t ); samples[i] = (short)(samples[i] * amplitude); } return samples; } public float GetLength() { return Attack + Decay + SustainTime + Release; } public Curve GetCurve() { Curve curve = new(); List points = new(); // Add the attack curve points.Add( new Vector2( 0, 0 ) ); points.Add( new Vector2( Attack, 1 ) ); // Add the decay curve points.Add( new Vector2( Attack + Decay, Sustain ) ); // Add the sustain curve points.Add( new Vector2( Attack + Decay + SustainTime, Sustain ) ); // Add the release curve points.Add( new Vector2( Attack + Decay + SustainTime + Release, 0 ) ); // Normalize the curve to 0-1 in the x for ( int i = 0; i < points.Count; i++ ) { points[i] = new Vector2( points[i].x / (Attack + Decay + SustainTime + Release), points[i].y ); } // Add the points to the curve foreach ( var point in points ) { curve.AddPoint( point.x, point.y ); } return curve; } }