Mercurial > hg > aimc
comparison trunk/src/Modules/BMM/ModuleGammatone.cc @ 288:34993448961f
-Updated the Slaney IIR gammatone to use a cascase of four second-order filters as per the implementtion in Slaney's auditory toolbox. This is more numerically stable at high sample rates and low centre frequencies.
author | tomwalters |
---|---|
date | Sat, 20 Feb 2010 17:56:40 +0000 |
parents | 4b3a43b543dd |
children | 6cf55200a199 |
comparison
equal
deleted
inserted
replaced
287:4b3a43b543dd | 288:34993448961f |
---|---|
46 | 46 |
47 ModuleGammatone::~ModuleGammatone() { | 47 ModuleGammatone::~ModuleGammatone() { |
48 } | 48 } |
49 | 49 |
50 void ModuleGammatone::ResetInternal() { | 50 void ModuleGammatone::ResetInternal() { |
51 state_.resize(num_channels_); | 51 state_1_.resize(num_channels_); |
52 state_2_.resize(num_channels_); | |
53 state_3_.resize(num_channels_); | |
54 state_4_.resize(num_channels_); | |
52 for (int i = 0; i < num_channels_; ++i) { | 55 for (int i = 0; i < num_channels_; ++i) { |
53 state_[i].resize(9, 0.0f); | 56 state_1_[i].resize(3, 0.0f); |
57 state_2_[i].resize(3, 0.0f); | |
58 state_3_[i].resize(3, 0.0f); | |
59 state_4_[i].resize(3, 0.0f); | |
54 } | 60 } |
55 } | 61 } |
56 | 62 |
57 bool ModuleGammatone::InitializeInternal(const SignalBank& input) { | 63 bool ModuleGammatone::InitializeInternal(const SignalBank& input) { |
58 // Calculate number of channels, and centre frequencies | 64 // Calculate number of channels, and centre frequencies |
61 float delta_erb = (erb_max - erb_min) / (num_channels_ - 1); | 67 float delta_erb = (erb_max - erb_min) / (num_channels_ - 1); |
62 | 68 |
63 centre_frequencies_.resize(num_channels_); | 69 centre_frequencies_.resize(num_channels_); |
64 float erb_current = erb_min; | 70 float erb_current = erb_min; |
65 | 71 |
72 output_.Initialize(num_channels_, | |
73 input.buffer_length(), | |
74 input.sample_rate()); | |
75 | |
66 for (int i = 0; i < num_channels_; ++i) { | 76 for (int i = 0; i < num_channels_; ++i) { |
67 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current); | 77 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current); |
68 erb_current += delta_erb; | 78 erb_current += delta_erb; |
69 } | 79 output_.set_centre_frequency(i, centre_frequencies_[i]); |
70 | 80 } |
71 forward_.resize(num_channels_); | 81 |
72 back_.resize(num_channels_); | 82 a_.resize(num_channels_); |
73 state_.resize(num_channels_); | 83 b1_.resize(num_channels_); |
84 b2_.resize(num_channels_); | |
85 b3_.resize(num_channels_); | |
86 b4_.resize(num_channels_); | |
87 state_1_.resize(num_channels_); | |
88 state_2_.resize(num_channels_); | |
89 state_3_.resize(num_channels_); | |
90 state_4_.resize(num_channels_); | |
74 | 91 |
75 for (int ch = 0; ch < num_channels_; ++ch) { | 92 for (int ch = 0; ch < num_channels_; ++ch) { |
76 float cf = centre_frequencies_[ch]; | 93 double cf = centre_frequencies_[ch]; |
77 float erb = ERBTools::Freq2ERBw(cf); | 94 double erb = ERBTools::Freq2ERBw(cf); |
78 | 95 |
79 // Sample interval | 96 // Sample interval |
80 float dt = 1.0f / input.sample_rate(); | 97 double dt = 1.0f / input.sample_rate(); |
81 | 98 |
82 // Bandwidth parameter | 99 // Bandwidth parameter |
83 float b = 1.019f * 2.0f * M_PI * erb; | 100 double b = 1.019f * 2.0f * M_PI * erb; |
84 | 101 |
85 // All of the following expressions are derived in Apple TR #35, "An | 102 // The following expressions are derived in Apple TR #35, "An |
86 // Efficient Implementation of the Patterson-Holdsworth Cochlear | 103 // Efficient Implementation of the Patterson-Holdsworth Cochlear |
87 // Filter Bank". | 104 // Filter Bank" and used in Malcolm Slaney's auditory toolbox, where he |
105 // defines this alternaltive four stage cascade of second-order filters. | |
88 | 106 |
89 // Calculate the gain: | 107 // Calculate the gain: |
90 float cpt = cf * M_PI * dt; | 108 double cpt = cf * M_PI * dt; |
91 complex<float> exponent(0.0f, 2.0f * cpt); | 109 complex<double> exponent(0.0, 2.0 * cpt); |
92 complex<float> ec = exp(2.0f * exponent); | 110 complex<double> ec = exp(2.0 * exponent); |
93 complex<float> two_cf_pi_t(2.0f * cpt, 0.0f); | 111 complex<double> two_cf_pi_t(2.0 * cpt, 0.0); |
94 complex<float> two_pow(pow(2.0f, (3.0f / 2.0f)), 0.0f); | 112 complex<double> two_pow(pow(2.0, (3.0 / 2.0)), 0.0); |
95 complex<float> p = -2.0f * ec * dt | 113 complex<double> p = -2.0 * ec * dt |
96 + 2.0f * exp(-(b * dt) + exponent) * dt; | 114 + 2.0 * exp(-(b * dt) + exponent) * dt; |
97 complex<float> b_dt(b * dt, 0.0f); | 115 complex<double> b_dt(b * dt, 0.0); |
98 | 116 |
99 float gain = abs( | 117 double gain = abs( |
100 (p * (cos(two_cf_pi_t) - sqrt(3.0f - two_pow) * sin(two_cf_pi_t))) | 118 (p * (cos(two_cf_pi_t) - sqrt(3.0 - two_pow) * sin(two_cf_pi_t))) |
101 * (p * (cos(two_cf_pi_t) + sqrt(3.0f - two_pow) * sin(two_cf_pi_t))) | 119 * (p * (cos(two_cf_pi_t) + sqrt(3.0 - two_pow) * sin(two_cf_pi_t))) |
102 * (p * (cos(two_cf_pi_t) - sqrt(3.0f + two_pow) * sin(two_cf_pi_t))) | 120 * (p * (cos(two_cf_pi_t) - sqrt(3.0 + two_pow) * sin(two_cf_pi_t))) |
103 * (p * (cos(two_cf_pi_t) + sqrt(3.0f + two_pow) * sin(two_cf_pi_t))) | 121 * (p * (cos(two_cf_pi_t) + sqrt(3.0 + two_pow) * sin(two_cf_pi_t))) |
104 / pow(-2.0f / exp(2.0f * b_dt) - 2.0f * ec + 2.0f * (1.0f + ec) | 122 / pow(-2.0 / exp(2.0 * b_dt) - 2.0 * ec + 2.0 * (1.0 + ec) |
105 / exp(b_dt), 4.0f)); | 123 / exp(b_dt), 4.0)); |
106 | 124 |
107 // The filter coefficients themselves: | 125 // The filter coefficients themselves: |
108 const int coeff_count = 9; | 126 const int coeff_count = 3; |
109 forward_[ch].resize(coeff_count, 0.0f); | 127 a_[ch].resize(coeff_count, 0.0f); |
110 back_[ch].resize(coeff_count, 0.0f); | 128 b1_[ch].resize(coeff_count, 0.0f); |
111 state_[ch].resize(coeff_count, 0.0f); | 129 b2_[ch].resize(coeff_count, 0.0f); |
112 | 130 b3_[ch].resize(coeff_count, 0.0f); |
113 forward_[ch][0] = pow(dt, 4.0f) / gain; | 131 b4_[ch].resize(coeff_count, 0.0f); |
114 forward_[ch][1] = (-4.0f * pow(dt, 4.0f) * cos(2.0f * cpt) | 132 state_1_[ch].resize(coeff_count, 0.0f); |
115 / exp(b * dt) / gain); | 133 state_2_[ch].resize(coeff_count, 0.0f); |
116 forward_[ch][2] = (6.0f * pow(dt, 4.0f) * cos(4.0f * cpt) | 134 state_3_[ch].resize(coeff_count, 0.0f); |
117 / exp(2.0f * b * dt) / gain); | 135 state_4_[ch].resize(coeff_count, 0.0f); |
118 forward_[ch][3] = (-4.0f * pow(dt, 4.0f) * cos(6.0f * cpt) | 136 |
119 / exp(3.0f * b * dt) / gain); | 137 double B0 = dt; |
120 forward_[ch][4] = (pow(dt, 4.0f) * cos(8.0f * cpt) | 138 double B2 = 0.0f; |
121 / exp(4.0f * b * dt) / gain); | 139 |
122 // Note: the remainder of the forward vector is zero-padded | 140 double B11 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) |
123 | 141 + 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt |
124 back_[ch][0] = 1.0f; | 142 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; |
125 back_[ch][1] = -8.0f * cos(2.0f * cpt) / exp(b * dt); | 143 double B12 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) |
126 back_[ch][2] = (4.0f * (4.0f + 3.0f * cos(4.0f * cpt)) | 144 - 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt |
127 / exp(2.0f * b * dt)); | 145 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; |
128 back_[ch][3] = (-8.0f * (6.0f * cos(2.0f * cpt) + cos(6.0f * cpt)) | 146 double B13 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) |
129 / exp(3.0f * b * dt)); | 147 + 2.0f * sqrt(3 - pow(2.0f, 1.5f)) * dt |
130 back_[ch][4] = (2.0f * (18.0f + 16.0f * cos(4.0f * cpt) + cos(8.0f * cpt)) | 148 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; |
131 / exp(4.0f * b * dt)); | 149 double B14 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) |
132 back_[ch][5] = (-8.0f * (6.0f * cos(2.0f * cpt) + cos(6.0f * cpt)) | 150 - 2.0f * sqrt(3 - pow(2.0f, 1.5f)) * dt |
133 / exp(5.0f * b * dt)); | 151 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;; |
134 back_[ch][6] = (4.0f * (4.0f + 3.0f * cos(4.0f * cpt)) | 152 |
135 / exp(6.0f * b * dt)); | 153 a_[ch][0] = 1.0f; |
136 back_[ch][7] = -8.0f * cos(2.0f * cpt) / exp(7.0f * b * dt); | 154 a_[ch][1] = -2.0f * cos(2.0f * cf * M_PI * dt) / exp(b * dt); |
137 back_[ch][8] = exp(-8.0f * b * dt); | 155 a_[ch][2] = exp(-2.0f * b * dt); |
138 } | 156 b1_[ch][0] = B0 / gain; |
139 output_.Initialize(num_channels_, | 157 b1_[ch][1] = B11 / gain; |
140 input.buffer_length(), | 158 b1_[ch][2] = B2 / gain; |
141 input.sample_rate()); | 159 b2_[ch][0] = B0; |
160 b2_[ch][1] = B12; | |
161 b2_[ch][2] = B2; | |
162 b3_[ch][0] = B0; | |
163 b3_[ch][1] = B13; | |
164 b3_[ch][2] = B2; | |
165 b4_[ch][0] = B0; | |
166 b4_[ch][1] = B14; | |
167 b4_[ch][2] = B2; | |
168 | |
169 } | |
142 return true; | 170 return true; |
143 } | 171 } |
144 | 172 |
145 void ModuleGammatone::Process(const SignalBank &input) { | 173 void ModuleGammatone::Process(const SignalBank &input) { |
146 output_.set_start_time(input.start_time()); | 174 output_.set_start_time(input.start_time()); |
147 int audio_channel = 0; | 175 int audio_channel = 0; |
148 | 176 |
149 vector<vector<float> >::iterator b = forward_.begin(); | 177 vector<vector<double> >::iterator b1 = b1_.begin(); |
150 vector<vector<float> >::iterator a = back_.begin(); | 178 vector<vector<double> >::iterator b2 = b2_.begin(); |
151 vector<vector<float> >::iterator s = state_.begin(); | 179 vector<vector<double> >::iterator b3 = b3_.begin(); |
152 | 180 vector<vector<double> >::iterator b4 = b4_.begin(); |
153 for (int ch = 0; ch < num_channels_; ++ch, ++a, ++b, ++s) { | 181 vector<vector<double> >::iterator a = a_.begin(); |
154 for (int i = 0; i < input.buffer_length(); ++i) { | 182 vector<vector<double> >::iterator s1 = state_1_.begin(); |
155 // Direct-form-II IIR filter | 183 vector<vector<double> >::iterator s2 = state_2_.begin(); |
156 float in = input.sample(audio_channel, i); | 184 vector<vector<double> >::iterator s3 = state_3_.begin(); |
157 float out = (*b)[0] * in + (*s)[0]; | 185 vector<vector<double> >::iterator s4 = state_4_.begin(); |
158 for (unsigned int stage = 1; stage < s->size(); ++stage) | 186 |
159 (*s)[stage - 1] = (*b)[stage] * in - (*a)[stage] * out + (*s)[stage]; | 187 // Temporary storage between filter stages |
160 output_.set_sample(ch, i, out); | 188 vector<double> out(input.buffer_length()); |
189 for (int ch = 0; ch < num_channels_; | |
190 ++ch, ++b1, ++b2, ++b3, ++b4, ++a, ++s1, ++s2, ++s3, ++s4) { | |
191 for (int i = 0; i < input.buffer_length(); ++i) { | |
192 // Direct-form-II IIR filter | |
193 double in = input.sample(audio_channel, i); | |
194 out[i] = (*b1)[0] * in + (*s1)[0]; | |
195 for (unsigned int stage = 1; stage < s1->size(); ++stage) | |
196 (*s1)[stage - 1] = (*b1)[stage] * in | |
197 - (*a)[stage] * out[i] + (*s1)[stage]; | |
198 } | |
199 for (int i = 0; i < input.buffer_length(); ++i) { | |
200 // Direct-form-II IIR filter | |
201 double in = out[i]; | |
202 out[i] = (*b2)[0] * in + (*s2)[0]; | |
203 for (unsigned int stage = 1; stage < s2->size(); ++stage) | |
204 (*s2)[stage - 1] = (*b2)[stage] * in | |
205 - (*a)[stage] * out[i] + (*s2)[stage]; | |
206 } | |
207 for (int i = 0; i < input.buffer_length(); ++i) { | |
208 // Direct-form-II IIR filter | |
209 double in = out[i]; | |
210 out[i] = (*b3)[0] * in + (*s3)[0]; | |
211 for (unsigned int stage = 1; stage < s3->size(); ++stage) | |
212 (*s3)[stage - 1] = (*b3)[stage] * in | |
213 - (*a)[stage] * out[i] + (*s3)[stage]; | |
214 } | |
215 for (int i = 0; i < input.buffer_length(); ++i) { | |
216 // Direct-form-II IIR filter | |
217 double in = out[i]; | |
218 out[i] = (*b4)[0] * in + (*s4)[0]; | |
219 for (unsigned int stage = 1; stage < s4->size(); ++stage) | |
220 (*s4)[stage - 1] = (*b4)[stage] * in | |
221 - (*a)[stage] * out[i] + (*s4)[stage]; | |
222 output_.set_sample(ch, i, out[i]); | |
161 } | 223 } |
162 } | 224 } |
163 PushOutput(); | 225 PushOutput(); |
164 } | 226 } |
165 | 227 |