]> git.sesse.net Git - nageru/blob - filter.h
Fix an issue where the mixer lagging too much behind CEF would cause us to display...
[nageru] / filter.h
1 // Filter class:
2 // a cascaded biquad IIR filter
3 //
4 // Special cases for type=LPF/BPF/HPF:
5 //
6 //   Butterworth filter:    order=1, resonance=1/sqrt(2)
7 //   Linkwitz-Riley filter: order=2, resonance=1/2
8
9 #ifndef _FILTER_H
10 #define _FILTER_H 1
11
12 #define _USE_MATH_DEFINES
13 #include <cmath>
14 #include <complex>
15
16 #ifdef __SSE__
17 #include <xmmintrin.h>
18 #endif
19
20 enum FilterType
21 {
22         FILTER_NONE = 0,
23         FILTER_LPF,
24         FILTER_HPF,
25         FILTER_BPF,
26         FILTER_NOTCH,
27         FILTER_APF,
28
29         // EQ filters.
30         FILTER_PEAKING_EQ,
31         FILTER_LOW_SHELF,
32         FILTER_HIGH_SHELF,
33 };
34
35 #define FILTER_MAX_ORDER 4
36
37 class Filter  
38 {
39         friend class StereoFilter;
40         friend class SplittingStereoFilter;
41 public:
42         Filter();
43         
44         void init(FilterType type, int new_order);
45
46         void update(); //update coefficients
47 #ifndef NDEBUG
48         void debug();
49 #endif
50         std::complex<double> evaluate_transfer_function(float omega);
51
52         FilterType get_type()                   { return filtertype; }
53         unsigned get_order()                    { return filter_order; }
54
55         // cutoff is taken to be in the [0..pi> (see set_linear_cutoff, below).
56         void render(float *inout_array, unsigned int buf_size, float cutoff, float resonance);
57
58         // Set cutoff, from [0..pi> (where pi is the Nyquist frequency).
59         // Overridden by render() if you use that.
60         void set_linear_cutoff(float new_omega)
61         {
62                 omega = new_omega;
63         }
64
65         void set_resonance(float new_resonance)
66         {
67                 resonance = new_resonance;
68         }
69
70         // For EQ filters only.
71         void set_dbgain_normalized(float db_gain_div_40)
72         {
73                 A = pow(10.0f, db_gain_div_40);
74         }
75
76 #ifdef __SSE__
77         // We don't need the stride argument for SSE, as StereoFilter
78         // has its own SSE implementations.
79         void render_chunk(float *inout_buf, unsigned nSamples);
80 #else
81         void render_chunk(float *inout_buf, unsigned nSamples, unsigned stride = 1);
82 #endif
83
84         FilterType filtertype;
85 private:
86         float omega; //which is 2*Pi*frequency /SAMPLE_RATE
87         float resonance;
88         float A;  // which is 10^(db_gain / 40)
89
90 public:
91         unsigned filter_order;
92 private:
93         float b0, b1, b2, a1, a2; //filter coefs
94
95         struct FeedbackBuffer {
96                 float d0,d1; //feedback buffers
97         } feedback[FILTER_MAX_ORDER];
98
99         void calcSinCos(float omega, float *sinVal, float *cosVal)
100         {
101                 *sinVal = (float)sin(omega);
102                 *cosVal = (float)cos(omega);
103         }
104 };
105
106
107 class StereoFilter
108 {
109 public:
110         void init(FilterType type, int new_order);
111         
112         void render(float *inout_left_ptr, unsigned n_samples, float cutoff, float resonance, float dbgain_normalized = 0.0f);
113 #ifndef NDEBUG
114 #ifdef __SSE__
115         void debug() { parm_filter.debug(); }
116 #else
117         void debug() { filters[0].debug(); }
118 #endif
119 #endif
120 #ifdef __SSE__
121         FilterType get_type() { return parm_filter.get_type(); }
122 #else
123         FilterType get_type() { return filters[0].get_type(); }
124 #endif
125
126 private:
127 #ifdef __SSE__
128         // We only use the filter to calculate coefficients; we don't actually
129         // use its feedbacks.
130         Filter parm_filter;
131         struct SIMDFeedbackBuffer {
132                 __m128 d0, d1;
133         } feedback[FILTER_MAX_ORDER];
134 #else
135         Filter filters[2];
136 #endif
137 };
138
139 #endif // !defined(_FILTER_H)