annotate src/Modules/BMM/ModuleGammatone.cc @ 121:3cdaa81c3aca

- Massive refactoring to make module tree stuff work. In theory we now support configuration files again. The graphics stuff is untested as yet.
author tomwalters
date Mon, 18 Oct 2010 04:42:28 +0000
parents c5f5e9569863
children 9fcf55c040fe
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@121 55 state_1_[i].clear();
tomwalters@16 56 state_1_[i].resize(3, 0.0f);
tomwalters@121 57 state_2_[i].clear();
tomwalters@16 58 state_2_[i].resize(3, 0.0f);
tomwalters@121 59 state_3_[i].clear();
tomwalters@16 60 state_3_[i].resize(3, 0.0f);
tomwalters@121 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