annotate src/Modules/BMM/ModuleGammatone.cc @ 5:3c782dec2fc0

- Ported over HTK file output - Added some more meat to the Slaney IIR gammatone implementation - Ported over the AIM-MAT sf2003 parabola strobe algorithm - Finished making the SAI implementation compile - Ported over the strobe list class (now uses STL deques internally)
author tomwalters
date Thu, 18 Feb 2010 16:55:40 +0000
parents eb0449575bb9
children fcbf85ce59fb
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@4 6 // This program is free software: you can redistribute it and/or modify
tomwalters@4 7 // it under the terms of the GNU General Public License as published by
tomwalters@4 8 // the Free Software Foundation, either version 3 of the License, or
tomwalters@4 9 // (at your option) any later version.
tomwalters@4 10 //
tomwalters@4 11 // This program is distributed in the hope that it will be useful,
tomwalters@4 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
tomwalters@4 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
tomwalters@4 14 // GNU General Public License for more details.
tomwalters@4 15 //
tomwalters@4 16 // You should have received a copy of the GNU General Public License
tomwalters@4 17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
tomwalters@4 18
tomwalters@4 19 /*! \file
tomwalters@4 20 * \brief Slaney's gammatone filterbank
tomwalters@4 21 *
tomwalters@4 22 * \author Thomas Walters <tom@acousticscale.org>
tomwalters@4 23 * \date created 2009/11/13
tomwalters@4 24 * \version \$Id$
tomwalters@4 25 */
tomwalters@4 26
tomwalters@4 27 #include <complex>
tomwalters@5 28 #include <math.h>
tomwalters@5 29 #include "Support/ERBTools.h"
tomwalters@4 30
tomwalters@4 31 #include "Modules/BMM/ModuleGammatone.h"
tomwalters@4 32
tomwalters@4 33 namespace aimc {
tomwalters@5 34 using std::vector;
tomwalters@4 35 using std::complex;
tomwalters@4 36 ModuleGammatone::ModuleGammatone(Parameters *params) : Module(params) {
tomwalters@5 37 module_identifier_ = "gt";
tomwalters@4 38 module_type_ = "bmm";
tomwalters@4 39 module_description_ = "Gammatone filterbank (Slaney's IIR gammatone)";
tomwalters@4 40 module_version_ = "$Id$";
tomwalters@4 41
tomwalters@4 42 num_channels_ = parameters_->DefaultInt("gtfb.channel_count", 200);
tomwalters@4 43 min_frequency_ = parameters_->DefaultFloat("gtfb.min_frequency", 86.0f);
tomwalters@4 44 max_frequency_ = parameters_->DefaultFloat("gtfb.max_frequency", 16000.0f);
tomwalters@4 45 }
tomwalters@4 46
tomwalters@5 47 ModuleGammatone::~ModuleGammatone() {
tomwalters@5 48 }
tomwalters@5 49
tomwalters@5 50 void ModuleGammatone::ResetInternal() {
tomwalters@5 51 state_.resize(num_channels_);
tomwalters@5 52 for (int i = 0; i < num_channels_; ++i) {
tomwalters@5 53 state_[i].resize(9, 0.0f);
tomwalters@5 54 }
tomwalters@5 55 }
tomwalters@5 56
tomwalters@4 57 bool ModuleGammatone::InitializeInternal(const SignalBank& input) {
tomwalters@4 58 // Calculate number of channels, and centre frequencies
tomwalters@5 59 float erb_max = ERBTools::Freq2ERB(max_frequency_);
tomwalters@5 60 float erb_min = ERBTools::Freq2ERB(min_frequency_);
tomwalters@5 61 float delta_erb = (erb_max - erb_min) / (num_channels_ - 1);
tomwalters@5 62
tomwalters@5 63 centre_frequencies_.resize(num_channels_);
tomwalters@5 64 float erb_current = erb_min;
tomwalters@5 65
tomwalters@5 66 for (int i = 0; i < num_channels_; ++i) {
tomwalters@5 67 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current);
tomwalters@5 68 erb_current += delta_erb;
tomwalters@5 69 }
tomwalters@4 70
tomwalters@4 71 forward_.resize(num_channels_);
tomwalters@5 72 back_.resize(num_channels_);
tomwalters@5 73 state_.resize(num_channels_);
tomwalters@4 74
tomwalters@4 75 for (int ch = 0; ch < num_channels_; ++ch) {
tomwalters@5 76 float cf = centre_frequencies_[ch];
tomwalters@5 77 float erb = ERBTools::Freq2ERBw(cf);
tomwalters@4 78
tomwalters@4 79 // Sample interval
tomwalters@5 80 float dt = 1.0f / input.sample_rate();
tomwalters@4 81
tomwalters@4 82 // Bandwidth parameter
tomwalters@4 83 float b = 1.019f * 2.0f * M_PI * erb;
tomwalters@4 84
tomwalters@4 85 // All of the following expressions are derived in Apple TR #35, "An
tomwalters@4 86 // Efficient Implementation of the Patterson-Holdsworth Cochlear
tomwalters@4 87 // Filter Bank".
tomwalters@4 88
tomwalters@4 89 // Calculate the gain:
tomwalters@5 90 float cpt = cf * M_PI * dt;
tomwalters@5 91 complex<float> exponent(0.0f, 2.0f * cpt);
tomwalters@5 92 complex<float> ec = exp(2.0f * exponent);
tomwalters@5 93 complex<float> two_cf_pi_t(2.0f * cpt, 0.0f);
tomwalters@5 94 complex<float> two_pow(pow(2.0f, (3.0f / 2.0f)), 0.0f);
tomwalters@5 95 complex<float> p = -2.0f * ec * dt
tomwalters@5 96 + 2.0f * exp(-(b * dt) + exponent) * dt;
tomwalters@5 97 complex<float> b_dt(b * dt, 0.0f);
tomwalters@4 98
tomwalters@4 99 float gain = abs(
tomwalters@5 100 (p * (cos(two_cf_pi_t) - sqrt(3.0f - two_pow) * sin(two_cf_pi_t)))
tomwalters@5 101 * (p * (cos(two_cf_pi_t) + sqrt(3.0f - two_pow) * sin(two_cf_pi_t)))
tomwalters@5 102 * (p * (cos(two_cf_pi_t) - sqrt(3.0f + two_pow) * sin(two_cf_pi_t)))
tomwalters@5 103 * (p * (cos(two_cf_pi_t) + sqrt(3.0f + two_pow) * sin(two_cf_pi_t)))
tomwalters@5 104 / pow(-2.0f / exp(2.0f * b_dt) - 2.0f * ec + 2.0f * (1.0f + ec)
tomwalters@5 105 / exp(b_dt), 4.0f));
tomwalters@4 106
tomwalters@4 107 // The filter coefficients themselves:
tomwalters@5 108 const int coeff_count = 9;
tomwalters@5 109 forward_[ch].resize(coeff_count, 0.0f);
tomwalters@5 110 back_[ch].resize(coeff_count, 0.0f);
tomwalters@5 111 state_[ch].resize(coeff_count, 0.0f);
tomwalters@4 112
tomwalters@5 113 forward_[ch][0] = pow(dt, 4.0f) / gain;
tomwalters@5 114 forward_[ch][1] = (-4.0f * pow(dt, 4.0f) * cos(2.0f * cpt)
tomwalters@4 115 / exp(b * dt) / gain);
tomwalters@5 116 forward_[ch][2] = (6.0f * pow(dt, 4.0f) * cos(4.0f * cpt)
tomwalters@4 117 / exp(2.0f * b * dt) / gain);
tomwalters@5 118 forward_[ch][3] = (-4.0f * pow(dt, 4.0f) * cos(6.0f * cpt)
tomwalters@4 119 / exp(3.0f * b * dt) / gain);
tomwalters@5 120 forward_[ch][4] = (pow(dt, 4.0f) * cos(8.0f * cpt)
tomwalters@4 121 / exp(4.0f * b * dt) / gain);
tomwalters@5 122 // Note: the remainder of the forward vector is zero-padded
tomwalters@4 123
tomwalters@5 124 back_[ch][0] = 1.0f;
tomwalters@5 125 back_[ch][1] = -8.0f * cos(2.0f * cpt) / exp(b * dt);
tomwalters@5 126 back_[ch][2] = (4.0f * (4.0f + 3.0f * cos(4.0f * cpt))
tomwalters@5 127 / exp(2.0f * b * dt));
tomwalters@5 128 back_[ch][3] = (-8.0f * (6.0f * cos(2.0f * cpt) + cos(6.0f * cpt))
tomwalters@5 129 / exp(3.0f * b * dt));
tomwalters@5 130 back_[ch][4] = (2.0f * (18.0f + 16.0f * cos(4.0f * cpt) + cos(8.0f * cpt))
tomwalters@5 131 / exp(4.0f * b * dt));
tomwalters@5 132 back_[ch][5] = (-8.0f * (6.0f * cos(2.0f * cpt) + cos(6.0f * cpt))
tomwalters@5 133 / exp(5.0f * b * dt));
tomwalters@5 134 back_[ch][6] = (4.0f * (4.0f + 3.0f * cos(4.0f * cpt))
tomwalters@5 135 / exp(6.0f * b * dt));
tomwalters@5 136 back_[ch][7] = -8.0f * cos(2.0f * cpt) / exp(7.0f * b * dt);
tomwalters@5 137 back_[ch][8] = exp(-8.0f * b * dt);
tomwalters@4 138 }
tomwalters@5 139 output_.Initialize(num_channels_,
tomwalters@5 140 input.buffer_length(),
tomwalters@5 141 input.sample_rate());
tomwalters@5 142 return true;
tomwalters@4 143 }
tomwalters@5 144
tomwalters@5 145 void ModuleGammatone::Process(const SignalBank &input) {
tomwalters@5 146 output_.set_start_time(input.start_time());
tomwalters@5 147 int audio_channel = 0;
tomwalters@5 148
tomwalters@5 149 vector<vector<float> >::iterator b = forward_.begin();
tomwalters@5 150 vector<vector<float> >::iterator a = back_.begin();
tomwalters@5 151 vector<vector<float> >::iterator s = state_.begin();
tomwalters@5 152
tomwalters@5 153 for (int ch = 0; ch < num_channels_; ++ch, ++a, ++b, ++s) {
tomwalters@5 154 for (int i = 0; i < input.buffer_length(); ++i) {
tomwalters@5 155 // Direct-form-II IIR filter
tomwalters@5 156 float in = input.sample(audio_channel, i);
tomwalters@5 157 float out = (*b)[0] * in + (*s)[0];
tomwalters@5 158 for (unsigned int stage = 1; stage < s->size(); ++stage)
tomwalters@5 159 (*s)[stage - 1] = (*b)[stage] * in - (*a)[stage] * out + (*s)[stage];
tomwalters@5 160 output_.set_sample(ch, i, out);
tomwalters@5 161 }
tomwalters@5 162 }
tomwalters@5 163 PushOutput();
tomwalters@5 164 }
tomwalters@5 165
tomwalters@4 166 } // namespace aimc