Code/FX/HighPass.cs

using System;
using Sandbox;

namespace SFXR;

[Title( "High Pass Filter" )]
[Category( "SFXR Effects" )]
[Icon( "align_horizontal_left" )]
public class SFXRHighPass : SFXREffect
{
    /// <summary>
    /// Cutoff value of the high-pass filter
    /// (Default: 0, Range: 0 - 1)
    /// </summary>
    [Property, Range( 0f, 12000f, 0.01f )]
    public float Cutoff { get; set; } = 4000;

    /// <summary>
    /// Amount by which the high-pass cutoff frequency is increased or decreased over time
    /// (Default: 0, Range: -1 - 1)
    /// </summary>
    [Property, Range( -12000f, 12000f, 0.01f )]
    public float Sweep { get; set; } = 0;

    /// <summary>
    /// Controls the high-pass filter's resonance (peak)
    /// (Default: 0, Range: 0 - 1)
    /// </summary>
    [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;
    }
}