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