tomwalters@4: // Copyright 2009-2010, Thomas Walters tomwalters@4: // tomwalters@4: // AIM-C: A C++ implementation of the Auditory Image Model tomwalters@4: // http://www.acousticscale.org/AIMC tomwalters@4: // tomwalters@45: // Licensed under the Apache License, Version 2.0 (the "License"); tomwalters@45: // you may not use this file except in compliance with the License. tomwalters@45: // You may obtain a copy of the License at tomwalters@4: // tomwalters@45: // http://www.apache.org/licenses/LICENSE-2.0 tomwalters@4: // tomwalters@45: // Unless required by applicable law or agreed to in writing, software tomwalters@45: // distributed under the License is distributed on an "AS IS" BASIS, tomwalters@45: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. tomwalters@45: // See the License for the specific language governing permissions and tomwalters@45: // limitations under the License. tomwalters@4: tomwalters@4: /*! \file tomwalters@4: * \brief Slaney's gammatone filterbank tomwalters@4: * tomwalters@4: * \author Thomas Walters tomwalters@4: * \date created 2009/11/13 tomwalters@4: * \version \$Id$ tomwalters@4: */ tomwalters@4: tomwalters@15: #include tomwalters@4: #include tomwalters@5: #include "Support/ERBTools.h" tomwalters@4: tomwalters@4: #include "Modules/BMM/ModuleGammatone.h" tomwalters@4: tomwalters@4: namespace aimc { tomwalters@5: using std::vector; tomwalters@4: using std::complex; tomwalters@4: ModuleGammatone::ModuleGammatone(Parameters *params) : Module(params) { tomwalters@5: module_identifier_ = "gt"; tomwalters@4: module_type_ = "bmm"; tomwalters@4: module_description_ = "Gammatone filterbank (Slaney's IIR gammatone)"; tomwalters@4: module_version_ = "$Id$"; tomwalters@4: tomwalters@4: num_channels_ = parameters_->DefaultInt("gtfb.channel_count", 200); tomwalters@4: min_frequency_ = parameters_->DefaultFloat("gtfb.min_frequency", 86.0f); tomwalters@4: max_frequency_ = parameters_->DefaultFloat("gtfb.max_frequency", 16000.0f); tomwalters@4: } tomwalters@4: tomwalters@5: ModuleGammatone::~ModuleGammatone() { tomwalters@5: } tomwalters@5: tomwalters@5: void ModuleGammatone::ResetInternal() { tomwalters@16: state_1_.resize(num_channels_); tomwalters@16: state_2_.resize(num_channels_); tomwalters@16: state_3_.resize(num_channels_); tomwalters@16: state_4_.resize(num_channels_); tomwalters@5: for (int i = 0; i < num_channels_; ++i) { tomwalters@16: state_1_[i].resize(3, 0.0f); tomwalters@16: state_2_[i].resize(3, 0.0f); tomwalters@16: state_3_[i].resize(3, 0.0f); tomwalters@16: state_4_[i].resize(3, 0.0f); tomwalters@5: } tomwalters@5: } tomwalters@5: tomwalters@4: bool ModuleGammatone::InitializeInternal(const SignalBank& input) { tomwalters@4: // Calculate number of channels, and centre frequencies tomwalters@5: float erb_max = ERBTools::Freq2ERB(max_frequency_); tomwalters@5: float erb_min = ERBTools::Freq2ERB(min_frequency_); tomwalters@5: float delta_erb = (erb_max - erb_min) / (num_channels_ - 1); tomwalters@5: tomwalters@5: centre_frequencies_.resize(num_channels_); tomwalters@5: float erb_current = erb_min; tomwalters@5: tomwalters@16: output_.Initialize(num_channels_, tomwalters@16: input.buffer_length(), tomwalters@16: input.sample_rate()); tomwalters@16: tomwalters@5: for (int i = 0; i < num_channels_; ++i) { tomwalters@8: centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current); tomwalters@8: erb_current += delta_erb; tomwalters@16: output_.set_centre_frequency(i, centre_frequencies_[i]); tomwalters@5: } tomwalters@4: tomwalters@16: a_.resize(num_channels_); tomwalters@16: b1_.resize(num_channels_); tomwalters@16: b2_.resize(num_channels_); tomwalters@16: b3_.resize(num_channels_); tomwalters@16: b4_.resize(num_channels_); tomwalters@16: state_1_.resize(num_channels_); tomwalters@16: state_2_.resize(num_channels_); tomwalters@16: state_3_.resize(num_channels_); tomwalters@16: state_4_.resize(num_channels_); tomwalters@4: tomwalters@4: for (int ch = 0; ch < num_channels_; ++ch) { tomwalters@16: double cf = centre_frequencies_[ch]; tomwalters@16: double erb = ERBTools::Freq2ERBw(cf); tomwalters@18: // LOG_INFO("%e", erb); tomwalters@4: tomwalters@4: // Sample interval tomwalters@16: double dt = 1.0f / input.sample_rate(); tomwalters@4: tomwalters@4: // Bandwidth parameter tomwalters@16: double b = 1.019f * 2.0f * M_PI * erb; tomwalters@4: tomwalters@16: // The following expressions are derived in Apple TR #35, "An tomwalters@8: // Efficient Implementation of the Patterson-Holdsworth Cochlear tomwalters@16: // Filter Bank" and used in Malcolm Slaney's auditory toolbox, where he tomwalters@16: // defines this alternaltive four stage cascade of second-order filters. tomwalters@4: tomwalters@4: // Calculate the gain: tomwalters@16: double cpt = cf * M_PI * dt; tomwalters@16: complex exponent(0.0, 2.0 * cpt); tomwalters@16: complex ec = exp(2.0 * exponent); tomwalters@16: complex two_cf_pi_t(2.0 * cpt, 0.0); tomwalters@16: complex two_pow(pow(2.0, (3.0 / 2.0)), 0.0); tomwalters@18: complex p1 = -2.0 * ec * dt; tomwalters@18: complex p2 = 2.0 * exp(-(b * dt) + exponent) * dt; tomwalters@16: complex b_dt(b * dt, 0.0); tomwalters@4: tomwalters@16: double gain = abs( tomwalters@18: (p1 + p2 * (cos(two_cf_pi_t) - sqrt(3.0 - two_pow) * sin(two_cf_pi_t))) tomwalters@18: * (p1 + p2 * (cos(two_cf_pi_t) + sqrt(3.0 - two_pow) * sin(two_cf_pi_t))) tomwalters@18: * (p1 + p2 * (cos(two_cf_pi_t) - sqrt(3.0 + two_pow) * sin(two_cf_pi_t))) tomwalters@18: * (p1 + p2 * (cos(two_cf_pi_t) + sqrt(3.0 + two_pow) * sin(two_cf_pi_t))) tomwalters@18: / pow((-2.0 / exp(2.0 * b_dt) - 2.0 * ec + 2.0 * (1.0 + ec) tomwalters@18: / exp(b_dt)), 4)); tomwalters@19: // LOG_INFO("%e", gain); tomwalters@4: tomwalters@4: // The filter coefficients themselves: tomwalters@16: const int coeff_count = 3; tomwalters@16: a_[ch].resize(coeff_count, 0.0f); tomwalters@16: b1_[ch].resize(coeff_count, 0.0f); tomwalters@16: b2_[ch].resize(coeff_count, 0.0f); tomwalters@16: b3_[ch].resize(coeff_count, 0.0f); tomwalters@16: b4_[ch].resize(coeff_count, 0.0f); tomwalters@16: state_1_[ch].resize(coeff_count, 0.0f); tomwalters@16: state_2_[ch].resize(coeff_count, 0.0f); tomwalters@16: state_3_[ch].resize(coeff_count, 0.0f); tomwalters@16: state_4_[ch].resize(coeff_count, 0.0f); tomwalters@4: tomwalters@16: double B0 = dt; tomwalters@16: double B2 = 0.0f; tomwalters@4: tomwalters@16: double B11 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) tomwalters@16: + 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt tomwalters@16: * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; tomwalters@16: double B12 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) tomwalters@16: - 2.0f * sqrt(3 + pow(2.0f, 1.5f)) * dt tomwalters@16: * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; tomwalters@16: double B13 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) tomwalters@16: + 2.0f * sqrt(3 - pow(2.0f, 1.5f)) * dt tomwalters@16: * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; tomwalters@16: double B14 = -(2.0f * dt * cos(2.0f * cf * M_PI * dt) / exp(b * dt) tomwalters@16: - 2.0f * sqrt(3 - pow(2.0f, 1.5f)) * dt tomwalters@17: * sin(2.0f * cf * M_PI * dt) / exp(b * dt)) / 2.0f; tomwalters@16: tomwalters@16: a_[ch][0] = 1.0f; tomwalters@16: a_[ch][1] = -2.0f * cos(2.0f * cf * M_PI * dt) / exp(b * dt); tomwalters@16: a_[ch][2] = exp(-2.0f * b * dt); tomwalters@16: b1_[ch][0] = B0 / gain; tomwalters@16: b1_[ch][1] = B11 / gain; tomwalters@16: b1_[ch][2] = B2 / gain; tomwalters@16: b2_[ch][0] = B0; tomwalters@16: b2_[ch][1] = B12; tomwalters@16: b2_[ch][2] = B2; tomwalters@16: b3_[ch][0] = B0; tomwalters@16: b3_[ch][1] = B13; tomwalters@16: b3_[ch][2] = B2; tomwalters@16: b4_[ch][0] = B0; tomwalters@16: b4_[ch][1] = B14; tomwalters@16: b4_[ch][2] = B2; tomwalters@4: } tomwalters@5: return true; tomwalters@4: } tomwalters@5: tomwalters@5: void ModuleGammatone::Process(const SignalBank &input) { tomwalters@5: output_.set_start_time(input.start_time()); tomwalters@5: int audio_channel = 0; tomwalters@5: tomwalters@16: vector >::iterator b1 = b1_.begin(); tomwalters@16: vector >::iterator b2 = b2_.begin(); tomwalters@16: vector >::iterator b3 = b3_.begin(); tomwalters@16: vector >::iterator b4 = b4_.begin(); tomwalters@16: vector >::iterator a = a_.begin(); tomwalters@16: vector >::iterator s1 = state_1_.begin(); tomwalters@16: vector >::iterator s2 = state_2_.begin(); tomwalters@16: vector >::iterator s3 = state_3_.begin(); tomwalters@16: vector >::iterator s4 = state_4_.begin(); tomwalters@5: tomwalters@16: // Temporary storage between filter stages tomwalters@16: vector out(input.buffer_length()); tomwalters@16: for (int ch = 0; ch < num_channels_; tomwalters@16: ++ch, ++b1, ++b2, ++b3, ++b4, ++a, ++s1, ++s2, ++s3, ++s4) { tomwalters@5: for (int i = 0; i < input.buffer_length(); ++i) { tomwalters@8: // Direct-form-II IIR filter tomwalters@16: double in = input.sample(audio_channel, i); tomwalters@16: out[i] = (*b1)[0] * in + (*s1)[0]; tomwalters@16: for (unsigned int stage = 1; stage < s1->size(); ++stage) tomwalters@16: (*s1)[stage - 1] = (*b1)[stage] * in tomwalters@16: - (*a)[stage] * out[i] + (*s1)[stage]; tomwalters@16: } tomwalters@16: for (int i = 0; i < input.buffer_length(); ++i) { tomwalters@16: // Direct-form-II IIR filter tomwalters@16: double in = out[i]; tomwalters@16: out[i] = (*b2)[0] * in + (*s2)[0]; tomwalters@16: for (unsigned int stage = 1; stage < s2->size(); ++stage) tomwalters@16: (*s2)[stage - 1] = (*b2)[stage] * in tomwalters@16: - (*a)[stage] * out[i] + (*s2)[stage]; tomwalters@16: } tomwalters@16: for (int i = 0; i < input.buffer_length(); ++i) { tomwalters@16: // Direct-form-II IIR filter tomwalters@16: double in = out[i]; tomwalters@16: out[i] = (*b3)[0] * in + (*s3)[0]; tomwalters@16: for (unsigned int stage = 1; stage < s3->size(); ++stage) tomwalters@16: (*s3)[stage - 1] = (*b3)[stage] * in tomwalters@16: - (*a)[stage] * out[i] + (*s3)[stage]; tomwalters@16: } tomwalters@16: for (int i = 0; i < input.buffer_length(); ++i) { tomwalters@16: // Direct-form-II IIR filter tomwalters@16: double in = out[i]; tomwalters@16: out[i] = (*b4)[0] * in + (*s4)[0]; tomwalters@16: for (unsigned int stage = 1; stage < s4->size(); ++stage) tomwalters@16: (*s4)[stage - 1] = (*b4)[stage] * in tomwalters@16: - (*a)[stage] * out[i] + (*s4)[stage]; tomwalters@16: output_.set_sample(ch, i, out[i]); tomwalters@5: } tomwalters@5: } tomwalters@5: PushOutput(); tomwalters@5: } tomwalters@5: tomwalters@8: } // namespace aimc