annotate trunk/src/Modules/BMM/ModuleGammatone.cc @ 706:f8e90b5d85fd tip

Delete CARFAC code from this repository. It has been moved to https://github.com/google/carfac Please email me with your github username to get access. I've also created a new mailing list to discuss CARFAC development: https://groups.google.com/forum/#!forum/carfac-dev
author ronw@google.com
date Thu, 18 Jul 2013 20:56:51 +0000
parents 69466da9745e
children
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@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