tomwalters@276
|
1 // Copyright 2009-2010, Thomas Walters
|
tomwalters@276
|
2 //
|
tomwalters@276
|
3 // AIM-C: A C++ implementation of the Auditory Image Model
|
tomwalters@276
|
4 // http://www.acousticscale.org/AIMC
|
tomwalters@276
|
5 //
|
tomwalters@318
|
6 // Licensed under the Apache License, Version 2.0 (the "License");
|
tomwalters@318
|
7 // you may not use this file except in compliance with the License.
|
tomwalters@318
|
8 // You may obtain a copy of the License at
|
tomwalters@276
|
9 //
|
tomwalters@318
|
10 // http://www.apache.org/licenses/LICENSE-2.0
|
tomwalters@276
|
11 //
|
tomwalters@318
|
12 // Unless required by applicable law or agreed to in writing, software
|
tomwalters@318
|
13 // distributed under the License is distributed on an "AS IS" BASIS,
|
tomwalters@318
|
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
tomwalters@318
|
15 // See the License for the specific language governing permissions and
|
tomwalters@318
|
16 // limitations under the License.
|
tomwalters@276
|
17
|
tomwalters@276
|
18 /*! \file
|
tomwalters@276
|
19 * \brief Slaney's gammatone filterbank
|
tomwalters@276
|
20 *
|
tomwalters@276
|
21 * \author Thomas Walters <tom@acousticscale.org>
|
tomwalters@276
|
22 * \date created 2009/11/13
|
tomwalters@276
|
23 * \version \$Id$
|
tomwalters@276
|
24 */
|
tomwalters@276
|
25
|
tomwalters@287
|
26 #include <cmath>
|
tomwalters@276
|
27 #include <complex>
|
tomwalters@277
|
28 #include "Support/ERBTools.h"
|
tomwalters@276
|
29
|
tomwalters@276
|
30 #include "Modules/BMM/ModuleGammatone.h"
|
tomwalters@276
|
31
|
tomwalters@276
|
32 namespace aimc {
|
tomwalters@277
|
33 using std::vector;
|
tomwalters@276
|
34 using std::complex;
|
tomwalters@276
|
35 ModuleGammatone::ModuleGammatone(Parameters *params) : Module(params) {
|
tomwalters@277
|
36 module_identifier_ = "gt";
|
tomwalters@276
|
37 module_type_ = "bmm";
|
tomwalters@276
|
38 module_description_ = "Gammatone filterbank (Slaney's IIR gammatone)";
|
tomwalters@276
|
39 module_version_ = "$Id$";
|
tomwalters@276
|
40
|
tomwalters@276
|
41 num_channels_ = parameters_->DefaultInt("gtfb.channel_count", 200);
|
tomwalters@276
|
42 min_frequency_ = parameters_->DefaultFloat("gtfb.min_frequency", 86.0f);
|
tomwalters@276
|
43 max_frequency_ = parameters_->DefaultFloat("gtfb.max_frequency", 16000.0f);
|
tomwalters@276
|
44 }
|
tomwalters@276
|
45
|
tomwalters@277
|
46 ModuleGammatone::~ModuleGammatone() {
|
tomwalters@277
|
47 }
|
tomwalters@277
|
48
|
tomwalters@277
|
49 void ModuleGammatone::ResetInternal() {
|
tomwalters@288
|
50 state_1_.resize(num_channels_);
|
tomwalters@288
|
51 state_2_.resize(num_channels_);
|
tomwalters@288
|
52 state_3_.resize(num_channels_);
|
tomwalters@288
|
53 state_4_.resize(num_channels_);
|
tomwalters@277
|
54 for (int i = 0; i < num_channels_; ++i) {
|
tomwalters@402
|
55 state_1_[i].clear();
|
tomwalters@288
|
56 state_1_[i].resize(3, 0.0f);
|
tomwalters@402
|
57 state_2_[i].clear();
|
tomwalters@288
|
58 state_2_[i].resize(3, 0.0f);
|
tomwalters@402
|
59 state_3_[i].clear();
|
tomwalters@288
|
60 state_3_[i].resize(3, 0.0f);
|
tomwalters@402
|
61 state_4_[i].clear();
|
tomwalters@288
|
62 state_4_[i].resize(3, 0.0f);
|
tomwalters@277
|
63 }
|
tomwalters@277
|
64 }
|
tomwalters@277
|
65
|
tomwalters@276
|
66 bool ModuleGammatone::InitializeInternal(const SignalBank& input) {
|
tomwalters@276
|
67 // Calculate number of channels, and centre frequencies
|
tomwalters@277
|
68 float erb_max = ERBTools::Freq2ERB(max_frequency_);
|
tomwalters@277
|
69 float erb_min = ERBTools::Freq2ERB(min_frequency_);
|
tomwalters@277
|
70 float delta_erb = (erb_max - erb_min) / (num_channels_ - 1);
|
tomwalters@277
|
71
|
tomwalters@277
|
72 centre_frequencies_.resize(num_channels_);
|
tomwalters@277
|
73 float erb_current = erb_min;
|
tomwalters@277
|
74
|
tomwalters@288
|
75 output_.Initialize(num_channels_,
|
tomwalters@288
|
76 input.buffer_length(),
|
tomwalters@288
|
77 input.sample_rate());
|
tomwalters@288
|
78
|
tomwalters@277
|
79 for (int i = 0; i < num_channels_; ++i) {
|
tomwalters@280
|
80 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current);
|
tomwalters@280
|
81 erb_current += delta_erb;
|
tomwalters@288
|
82 output_.set_centre_frequency(i, centre_frequencies_[i]);
|
tomwalters@277
|
83 }
|
tomwalters@276
|
84
|
tomwalters@288
|
85 a_.resize(num_channels_);
|
tomwalters@288
|
86 b1_.resize(num_channels_);
|
tomwalters@288
|
87 b2_.resize(num_channels_);
|
tomwalters@288
|
88 b3_.resize(num_channels_);
|
tomwalters@288
|
89 b4_.resize(num_channels_);
|
tomwalters@288
|
90 state_1_.resize(num_channels_);
|
tomwalters@288
|
91 state_2_.resize(num_channels_);
|
tomwalters@288
|
92 state_3_.resize(num_channels_);
|
tomwalters@288
|
93 state_4_.resize(num_channels_);
|
tomwalters@276
|
94
|
tomwalters@276
|
95 for (int ch = 0; ch < num_channels_; ++ch) {
|
tomwalters@288
|
96 double cf = centre_frequencies_[ch];
|
tomwalters@288
|
97 double erb = ERBTools::Freq2ERBw(cf);
|
tomwalters@290
|
98 // LOG_INFO("%e", erb);
|
tomwalters@276
|
99
|
tomwalters@276
|
100 // Sample interval
|
tomwalters@288
|
101 double dt = 1.0f / input.sample_rate();
|
tomwalters@276
|
102
|
tomwalters@276
|
103 // Bandwidth parameter
|
tomwalters@288
|
104 double b = 1.019f * 2.0f * M_PI * erb;
|
tomwalters@276
|
105
|
tomwalters@288
|
106 // The following expressions are derived in Apple TR #35, "An
|
tomwalters@280
|
107 // Efficient Implementation of the Patterson-Holdsworth Cochlear
|
tomwalters@288
|
108 // Filter Bank" and used in Malcolm Slaney's auditory toolbox, where he
|
tomwalters@288
|
109 // defines this alternaltive four stage cascade of second-order filters.
|
tomwalters@276
|
110
|
tomwalters@276
|
111 // Calculate the gain:
|
tomwalters@288
|
112 double cpt = cf * M_PI * dt;
|
tomwalters@288
|
113 complex<double> exponent(0.0, 2.0 * cpt);
|
tomwalters@288
|
114 complex<double> ec = exp(2.0 * exponent);
|
tomwalters@288
|
115 complex<double> two_cf_pi_t(2.0 * cpt, 0.0);
|
tomwalters@288
|
116 complex<double> two_pow(pow(2.0, (3.0 / 2.0)), 0.0);
|
tomwalters@290
|
117 complex<double> p1 = -2.0 * ec * dt;
|
tomwalters@290
|
118 complex<double> p2 = 2.0 * exp(-(b * dt) + exponent) * dt;
|
tomwalters@288
|
119 complex<double> b_dt(b * dt, 0.0);
|
tomwalters@276
|
120
|
tomwalters@288
|
121 double gain = abs(
|
tomwalters@290
|
122 (p1 + p2 * (cos(two_cf_pi_t) - sqrt(3.0 - two_pow) * sin(two_cf_pi_t)))
|
tomwalters@290
|
123 * (p1 + p2 * (cos(two_cf_pi_t) + sqrt(3.0 - two_pow) * sin(two_cf_pi_t)))
|
tomwalters@290
|
124 * (p1 + p2 * (cos(two_cf_pi_t) - sqrt(3.0 + two_pow) * sin(two_cf_pi_t)))
|
tomwalters@290
|
125 * (p1 + p2 * (cos(two_cf_pi_t) + sqrt(3.0 + two_pow) * sin(two_cf_pi_t)))
|
tomwalters@290
|
126 / pow((-2.0 / exp(2.0 * b_dt) - 2.0 * ec + 2.0 * (1.0 + ec)
|
tomwalters@290
|
127 / exp(b_dt)), 4));
|
tomwalters@291
|
128 // LOG_INFO("%e", gain);
|
tomwalters@276
|
129
|
tomwalters@276
|
130 // The filter coefficients themselves:
|
tomwalters@288
|
131 const int coeff_count = 3;
|
tomwalters@288
|
132 a_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
133 b1_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
134 b2_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
135 b3_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
136 b4_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
137 state_1_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
138 state_2_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
139 state_3_[ch].resize(coeff_count, 0.0f);
|
tomwalters@288
|
140 state_4_[ch].resize(coeff_count, 0.0f);
|
tomwalters@276
|
141
|
tomwalters@288
|
142 double B0 = dt;
|
tomwalters@288
|
143 double B2 = 0.0f;
|
tomwalters@276
|
144
|
tomwalters@288
|
145 double B11 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt)
|
tomwalters@288
|
146 + 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt
|
tomwalters@288
|
147 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;
|
tomwalters@288
|
148 double B12 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt)
|
tomwalters@288
|
149 - 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt
|
tomwalters@288
|
150 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;
|
tomwalters@288
|
151 double B13 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt)
|
tomwalters@288
|
152 + 2.0f * sqrt(3 - pow(2.0f, 1.5f)) * dt
|
tomwalters@288
|
153 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;
|
tomwalters@288
|
154 double B14 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt)
|
tomwalters@288
|
155 - 2.0f * sqrt(3 - pow(2.0f, 1.5f)) * dt
|
tomwalters@289
|
156 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;
|
tomwalters@288
|
157
|
tomwalters@288
|
158 a_[ch][0] = 1.0f;
|
tomwalters@288
|
159 a_[ch][1] = -2.0f * cos(2.0f * cf * M_PI * dt) / exp(b * dt);
|
tomwalters@288
|
160 a_[ch][2] = exp(-2.0f * b * dt);
|
tomwalters@288
|
161 b1_[ch][0] = B0 / gain;
|
tomwalters@288
|
162 b1_[ch][1] = B11 / gain;
|
tomwalters@288
|
163 b1_[ch][2] = B2 / gain;
|
tomwalters@288
|
164 b2_[ch][0] = B0;
|
tomwalters@288
|
165 b2_[ch][1] = B12;
|
tomwalters@288
|
166 b2_[ch][2] = B2;
|
tomwalters@288
|
167 b3_[ch][0] = B0;
|
tomwalters@288
|
168 b3_[ch][1] = B13;
|
tomwalters@288
|
169 b3_[ch][2] = B2;
|
tomwalters@288
|
170 b4_[ch][0] = B0;
|
tomwalters@288
|
171 b4_[ch][1] = B14;
|
tomwalters@288
|
172 b4_[ch][2] = B2;
|
tomwalters@276
|
173 }
|
tomwalters@277
|
174 return true;
|
tomwalters@276
|
175 }
|
tomwalters@277
|
176
|
tomwalters@277
|
177 void ModuleGammatone::Process(const SignalBank &input) {
|
tomwalters@277
|
178 output_.set_start_time(input.start_time());
|
tomwalters@277
|
179 int audio_channel = 0;
|
tomwalters@277
|
180
|
tomwalters@288
|
181 vector<vector<double> >::iterator b1 = b1_.begin();
|
tomwalters@288
|
182 vector<vector<double> >::iterator b2 = b2_.begin();
|
tomwalters@288
|
183 vector<vector<double> >::iterator b3 = b3_.begin();
|
tomwalters@288
|
184 vector<vector<double> >::iterator b4 = b4_.begin();
|
tomwalters@288
|
185 vector<vector<double> >::iterator a = a_.begin();
|
tomwalters@288
|
186 vector<vector<double> >::iterator s1 = state_1_.begin();
|
tomwalters@288
|
187 vector<vector<double> >::iterator s2 = state_2_.begin();
|
tomwalters@288
|
188 vector<vector<double> >::iterator s3 = state_3_.begin();
|
tomwalters@288
|
189 vector<vector<double> >::iterator s4 = state_4_.begin();
|
tomwalters@277
|
190
|
tomwalters@288
|
191 // Temporary storage between filter stages
|
tomwalters@288
|
192 vector<double> out(input.buffer_length());
|
tomwalters@288
|
193 for (int ch = 0; ch < num_channels_;
|
tomwalters@288
|
194 ++ch, ++b1, ++b2, ++b3, ++b4, ++a, ++s1, ++s2, ++s3, ++s4) {
|
tomwalters@277
|
195 for (int i = 0; i < input.buffer_length(); ++i) {
|
tomwalters@280
|
196 // Direct-form-II IIR filter
|
tomwalters@288
|
197 double in = input.sample(audio_channel, i);
|
tomwalters@288
|
198 out[i] = (*b1)[0] * in + (*s1)[0];
|
tomwalters@288
|
199 for (unsigned int stage = 1; stage < s1->size(); ++stage)
|
tomwalters@288
|
200 (*s1)[stage - 1] = (*b1)[stage] * in
|
tomwalters@288
|
201 - (*a)[stage] * out[i] + (*s1)[stage];
|
tomwalters@288
|
202 }
|
tomwalters@288
|
203 for (int i = 0; i < input.buffer_length(); ++i) {
|
tomwalters@288
|
204 // Direct-form-II IIR filter
|
tomwalters@288
|
205 double in = out[i];
|
tomwalters@288
|
206 out[i] = (*b2)[0] * in + (*s2)[0];
|
tomwalters@288
|
207 for (unsigned int stage = 1; stage < s2->size(); ++stage)
|
tomwalters@288
|
208 (*s2)[stage - 1] = (*b2)[stage] * in
|
tomwalters@288
|
209 - (*a)[stage] * out[i] + (*s2)[stage];
|
tomwalters@288
|
210 }
|
tomwalters@288
|
211 for (int i = 0; i < input.buffer_length(); ++i) {
|
tomwalters@288
|
212 // Direct-form-II IIR filter
|
tomwalters@288
|
213 double in = out[i];
|
tomwalters@288
|
214 out[i] = (*b3)[0] * in + (*s3)[0];
|
tomwalters@288
|
215 for (unsigned int stage = 1; stage < s3->size(); ++stage)
|
tomwalters@288
|
216 (*s3)[stage - 1] = (*b3)[stage] * in
|
tomwalters@288
|
217 - (*a)[stage] * out[i] + (*s3)[stage];
|
tomwalters@288
|
218 }
|
tomwalters@288
|
219 for (int i = 0; i < input.buffer_length(); ++i) {
|
tomwalters@288
|
220 // Direct-form-II IIR filter
|
tomwalters@288
|
221 double in = out[i];
|
tomwalters@288
|
222 out[i] = (*b4)[0] * in + (*s4)[0];
|
tomwalters@288
|
223 for (unsigned int stage = 1; stage < s4->size(); ++stage)
|
tomwalters@288
|
224 (*s4)[stage - 1] = (*b4)[stage] * in
|
tomwalters@288
|
225 - (*a)[stage] * out[i] + (*s4)[stage];
|
tomwalters@288
|
226 output_.set_sample(ch, i, out[i]);
|
tomwalters@277
|
227 }
|
tomwalters@277
|
228 }
|
tomwalters@277
|
229 PushOutput();
|
tomwalters@277
|
230 }
|
tomwalters@277
|
231
|
tomwalters@280
|
232 } // namespace aimc
|