Mercurial > hg > aimc
comparison trunk/src/Modules/BMM/ModuleGammatone.cc @ 277:6b4921704eb1
- 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 | a57b29e373c7 |
children | e55d0c225a57 |
comparison
equal
deleted
inserted
replaced
276:a57b29e373c7 | 277:6b4921704eb1 |
---|---|
23 * \date created 2009/11/13 | 23 * \date created 2009/11/13 |
24 * \version \$Id$ | 24 * \version \$Id$ |
25 */ | 25 */ |
26 | 26 |
27 #include <complex> | 27 #include <complex> |
28 #include <math.h> | |
29 #include "Support/ERBTools.h" | |
28 | 30 |
29 #include "Modules/BMM/ModuleGammatone.h" | 31 #include "Modules/BMM/ModuleGammatone.h" |
30 | 32 |
31 namespace aimc { | 33 namespace aimc { |
34 using std::vector; | |
32 using std::complex; | 35 using std::complex; |
33 ModuleGammatone::ModuleGammatone(Parameters *params) : Module(params) { | 36 ModuleGammatone::ModuleGammatone(Parameters *params) : Module(params) { |
34 module_identifier_ = "gtfb"; | 37 module_identifier_ = "gt"; |
35 module_type_ = "bmm"; | 38 module_type_ = "bmm"; |
36 module_description_ = "Gammatone filterbank (Slaney's IIR gammatone)"; | 39 module_description_ = "Gammatone filterbank (Slaney's IIR gammatone)"; |
37 module_version_ = "$Id$"; | 40 module_version_ = "$Id$"; |
38 | 41 |
39 num_channels_ = parameters_->DefaultInt("gtfb.channel_count", 200); | 42 num_channels_ = parameters_->DefaultInt("gtfb.channel_count", 200); |
40 min_frequency_ = parameters_->DefaultFloat("gtfb.min_frequency", 86.0f); | 43 min_frequency_ = parameters_->DefaultFloat("gtfb.min_frequency", 86.0f); |
41 max_frequency_ = parameters_->DefaultFloat("gtfb.max_frequency", 16000.0f); | 44 max_frequency_ = parameters_->DefaultFloat("gtfb.max_frequency", 16000.0f); |
42 } | 45 } |
43 | 46 |
47 ModuleGammatone::~ModuleGammatone() { | |
48 } | |
49 | |
50 void ModuleGammatone::ResetInternal() { | |
51 state_.resize(num_channels_); | |
52 for (int i = 0; i < num_channels_; ++i) { | |
53 state_[i].resize(9, 0.0f); | |
54 } | |
55 } | |
56 | |
44 bool ModuleGammatone::InitializeInternal(const SignalBank& input) { | 57 bool ModuleGammatone::InitializeInternal(const SignalBank& input) { |
45 // Calculate number of channels, and centre frequencies | 58 // Calculate number of channels, and centre frequencies |
59 float erb_max = ERBTools::Freq2ERB(max_frequency_); | |
60 float erb_min = ERBTools::Freq2ERB(min_frequency_); | |
61 float delta_erb = (erb_max - erb_min) / (num_channels_ - 1); | |
62 | |
63 centre_frequencies_.resize(num_channels_); | |
64 float erb_current = erb_min; | |
65 | |
66 for (int i = 0; i < num_channels_; ++i) { | |
67 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current); | |
68 erb_current += delta_erb; | |
69 } | |
46 | 70 |
47 forward_.resize(num_channels_); | 71 forward_.resize(num_channels_); |
48 feedback_.resize(num_channels_); | 72 back_.resize(num_channels_); |
73 state_.resize(num_channels_); | |
49 | 74 |
50 for (int ch = 0; ch < num_channels_; ++ch) { | 75 for (int ch = 0; ch < num_channels_; ++ch) { |
51 float erb = Freq2ERBw(cf) | 76 float cf = centre_frequencies_[ch]; |
77 float erb = ERBTools::Freq2ERBw(cf); | |
52 | 78 |
53 // Sample interval | 79 // Sample interval |
54 float dt = 1.0f / fs; | 80 float dt = 1.0f / input.sample_rate(); |
55 | 81 |
56 // Bandwidth parameter | 82 // Bandwidth parameter |
57 float b = 1.019f * 2.0f * M_PI * erb; | 83 float b = 1.019f * 2.0f * M_PI * erb; |
58 | 84 |
59 // All of the following expressions are derived in Apple TR #35, "An | 85 // All of the following expressions are derived in Apple TR #35, "An |
60 // Efficient Implementation of the Patterson-Holdsworth Cochlear | 86 // Efficient Implementation of the Patterson-Holdsworth Cochlear |
61 // Filter Bank". | 87 // Filter Bank". |
62 | 88 |
63 // Calculate the gain: | 89 // Calculate the gain: |
64 complex<float> exponent(0.0f, 2.0f * cf * M_PI * T); | 90 float cpt = cf * M_PI * dt; |
65 complex<float> ec = exp(2.0f * complex_exponent); | 91 complex<float> exponent(0.0f, 2.0f * cpt); |
66 complex<float> two_cf_pi_t(2.0f * cf * M_PI * T, 0.0f); | 92 complex<float> ec = exp(2.0f * exponent); |
67 complex<float> two_pow(pow(2.0f, (3.0f/2.0f)), 0.0f); | 93 complex<float> two_cf_pi_t(2.0f * cpt, 0.0f); |
68 | 94 complex<float> two_pow(pow(2.0f, (3.0f / 2.0f)), 0.0f); |
69 complex<float> p = -2.0f * ec * T + 2.0f * exp(-(B * T) + exponent) * dt; | 95 complex<float> p = -2.0f * ec * dt |
96 + 2.0f * exp(-(b * dt) + exponent) * dt; | |
97 complex<float> b_dt(b * dt, 0.0f); | |
70 | 98 |
71 float gain = abs( | 99 float gain = abs( |
72 (part1 * (cos(two_cf_pi_t) - sqrt(3.0f - twopow) * sin(two_cf_pi_t))) | 100 (p * (cos(two_cf_pi_t) - sqrt(3.0f - two_pow) * sin(two_cf_pi_t))) |
73 * (part1 * (cos(two_cf_pi_t) + sqrt(3.0f - twopow) * sin(two_cf_pi_t))) | 101 * (p * (cos(two_cf_pi_t) + sqrt(3.0f - two_pow) * sin(two_cf_pi_t))) |
74 * (part1 * (cos(two_cf_pi_t) - sqrt(3.0f + twopow) * sin(two_cf_pi_t))) | 102 * (p * (cos(two_cf_pi_t) - sqrt(3.0f + two_pow) * sin(two_cf_pi_t))) |
75 * (part1 * (cos(two_cf_pi_t) + sqrt(3.0f + twopow) * sin(two_cf_pi_t))) | 103 * (p * (cos(two_cf_pi_t) + sqrt(3.0f + two_pow) * sin(two_cf_pi_t))) |
76 / pow(-2.0f / exp(2.0f * b * dt) - 2.0f * ec + 2.0f * (1.0f + ec) | 104 / pow(-2.0f / exp(2.0f * b_dt) - 2.0f * ec + 2.0f * (1.0f + ec) |
77 / exp(b * dt), 4.0f)); | 105 / exp(b_dt), 4.0f)); |
78 | 106 |
79 // The filter coefficients themselves: | 107 // The filter coefficients themselves: |
80 forward[ch].resize(5, 0.0f); | 108 const int coeff_count = 9; |
81 feedback[ch].resize(9, 0.0f); | 109 forward_[ch].resize(coeff_count, 0.0f); |
110 back_[ch].resize(coeff_count, 0.0f); | |
111 state_[ch].resize(coeff_count, 0.0f); | |
82 | 112 |
83 forward[ch][0] = pow(T, 4.0f) / gain; | 113 forward_[ch][0] = pow(dt, 4.0f) / gain; |
84 forward[ch][1] = (-4.0f * pow(T, 4.0f) * cos(2.0f * cf * M_PI * dt) | 114 forward_[ch][1] = (-4.0f * pow(dt, 4.0f) * cos(2.0f * cpt) |
85 / exp(b * dt) / gain); | 115 / exp(b * dt) / gain); |
86 forward[ch][2] = (6.0f * pow(T, 4.0f) * cos(4.0f * cf * M_PI * dt) | 116 forward_[ch][2] = (6.0f * pow(dt, 4.0f) * cos(4.0f * cpt) |
87 / exp(2.0f * b * dt) / gain); | 117 / exp(2.0f * b * dt) / gain); |
88 forward[ch][3] = (-4.0f * pow(T, 4.0f) * cos(6.0f * cf * M_PI * dt) | 118 forward_[ch][3] = (-4.0f * pow(dt, 4.0f) * cos(6.0f * cpt) |
89 / exp(3.0f * b * dt) / gain); | 119 / exp(3.0f * b * dt) / gain); |
90 forward[ch][4] = (pow(T,4.0f) * cos(8.0f * cf * M_PI * dt) | 120 forward_[ch][4] = (pow(dt, 4.0f) * cos(8.0f * cpt) |
91 / exp(4.0f * b * dt) / gain); | 121 / exp(4.0f * b * dt) / gain); |
122 // Note: the remainder of the forward vector is zero-padded | |
92 | 123 |
93 feedback[ch][0] = 1.0f; | 124 back_[ch][0] = 1.0f; |
94 feedback[ch][1] = -8.0f * cos(2.0f * cf * M_PI * T) / exp(b * dt); | 125 back_[ch][1] = -8.0f * cos(2.0f * cpt) / exp(b * dt); |
95 feedback[ch][2] = (4.0f * (4.0f + 3.0f * cos(4.0f * cf * M_PI * dt)) | 126 back_[ch][2] = (4.0f * (4.0f + 3.0f * cos(4.0f * cpt)) |
96 / exp(2.0f * b * dt)); | 127 / exp(2.0f * b * dt)); |
97 feedback[ch][3] = (-8.0f * (6.0f * cos(2.0f * cf * M_PI * dt) | 128 back_[ch][3] = (-8.0f * (6.0f * cos(2.0f * cpt) + cos(6.0f * cpt)) |
98 + cos(6.0f * cf * M_PI * dt)) | 129 / exp(3.0f * b * dt)); |
99 / exp(3.0f * b * dt)); | 130 back_[ch][4] = (2.0f * (18.0f + 16.0f * cos(4.0f * cpt) + cos(8.0f * cpt)) |
100 feedback[ch][4] = (2.0f * (18.0f + 16.0f * cos(4.0f * cf * M_PI * dt) | 131 / exp(4.0f * b * dt)); |
101 + cos(8.0f * cf * M_PI * dt)) | 132 back_[ch][5] = (-8.0f * (6.0f * cos(2.0f * cpt) + cos(6.0f * cpt)) |
102 / exp(4.0f * b * dt)); | 133 / exp(5.0f * b * dt)); |
103 feedback[ch][5] = (-8.0f * (6.0f * cos(2.0f * cf * M_PI * T) | 134 back_[ch][6] = (4.0f * (4.0f + 3.0f * cos(4.0f * cpt)) |
104 + cos(6.0f * cf * M_PI * T)) | 135 / exp(6.0f * b * dt)); |
105 / exp(5.0f * B * T)); | 136 back_[ch][7] = -8.0f * cos(2.0f * cpt) / exp(7.0f * b * dt); |
106 feedback[ch][6] = (4.0f * (4.0f + 3.0f * cos(4.0f * cf * M_PI * T)) | 137 back_[ch][8] = exp(-8.0f * b * dt); |
107 / exp(6.0f * B * T)); | |
108 feedback[ch][7] = -8.0f * cos(2.0f * cf * M_PI * dt) / exp(7.0f * b * dt); | |
109 feedback[ch][8] = exp(-8.0f * b * dt); | |
110 } | 138 } |
139 output_.Initialize(num_channels_, | |
140 input.buffer_length(), | |
141 input.sample_rate()); | |
142 return true; | |
111 } | 143 } |
144 | |
145 void ModuleGammatone::Process(const SignalBank &input) { | |
146 output_.set_start_time(input.start_time()); | |
147 int audio_channel = 0; | |
148 | |
149 vector<vector<float> >::iterator b = forward_.begin(); | |
150 vector<vector<float> >::iterator a = back_.begin(); | |
151 vector<vector<float> >::iterator s = state_.begin(); | |
152 | |
153 for (int ch = 0; ch < num_channels_; ++ch, ++a, ++b, ++s) { | |
154 for (int i = 0; i < input.buffer_length(); ++i) { | |
155 // Direct-form-II IIR filter | |
156 float in = input.sample(audio_channel, i); | |
157 float out = (*b)[0] * in + (*s)[0]; | |
158 for (unsigned int stage = 1; stage < s->size(); ++stage) | |
159 (*s)[stage - 1] = (*b)[stage] * in - (*a)[stage] * out + (*s)[stage]; | |
160 output_.set_sample(ch, i, out); | |
161 } | |
162 } | |
163 PushOutput(); | |
164 } | |
165 | |
112 } // namespace aimc | 166 } // namespace aimc |