using System; using Sandbox; namespace SFXR; [Title( "High Pass Filter" )] [Category( "SFXR Effects" )] [Icon( "align_horizontal_left" )] public class SFXRHighPass : SFXREffect { /// /// Cutoff value of the high-pass filter /// (Default: 0, Range: 0 - 1) /// [Property, Range( 0f, 12000f, 0.01f )] public float Cutoff { get; set; } = 4000; /// /// Amount by which the high-pass cutoff frequency is increased or decreased over time /// (Default: 0, Range: -1 - 1) /// [Property, Range( -12000f, 12000f, 0.01f )] public float Sweep { get; set; } = 0; /// /// Controls the high-pass filter's resonance (peak) /// (Default: 0, Range: 0 - 1) /// [Property, Range( 0f, 1f, 0.01f )] public float Resonance { get; set; } = 0; public override short[] Apply( short[] samples, SFXRComponent sound ) { short[] outputSamples = new short[samples.Length]; double currentCutoff = Cutoff; double previousInput = 0; double previousOutput = 0; for ( int i = 0; i < samples.Length; i++ ) { // Update cutoff frequency based on Sweep currentCutoff += Sweep / (double)sound.SampleRate; double RC = 1.0 / (2 * Math.PI * currentCutoff); double dt = 1.0 / (double)sound.SampleRate; double alpha = RC / (RC + dt); double inputSample = samples[i]; double outputSample = alpha * (previousOutput + inputSample - previousInput); // Apply resonance if ( Resonance > 0 ) { double feedback = Resonance + Resonance / (1 - currentCutoff); outputSample = (1 - feedback) * outputSample + feedback * previousOutput; } outputSamples[i] = (short)Math.Clamp( outputSample, short.MinValue, short.MaxValue ); previousInput = inputSample; previousOutput = outputSample; } return outputSamples; } }