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;
}
}