1 module nes.filter;
2 
3 import std.math;
4 
5 interface Filter {
6     float step(float x);
7 }
8 
9 // First order filters are defined by the following parameters.
10 // y[n] = B0*x[n] + B1*x[n-1] - A1*y[n-1]
11 class FirstOrderFilter : Filter {
12     this(float b0, float b1, float a1, float prevX, float prevY) {
13         this.b0 = b0;
14         this.b1 = b1;
15         this.a1 = a1;
16         this.prevX = prevX;
17         this.prevY = prevY;
18     }
19 
20     float step(float x) {
21         auto y = this.b0 * x + this.b1 * this.prevX - this.a1 * this.prevY;
22         this.prevY = y;
23         this.prevX = x;
24         return y;
25     }
26 
27     private:
28         float b0, b1, a1, prevX, prevY;
29 }
30 
31 class FilterChain : Filter {
32     this(Filter[] filters ...) {
33         this.filterChain = filters.dup;
34     }
35 
36     float step(float x) {
37         if (this.filterChain != null) {
38             foreach (f; this.filterChain) {
39                 x = f.step(x);
40             }
41         }
42         return x;
43     }
44 
45     private:
46         Filter[] filterChain;
47 }
48 
49 // sampleRate: samples per second
50 // cutoffFreq: oscillations per second
51 Filter LowPassFilter(float sampleRate, float cutoffFreq) {
52     auto c = sampleRate / std.math.PI / cutoffFreq;
53     auto a0i = 1 / (1 + c);
54     return new FirstOrderFilter(a0i, a0i, (1 - c) * a0i, 0, 0);
55 }
56 
57 Filter HighPassFilter(float sampleRate, float cutoffFreq) {
58     auto c = sampleRate / std.math.PI / cutoffFreq;
59     auto a0i = 1 / (1 + c);
60     return new FirstOrderFilter(c * a0i, -c * a0i, (1 - c) * a0i, 0, 0);
61 }