1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! # HighPass
//! 
//! 18dB/octave
//! Derived from 3rd Order Butterworth Low Pass Filter.

use super::*;

/// High pass filter adapted from the 3rd Order Butterworth Low Pass Filter with
/// resonance.
pub struct HighPass {
    a0: SampleT,
    a1: SampleT,
    a2: SampleT,
    a3: SampleT,
    b1: SampleT,
    b2: SampleT,
    b3: SampleT,

    x1: SampleT,
    x2: SampleT,
    x3: SampleT,
    y1: SampleT,
    y2: SampleT,
    y3: SampleT,

    fc: MathT,
    r: MathT
}

impl HighPass {
    /// Creates a new high pass from the given cutoff frequency and resonance
    /// values.
    /// 
    /// # Parameters
    /// 
    /// * `fc` - The cutoff frequency.
    /// * `r` - The resonance of the filter. Value should be in the range [0,1].
    /// If the value falls out of that range it is clamped to the closer value.
    pub fn new(fc: MathT, r: MathT) -> HighPass {
        let fc = fc.min(SAMPLE_RATE as MathT / 2.0);
        let r = r.min(1.0).max(0.0);
        let mut hp = HighPass {
            a0: SampleT::default(),
            a1: SampleT::default(),
            a2: SampleT::default(),
            a3: SampleT::default(),
            b1: SampleT::default(),
            b2: SampleT::default(),
            b3: SampleT::default(),
            x1: SampleT::default(),
            x2: SampleT::default(),
            x3: SampleT::default(),
            y1: SampleT::default(),
            y2: SampleT::default(),
            y3: SampleT::default(),
            fc,
            r,
        };

        hp.reset();

        hp
    }

    /// Returns the central frequency of the filter.
    pub fn get_central_frequency(&self) -> MathT {
        self.fc
    }

    /// Sets the central frequency of the filter.
    pub fn set_central_frequency(&mut self, fc: MathT) {
        let fc = fc.min(SAMPLE_RATE as MathT / 2.0);

        self.fc = fc;
        self.reset();
    }

    /// Returns the resonance of the filter.
    pub fn get_resonance(&self) -> MathT {
        self.r
    }

    /// Sets the resonance of the filter.
    pub fn set_resonance(&mut self, r: MathT) {
        let r = r.min(1.0).max(0.0);

        self.r = r;
        self.reset();
    }

    fn reset(&mut self) {
        let theta = std::f64::consts::PI * (4.0 - self.r) / 6.0;
        let k = 1.0 - 2.0 * theta.cos();
        let w = 2.0 * std::f64::consts::PI * self.fc;
        let t = w * INV_SAMPLE_RATE;
        let g = t.powf(3.0) + k*t.powf(2.0) + k*t + 1.0;

        self.a0 = ( 1.0/g) as SampleT;
        self.a1 = (-3.0/g) as SampleT;
        self.a2 = ( 3.0/g) as SampleT;
        self.a3 = (-1.0/g) as SampleT;

        self.b1 = ((k*t.powf(2.0) + 2.0*k*t + 3.0)/g) as SampleT;
        self.b2 = ((-k*t - 3.0)/g) as SampleT;
        self.b3 = (1.0/g) as SampleT;
    }
}

impl Modifier for HighPass {
    fn process(&mut self, x: SampleT) -> SampleT {
        let y = self.a0*x + self.a1*self.x1 + self.a2*self.x2 + self.a3*self.x3 +
            self.b1*self.y1 + self.b2*self.y2 + self.b3*self.y3;

        self.x3 = self.x2;
        self.x2 = self.x1;
        self.x1 = x;
        self.y3 = self.y2;
        self.y2 = self.y1;
        self.y1 = y;

        y
    }
}

impl Clone for HighPass {
    fn clone(&self) -> Self {
        HighPass {
            a0: self.a0,
            a1: self.a1,
            a2: self.a2,
            a3: self.a3,
            b1: self.b1,
            b2: self.b2,
            b3: self.b3,
            x1: SampleT::default(),
            x2: SampleT::default(),
            x3: SampleT::default(),
            y1: SampleT::default(),
            y2: SampleT::default(),
            y3: SampleT::default(),
            fc: self.fc,
            r: self.r,
        }
    }
}