annotate src/Modules/BMM/ModuleGammatone.cc @ 639:7c3671f98280

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