annotate trunk/src/Modules/BMM/ModuleGammatone.cc @ 290:e344ef4898b2

-Moved scripts to new scripts dir -Fixed a bug in the IIR gammatone gain that was causing a resonance at 3kHz -Changes HCL default for do_lowpass to true
author tomwalters
date Mon, 22 Feb 2010 12:42:47 +0000
parents 6cf55200a199
children 2d3cef76b073
rev   line source
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@276 6 // This program is free software: you can redistribute it and/or modify
tomwalters@276 7 // it under the terms of the GNU General Public License as published by
tomwalters@276 8 // the Free Software Foundation, either version 3 of the License, or
tomwalters@276 9 // (at your option) any later version.
tomwalters@276 10 //
tomwalters@276 11 // This program is distributed in the hope that it will be useful,
tomwalters@276 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
tomwalters@276 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
tomwalters@276 14 // GNU General Public License for more details.
tomwalters@276 15 //
tomwalters@276 16 // You should have received a copy of the GNU General Public License
tomwalters@276 17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
tomwalters@276 18
tomwalters@276 19 /*! \file
tomwalters@276 20 * \brief Slaney's gammatone filterbank
tomwalters@276 21 *
tomwalters@276 22 * \author Thomas Walters <tom@acousticscale.org>
tomwalters@276 23 * \date created 2009/11/13
tomwalters@276 24 * \version \$Id$
tomwalters@276 25 */
tomwalters@276 26
tomwalters@287 27 #include <cmath>
tomwalters@276 28 #include <complex>
tomwalters@277 29 #include "Support/ERBTools.h"
tomwalters@276 30
tomwalters@276 31 #include "Modules/BMM/ModuleGammatone.h"
tomwalters@276 32
tomwalters@276 33 namespace aimc {
tomwalters@277 34 using std::vector;
tomwalters@276 35 using std::complex;
tomwalters@276 36 ModuleGammatone::ModuleGammatone(Parameters *params) : Module(params) {
tomwalters@277 37 module_identifier_ = "gt";
tomwalters@276 38 module_type_ = "bmm";
tomwalters@276 39 module_description_ = "Gammatone filterbank (Slaney's IIR gammatone)";
tomwalters@276 40 module_version_ = "$Id$";
tomwalters@276 41
tomwalters@276 42 num_channels_ = parameters_->DefaultInt("gtfb.channel_count", 200);
tomwalters@276 43 min_frequency_ = parameters_->DefaultFloat("gtfb.min_frequency", 86.0f);
tomwalters@276 44 max_frequency_ = parameters_->DefaultFloat("gtfb.max_frequency", 16000.0f);
tomwalters@276 45 }
tomwalters@276 46
tomwalters@277 47 ModuleGammatone::~ModuleGammatone() {
tomwalters@277 48 }
tomwalters@277 49
tomwalters@277 50 void ModuleGammatone::ResetInternal() {
tomwalters@288 51 state_1_.resize(num_channels_);
tomwalters@288 52 state_2_.resize(num_channels_);
tomwalters@288 53 state_3_.resize(num_channels_);
tomwalters@288 54 state_4_.resize(num_channels_);
tomwalters@277 55 for (int i = 0; i < num_channels_; ++i) {
tomwalters@288 56 state_1_[i].resize(3, 0.0f);
tomwalters@288 57 state_2_[i].resize(3, 0.0f);
tomwalters@288 58 state_3_[i].resize(3, 0.0f);
tomwalters@288 59 state_4_[i].resize(3, 0.0f);
tomwalters@277 60 }
tomwalters@277 61 }
tomwalters@277 62
tomwalters@276 63 bool ModuleGammatone::InitializeInternal(const SignalBank& input) {
tomwalters@276 64 // Calculate number of channels, and centre frequencies
tomwalters@277 65 float erb_max = ERBTools::Freq2ERB(max_frequency_);
tomwalters@277 66 float erb_min = ERBTools::Freq2ERB(min_frequency_);
tomwalters@277 67 float delta_erb = (erb_max - erb_min) / (num_channels_ - 1);
tomwalters@277 68
tomwalters@277 69 centre_frequencies_.resize(num_channels_);
tomwalters@277 70 float erb_current = erb_min;
tomwalters@277 71
tomwalters@288 72 output_.Initialize(num_channels_,
tomwalters@288 73 input.buffer_length(),
tomwalters@288 74 input.sample_rate());
tomwalters@288 75
tomwalters@277 76 for (int i = 0; i < num_channels_; ++i) {
tomwalters@280 77 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current);
tomwalters@280 78 erb_current += delta_erb;
tomwalters@288 79 output_.set_centre_frequency(i, centre_frequencies_[i]);
tomwalters@277 80 }
tomwalters@276 81
tomwalters@288 82 a_.resize(num_channels_);
tomwalters@288 83 b1_.resize(num_channels_);
tomwalters@288 84 b2_.resize(num_channels_);
tomwalters@288 85 b3_.resize(num_channels_);
tomwalters@288 86 b4_.resize(num_channels_);
tomwalters@288 87 state_1_.resize(num_channels_);
tomwalters@288 88 state_2_.resize(num_channels_);
tomwalters@288 89 state_3_.resize(num_channels_);
tomwalters@288 90 state_4_.resize(num_channels_);
tomwalters@276 91
tomwalters@276 92 for (int ch = 0; ch < num_channels_; ++ch) {
tomwalters@288 93 double cf = centre_frequencies_[ch];
tomwalters@288 94 double erb = ERBTools::Freq2ERBw(cf);
tomwalters@290 95 // LOG_INFO("%e", erb);
tomwalters@276 96
tomwalters@276 97 // Sample interval
tomwalters@288 98 double dt = 1.0f / input.sample_rate();
tomwalters@276 99
tomwalters@276 100 // Bandwidth parameter
tomwalters@288 101 double b = 1.019f * 2.0f * M_PI * erb;
tomwalters@276 102
tomwalters@288 103 // The following expressions are derived in Apple TR #35, "An
tomwalters@280 104 // Efficient Implementation of the Patterson-Holdsworth Cochlear
tomwalters@288 105 // Filter Bank" and used in Malcolm Slaney's auditory toolbox, where he
tomwalters@288 106 // defines this alternaltive four stage cascade of second-order filters.
tomwalters@276 107
tomwalters@276 108 // Calculate the gain:
tomwalters@288 109 double cpt = cf * M_PI * dt;
tomwalters@288 110 complex<double> exponent(0.0, 2.0 * cpt);
tomwalters@288 111 complex<double> ec = exp(2.0 * exponent);
tomwalters@288 112 complex<double> two_cf_pi_t(2.0 * cpt, 0.0);
tomwalters@288 113 complex<double> two_pow(pow(2.0, (3.0 / 2.0)), 0.0);
tomwalters@290 114 complex<double> p1 = -2.0 * ec * dt;
tomwalters@290 115 complex<double> p2 = 2.0 * exp(-(b * dt) + exponent) * dt;
tomwalters@288 116 complex<double> b_dt(b * dt, 0.0);
tomwalters@276 117
tomwalters@288 118 double gain = abs(
tomwalters@290 119 (p1 + p2 * (cos(two_cf_pi_t) - sqrt(3.0 - two_pow) * sin(two_cf_pi_t)))
tomwalters@290 120 * (p1 + p2 * (cos(two_cf_pi_t) + sqrt(3.0 - two_pow) * sin(two_cf_pi_t)))
tomwalters@290 121 * (p1 + p2 * (cos(two_cf_pi_t) - sqrt(3.0 + two_pow) * sin(two_cf_pi_t)))
tomwalters@290 122 * (p1 + p2 * (cos(two_cf_pi_t) + sqrt(3.0 + two_pow) * sin(two_cf_pi_t)))
tomwalters@290 123 / pow((-2.0 / exp(2.0 * b_dt) - 2.0 * ec + 2.0 * (1.0 + ec)
tomwalters@290 124 / exp(b_dt)), 4));
tomwalters@290 125 LOG_INFO("%e", gain);
tomwalters@276 126
tomwalters@276 127 // The filter coefficients themselves:
tomwalters@288 128 const int coeff_count = 3;
tomwalters@288 129 a_[ch].resize(coeff_count, 0.0f);
tomwalters@288 130 b1_[ch].resize(coeff_count, 0.0f);
tomwalters@288 131 b2_[ch].resize(coeff_count, 0.0f);
tomwalters@288 132 b3_[ch].resize(coeff_count, 0.0f);
tomwalters@288 133 b4_[ch].resize(coeff_count, 0.0f);
tomwalters@288 134 state_1_[ch].resize(coeff_count, 0.0f);
tomwalters@288 135 state_2_[ch].resize(coeff_count, 0.0f);
tomwalters@288 136 state_3_[ch].resize(coeff_count, 0.0f);
tomwalters@288 137 state_4_[ch].resize(coeff_count, 0.0f);
tomwalters@276 138
tomwalters@288 139 double B0 = dt;
tomwalters@288 140 double B2 = 0.0f;
tomwalters@276 141
tomwalters@288 142 double B11 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt)
tomwalters@288 143 + 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt
tomwalters@288 144 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;
tomwalters@288 145 double B12 = -(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 B13 = -(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 B14 = -(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@289 153 * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f;
tomwalters@288 154
tomwalters@288 155 a_[ch][0] = 1.0f;
tomwalters@288 156 a_[ch][1] = -2.0f * cos(2.0f * cf * M_PI * dt) / exp(b * dt);
tomwalters@288 157 a_[ch][2] = exp(-2.0f * b * dt);
tomwalters@288 158 b1_[ch][0] = B0 / gain;
tomwalters@288 159 b1_[ch][1] = B11 / gain;
tomwalters@288 160 b1_[ch][2] = B2 / gain;
tomwalters@288 161 b2_[ch][0] = B0;
tomwalters@288 162 b2_[ch][1] = B12;
tomwalters@288 163 b2_[ch][2] = B2;
tomwalters@288 164 b3_[ch][0] = B0;
tomwalters@288 165 b3_[ch][1] = B13;
tomwalters@288 166 b3_[ch][2] = B2;
tomwalters@288 167 b4_[ch][0] = B0;
tomwalters@288 168 b4_[ch][1] = B14;
tomwalters@288 169 b4_[ch][2] = B2;
tomwalters@276 170 }
tomwalters@277 171 return true;
tomwalters@276 172 }
tomwalters@277 173
tomwalters@277 174 void ModuleGammatone::Process(const SignalBank &input) {
tomwalters@277 175 output_.set_start_time(input.start_time());
tomwalters@277 176 int audio_channel = 0;
tomwalters@277 177
tomwalters@288 178 vector<vector<double> >::iterator b1 = b1_.begin();
tomwalters@288 179 vector<vector<double> >::iterator b2 = b2_.begin();
tomwalters@288 180 vector<vector<double> >::iterator b3 = b3_.begin();
tomwalters@288 181 vector<vector<double> >::iterator b4 = b4_.begin();
tomwalters@288 182 vector<vector<double> >::iterator a = a_.begin();
tomwalters@288 183 vector<vector<double> >::iterator s1 = state_1_.begin();
tomwalters@288 184 vector<vector<double> >::iterator s2 = state_2_.begin();
tomwalters@288 185 vector<vector<double> >::iterator s3 = state_3_.begin();
tomwalters@288 186 vector<vector<double> >::iterator s4 = state_4_.begin();
tomwalters@277 187
tomwalters@288 188 // Temporary storage between filter stages
tomwalters@288 189 vector<double> out(input.buffer_length());
tomwalters@288 190 for (int ch = 0; ch < num_channels_;
tomwalters@288 191 ++ch, ++b1, ++b2, ++b3, ++b4, ++a, ++s1, ++s2, ++s3, ++s4) {
tomwalters@277 192 for (int i = 0; i < input.buffer_length(); ++i) {
tomwalters@280 193 // Direct-form-II IIR filter
tomwalters@288 194 double in = input.sample(audio_channel, i);
tomwalters@288 195 out[i] = (*b1)[0] * in + (*s1)[0];
tomwalters@288 196 for (unsigned int stage = 1; stage < s1->size(); ++stage)
tomwalters@288 197 (*s1)[stage - 1] = (*b1)[stage] * in
tomwalters@288 198 - (*a)[stage] * out[i] + (*s1)[stage];
tomwalters@288 199 }
tomwalters@288 200 for (int i = 0; i < input.buffer_length(); ++i) {
tomwalters@288 201 // Direct-form-II IIR filter
tomwalters@288 202 double in = out[i];
tomwalters@288 203 out[i] = (*b2)[0] * in + (*s2)[0];
tomwalters@288 204 for (unsigned int stage = 1; stage < s2->size(); ++stage)
tomwalters@288 205 (*s2)[stage - 1] = (*b2)[stage] * in
tomwalters@288 206 - (*a)[stage] * out[i] + (*s2)[stage];
tomwalters@288 207 }
tomwalters@288 208 for (int i = 0; i < input.buffer_length(); ++i) {
tomwalters@288 209 // Direct-form-II IIR filter
tomwalters@288 210 double in = out[i];
tomwalters@288 211 out[i] = (*b3)[0] * in + (*s3)[0];
tomwalters@288 212 for (unsigned int stage = 1; stage < s3->size(); ++stage)
tomwalters@288 213 (*s3)[stage - 1] = (*b3)[stage] * in
tomwalters@288 214 - (*a)[stage] * out[i] + (*s3)[stage];
tomwalters@288 215 }
tomwalters@288 216 for (int i = 0; i < input.buffer_length(); ++i) {
tomwalters@288 217 // Direct-form-II IIR filter
tomwalters@288 218 double in = out[i];
tomwalters@288 219 out[i] = (*b4)[0] * in + (*s4)[0];
tomwalters@288 220 for (unsigned int stage = 1; stage < s4->size(); ++stage)
tomwalters@288 221 (*s4)[stage - 1] = (*b4)[stage] * in
tomwalters@288 222 - (*a)[stage] * out[i] + (*s4)[stage];
tomwalters@288 223 output_.set_sample(ch, i, out[i]);
tomwalters@277 224 }
tomwalters@277 225 }
tomwalters@277 226 PushOutput();
tomwalters@277 227 }
tomwalters@277 228
tomwalters@280 229 } // namespace aimc