annotate src/Modules/BMM/ModulePZFC.cc @ 611:0fbaf443ec82

Carfac C++ revision 3, indluding more style improvements. The output structs are now classes again, and have separate storage methods for each output structure along with flags in the Run and RunSegment methods to allow for only storing NAPs if desired.
author alexbrandmeyer
date Fri, 17 May 2013 19:52:45 +0000
parents 988c8b6f7946
children
rev   line source
tomwalters@0 1 // Copyright 2008-2010, Thomas Walters
tomwalters@0 2 //
tomwalters@0 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@0 4 // http://www.acousticscale.org/AIMC
tomwalters@0 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@0 9 //
tomwalters@45 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@0 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@0 17
tomwalters@0 18 /*! \file
tomwalters@0 19 * \brief Dick Lyon's Pole-Zero Filter Cascade - implemented as an AIM-C
tomwalters@0 20 * module by Tom Walters from the AIM-MAT module based on Dick Lyon's code
tomwalters@0 21 */
tomwalters@0 22
tomwalters@0 23 /*! \author Thomas Walters <tom@acousticscale.org>
tomwalters@0 24 * \date created 2008/02/05
tomwalters@23 25 * \version \$Id$
tomwalters@0 26 */
tomwalters@0 27
tomwalters@0 28 #include "Support/ERBTools.h"
tomwalters@0 29
tomwalters@0 30 #include "Modules/BMM/ModulePZFC.h"
tomwalters@0 31
tomwalters@0 32 namespace aimc {
tomwalters@0 33 ModulePZFC::ModulePZFC(Parameters *parameters) : Module(parameters) {
tomwalters@0 34 module_identifier_ = "pzfc";
tomwalters@0 35 module_type_ = "bmm";
tomwalters@0 36 module_description_ = "Pole-Zero Filter Cascade";
tomwalters@23 37 module_version_ = "$Id$";
tomwalters@0 38
tomwalters@0 39 // Get parameter values, setting default values where necessary
tomwalters@0 40 // Each parameter is set here only if it has not already been set elsewhere.
tomwalters@0 41 cf_max_ = parameters_->DefaultFloat("pzfc.highest_frequency", 6000.0f);
tomwalters@0 42 cf_min_ = parameters_->DefaultFloat("pzfc.lowest_frequency", 100.0f);
tomwalters@0 43 pole_damping_ = parameters_->DefaultFloat("pzfc.pole_damping", 0.12f);
tomwalters@0 44 zero_damping_ = parameters_->DefaultFloat("pzfc.zero_damping", 0.2f);
tomwalters@0 45 zero_factor_ = parameters_->DefaultFloat("pzfc.zero_factor", 1.4f);
tomwalters@0 46 step_factor_ = parameters_->DefaultFloat("pzfc.step_factor", 1.0f/3.0f);
tomwalters@0 47 bandwidth_over_cf_ = parameters_->DefaultFloat("pzfc.bandwidth_over_cf",
tomwalters@0 48 0.11f);
tomwalters@0 49 min_bandwidth_hz_ = parameters_->DefaultFloat("pzfc.min_bandwidth_hz",
tomwalters@0 50 27.0f);
tomwalters@0 51 agc_factor_ = parameters_->DefaultFloat("pzfc.agc_factor", 12.0f);
tomwalters@0 52 do_agc_step_ = parameters_->DefaultBool("pzfc.do_agc", true);
tomwalters@47 53 use_fitted_parameters_ = parameters_->DefaultBool("pzfc.use_fit", false);
tomwalters@0 54
tomwalters@0 55 detect_.resize(0);
tomwalters@0 56 }
tomwalters@0 57
tomwalters@0 58 ModulePZFC::~ModulePZFC() {
tomwalters@0 59 }
tomwalters@0 60
tomwalters@0 61 bool ModulePZFC::InitializeInternal(const SignalBank &input) {
tomwalters@0 62 // Make local convenience copies of some variables
tomwalters@0 63 sample_rate_ = input.sample_rate();
tomwalters@0 64 buffer_length_ = input.buffer_length();
tomwalters@0 65 channel_count_ = 0;
tomwalters@0 66
tomwalters@0 67 // Prepare the coefficients and also the output SignalBank
tomwalters@0 68 if (!SetPZBankCoeffs())
tomwalters@0 69 return false;
tomwalters@0 70
tomwalters@0 71 // The output signal bank should be set up by now.
tomwalters@0 72 if (!output_.initialized())
tomwalters@0 73 return false;
tomwalters@0 74
tomwalters@0 75 // This initialises all buffers which can be modified by Process()
tomwalters@3 76 ResetInternal();
tomwalters@0 77
tomwalters@0 78 return true;
tomwalters@0 79 }
tomwalters@0 80
tomwalters@3 81 void ModulePZFC::ResetInternal() {
tomwalters@0 82 // These buffers may be actively modified by the algorithm
tomwalters@0 83 agc_state_.clear();
tomwalters@0 84 agc_state_.resize(channel_count_);
tomwalters@0 85 for (int i = 0; i < channel_count_; ++i) {
tomwalters@0 86 agc_state_[i].clear();
tomwalters@0 87 agc_state_[i].resize(agc_stage_count_, 0.0f);
tomwalters@0 88 }
tomwalters@0 89
tomwalters@0 90 state_1_.clear();
tomwalters@0 91 state_1_.resize(channel_count_, 0.0f);
tomwalters@0 92
tomwalters@0 93 state_2_.clear();
tomwalters@0 94 state_2_.resize(channel_count_, 0.0f);
tomwalters@0 95
tomwalters@0 96 previous_out_.clear();
tomwalters@0 97 previous_out_.resize(channel_count_, 0.0f);
tomwalters@0 98
tomwalters@0 99 pole_damps_mod_.clear();
tomwalters@0 100 pole_damps_mod_.resize(channel_count_, 0.0f);
tomwalters@0 101
tomwalters@0 102 inputs_.clear();
tomwalters@0 103 inputs_.resize(channel_count_, 0.0f);
tomwalters@0 104
tomwalters@0 105 // Init AGC
tomwalters@0 106 AGCDampStep();
tomwalters@0 107 // pole_damps_mod_ and agc_state_ are now be initialized
tomwalters@0 108
tomwalters@0 109 // Modify the pole dampings and AGC state slightly from their values in
tomwalters@0 110 // silence in case the input is abuptly loud.
tomwalters@0 111 for (int i = 0; i < channel_count_; ++i) {
tomwalters@0 112 pole_damps_mod_[i] += 0.05f;
tomwalters@0 113 for (int j = 0; j < agc_stage_count_; ++j)
tomwalters@0 114 agc_state_[i][j] += 0.05f;
tomwalters@0 115 }
tomwalters@0 116
tomwalters@0 117 last_input_ = 0.0f;
tomwalters@0 118 }
tomwalters@0 119
tomwalters@47 120 bool ModulePZFC::SetPZBankCoeffsOrig() {
tomwalters@47 121 // This function sets the following variables:
tomwalters@47 122 // channel_count_
tomwalters@47 123 // pole_dampings_
tomwalters@47 124 // pole_frequencies_
tomwalters@47 125 // za0_, za1_, za2
tomwalters@47 126 // output_
tomwalters@47 127
tomwalters@47 128 // TODO(tomwalters): There's significant code-duplication between this function
tomwalters@47 129 // and SetPZBankCoeffsERBFitted, and SetPZBankCoeffs
tomwalters@47 130
tomwalters@47 131 // Normalised maximum pole frequency
tomwalters@47 132 float pole_frequency = cf_max_ / sample_rate_ * (2.0f * M_PI);
tomwalters@47 133 channel_count_ = 0;
tomwalters@47 134 while ((pole_frequency / (2.0f * M_PI)) * sample_rate_ > cf_min_) {
tomwalters@228 135 float bw = bandwidth_over_cf_ * pole_frequency + 2 * M_PI * min_bandwidth_hz_ / sample_rate_;
tomwalters@47 136 pole_frequency -= step_factor_ * bw;
tomwalters@47 137 channel_count_++;
tomwalters@47 138 }
tomwalters@47 139
tomwalters@47 140 // Now the number of channels is known, various buffers for the filterbank
tomwalters@47 141 // coefficients can be initialised
tomwalters@47 142 pole_dampings_.clear();
tomwalters@47 143 pole_dampings_.resize(channel_count_, pole_damping_);
tomwalters@47 144 pole_frequencies_.clear();
tomwalters@47 145 pole_frequencies_.resize(channel_count_, 0.0f);
tomwalters@47 146
tomwalters@47 147 // Direct-form coefficients
tomwalters@47 148 za0_.clear();
tomwalters@47 149 za0_.resize(channel_count_, 0.0f);
tomwalters@47 150 za1_.clear();
tomwalters@47 151 za1_.resize(channel_count_, 0.0f);
tomwalters@47 152 za2_.clear();
tomwalters@47 153 za2_.resize(channel_count_, 0.0f);
tomwalters@47 154
tomwalters@47 155 // The output signal bank
tomwalters@47 156 output_.Initialize(channel_count_, buffer_length_, sample_rate_);
tomwalters@47 157
tomwalters@47 158 // Reset the pole frequency to maximum
tomwalters@47 159 pole_frequency = cf_max_ / sample_rate_ * (2.0f * M_PI);
tomwalters@47 160
tomwalters@47 161 for (int i = channel_count_ - 1; i > -1; --i) {
tomwalters@47 162 // Store the normalised pole frequncy
tomwalters@47 163 pole_frequencies_[i] = pole_frequency;
tomwalters@47 164
tomwalters@47 165 // Calculate the real pole frequency from the normalised pole frequency
tomwalters@47 166 float frequency = pole_frequency / (2.0f * M_PI) * sample_rate_;
tomwalters@47 167
tomwalters@47 168 // Store the real pole frequency as the 'centre frequency' of the filterbank
tomwalters@47 169 // channel
tomwalters@47 170 output_.set_centre_frequency(i, frequency);
tomwalters@47 171
tom@253 172 float zero_frequency = Minimum(M_PI, zero_factor_ * pole_frequency);
tomwalters@47 173
tomwalters@47 174 // Impulse-invariance mapping
tomwalters@47 175 float z_plane_theta = zero_frequency * sqrt(1.0f - pow(zero_damping_, 2));
tomwalters@47 176 float z_plane_rho = exp(-zero_damping_ * zero_frequency);
tomwalters@47 177
tomwalters@47 178 // Direct-form coefficients from z-plane rho and theta
tomwalters@47 179 float a1 = -2.0f * z_plane_rho * cos(z_plane_theta);
tomwalters@47 180 float a2 = z_plane_rho * z_plane_rho;
tomwalters@47 181
tomwalters@47 182 // Normalised to unity gain at DC
tomwalters@47 183 float a_sum = 1.0f + a1 + a2;
tomwalters@47 184 za0_[i] = 1.0f / a_sum;
tomwalters@47 185 za1_[i] = a1 / a_sum;
tomwalters@47 186 za2_[i] = a2 / a_sum;
tomwalters@47 187
tomwalters@47 188 // Subtract step factor (1/n2) times current bandwidth from the pole
tomwalters@47 189 // frequency
tomwalters@228 190 float bw = bandwidth_over_cf_ * pole_frequency + 2 * M_PI * min_bandwidth_hz_ / sample_rate_;
tomwalters@47 191 pole_frequency -= step_factor_ * bw;
tomwalters@47 192 }
tomwalters@47 193 return true;
tomwalters@47 194 }
tomwalters@47 195
tomwalters@47 196
tomwalters@47 197 bool ModulePZFC::SetPZBankCoeffsERB() {
tomwalters@47 198 // This function sets the following variables:
tomwalters@47 199 // channel_count_
tomwalters@47 200 // pole_dampings_
tomwalters@47 201 // pole_frequencies_
tomwalters@47 202 // za0_, za1_, za2
tomwalters@47 203 // output_
tomwalters@47 204
tomwalters@47 205 // TODO(tomwalters): There's significant code-duplication between here,
tomwalters@47 206 // SetPZBankCoeffsERBFitted, and SetPZBankCoeffs
tomwalters@47 207
tomwalters@47 208 // Normalised maximum pole frequency
tomwalters@47 209 float pole_frequency = cf_max_ / sample_rate_ * (2.0f * M_PI);
tomwalters@47 210 channel_count_ = 0;
tomwalters@47 211 while ((pole_frequency / (2.0f * M_PI)) * sample_rate_ > cf_min_) {
tomwalters@47 212 float bw = ERBTools::Freq2ERBw(pole_frequency
tomwalters@47 213 / (2.0f * M_PI) * sample_rate_);
tomwalters@47 214 pole_frequency -= step_factor_ * (bw * (2.0f * M_PI) / sample_rate_);
tomwalters@47 215 channel_count_++;
tomwalters@47 216 }
tomwalters@47 217
tomwalters@47 218 // Now the number of channels is known, various buffers for the filterbank
tomwalters@47 219 // coefficients can be initialised
tomwalters@47 220 pole_dampings_.clear();
tomwalters@47 221 pole_dampings_.resize(channel_count_, pole_damping_);
tomwalters@47 222 pole_frequencies_.clear();
tomwalters@47 223 pole_frequencies_.resize(channel_count_, 0.0f);
tomwalters@47 224
tomwalters@47 225 // Direct-form coefficients
tomwalters@47 226 za0_.clear();
tomwalters@47 227 za0_.resize(channel_count_, 0.0f);
tomwalters@47 228 za1_.clear();
tomwalters@47 229 za1_.resize(channel_count_, 0.0f);
tomwalters@47 230 za2_.clear();
tomwalters@47 231 za2_.resize(channel_count_, 0.0f);
tomwalters@47 232
tomwalters@47 233 // The output signal bank
tomwalters@47 234 output_.Initialize(channel_count_, buffer_length_, sample_rate_);
tomwalters@47 235
tomwalters@47 236 // Reset the pole frequency to maximum
tomwalters@47 237 pole_frequency = cf_max_ / sample_rate_ * (2.0f * M_PI);
tomwalters@47 238
tomwalters@47 239 for (int i = channel_count_ - 1; i > -1; --i) {
tomwalters@47 240 // Store the normalised pole frequncy
tomwalters@47 241 pole_frequencies_[i] = pole_frequency;
tomwalters@47 242
tomwalters@47 243 // Calculate the real pole frequency from the normalised pole frequency
tomwalters@47 244 float frequency = pole_frequency / (2.0f * M_PI) * sample_rate_;
tomwalters@47 245
tomwalters@47 246 // Store the real pole frequency as the 'centre frequency' of the filterbank
tomwalters@47 247 // channel
tomwalters@47 248 output_.set_centre_frequency(i, frequency);
tomwalters@47 249
tomwalters@228 250 float zero_frequency = Minimum(M_PI, zero_factor_ * pole_frequency);
tomwalters@47 251
tomwalters@47 252 // Impulse-invariance mapping
tomwalters@47 253 float z_plane_theta = zero_frequency * sqrt(1.0f - pow(zero_damping_, 2));
tomwalters@47 254 float z_plane_rho = exp(-zero_damping_ * zero_frequency);
tomwalters@47 255
tomwalters@47 256 // Direct-form coefficients from z-plane rho and theta
tomwalters@47 257 float a1 = -2.0f * z_plane_rho * cos(z_plane_theta);
tomwalters@47 258 float a2 = z_plane_rho * z_plane_rho;
tomwalters@47 259
tomwalters@47 260 // Normalised to unity gain at DC
tomwalters@47 261 float a_sum = 1.0f + a1 + a2;
tomwalters@47 262 za0_[i] = 1.0f / a_sum;
tomwalters@47 263 za1_[i] = a1 / a_sum;
tomwalters@47 264 za2_[i] = a2 / a_sum;
tomwalters@47 265
tomwalters@47 266 float bw = ERBTools::Freq2ERBw(pole_frequency
tomwalters@47 267 / (2.0f * M_PI) * sample_rate_);
tomwalters@47 268 pole_frequency -= step_factor_ * (bw * (2.0f * M_PI) / sample_rate_);
tomwalters@47 269 }
tomwalters@47 270 return true;
tomwalters@47 271 }
tomwalters@47 272
tomwalters@0 273 bool ModulePZFC::SetPZBankCoeffsERBFitted() {
tomwalters@47 274 //float parameter_values[3 * 7] = {
tomwalters@47 275 //// Filed, Nfit = 524, 11-3 parameters, PZFC, cwt 0, fit time 9915 sec
tomwalters@47 276 //1.14827, 0.00000, 0.00000, // % SumSqrErr= 10125.41
tomwalters@47 277 //0.53571, -0.70128, 0.63246, // % RMSErr = 2.81586
tomwalters@47 278 //0.76779, 0.00000, 0.00000, // % MeanErr = 0.00000
tomwalters@47 279 //// Inf 0.00000 0.00000 % RMSCost = NaN
tomwalters@47 280 //0.00000, 0.00000, 0.00000,
tomwalters@47 281 //6.00000, 0.00000, 0.00000,
tomwalters@47 282 //1.08869, -0.09470, 0.07844,
tomwalters@47 283 //10.56432, 2.52732, 1.86895
tomwalters@47 284 //// -3.45865 -1.31457 3.91779 % Kv
tomwalters@47 285 //};
tomwalters@47 286
tomwalters@0 287 float parameter_values[3 * 7] = {
tomwalters@47 288 // Fit 515 from Dick
tomwalters@47 289 // Final, Nfit = 515, 9-3 parameters, PZFC, cwt 0
tomwalters@47 290 1.72861, 0.00000, 0.00000, // SumSqrErr = 13622.24
tomwalters@47 291 0.56657, -0.93911, 0.89163, // RMSErr = 3.26610
tomwalters@47 292 0.39469, 0.00000, 0.00000, // MeanErr = 0.00000
tomwalters@47 293 // Inf, 0.00000, 0.00000, // RMSCost = NaN - would set coefc to infinity, but this isn't passed on
tomwalters@47 294 0.00000, 0.00000, 0.00000,
tomwalters@47 295 2.00000, 0.00000, 0.00000, //
tomwalters@47 296 1.27393, 0.00000, 0.00000,
tomwalters@47 297 11.46247, 5.46894, 0.11800
tomwalters@47 298 // -4.15525, 1.54874, 2.99858 // Kv
tomwalters@0 299 };
tomwalters@0 300
tomwalters@0 301 // Precalculate the number of channels required - this method is ugly but it
tomwalters@0 302 // was the quickest way of converting from MATLAB as the step factor between
tomwalters@0 303 // channels can vary quadratically with pole frequency...
tomwalters@0 304
tomwalters@0 305 // Normalised maximum pole frequency
tomwalters@0 306 float pole_frequency = cf_max_ / sample_rate_ * (2.0f * M_PI);
tomwalters@0 307
tomwalters@0 308 channel_count_ = 0;
tomwalters@0 309 while ((pole_frequency / (2.0f * M_PI)) * sample_rate_ > cf_min_) {
tomwalters@0 310 float frequency = pole_frequency / (2.0f * M_PI) * sample_rate_;
tomwalters@0 311 float f_dep = ERBTools::Freq2ERB(frequency)
tomwalters@0 312 / ERBTools::Freq2ERB(1000.0f) - 1.0f;
tomwalters@0 313 float bw = ERBTools::Freq2ERBw(pole_frequency
tomwalters@0 314 / (2.0f * M_PI) * sample_rate_);
tomwalters@0 315 float step_factor = 1.0f
tomwalters@0 316 / (parameter_values[4*3] + parameter_values[4 * 3 + 1]
tomwalters@0 317 * f_dep + parameter_values[4 * 3 + 2] * f_dep * f_dep); // 1/n2
tomwalters@0 318 pole_frequency -= step_factor * (bw * (2.0f * M_PI) / sample_rate_);
tomwalters@0 319 channel_count_++;
tomwalters@0 320 }
tomwalters@0 321
tomwalters@0 322 // Now the number of channels is known, various buffers for the filterbank
tomwalters@0 323 // coefficients can be initialised
tomwalters@0 324 pole_dampings_.clear();
tomwalters@0 325 pole_dampings_.resize(channel_count_, 0.0f);
tomwalters@0 326 pole_frequencies_.clear();
tomwalters@0 327 pole_frequencies_.resize(channel_count_, 0.0f);
tomwalters@0 328
tomwalters@0 329 // Direct-form coefficients
tomwalters@0 330 za0_.clear();
tomwalters@0 331 za0_.resize(channel_count_, 0.0f);
tomwalters@0 332 za1_.clear();
tomwalters@0 333 za1_.resize(channel_count_, 0.0f);
tomwalters@0 334 za2_.clear();
tomwalters@0 335 za2_.resize(channel_count_, 0.0f);
tomwalters@0 336
tomwalters@0 337 // The output signal bank
tomwalters@0 338 output_.Initialize(channel_count_, buffer_length_, sample_rate_);
tomwalters@0 339
tomwalters@0 340 // Reset the pole frequency to maximum
tomwalters@0 341 pole_frequency = cf_max_ / sample_rate_ * (2.0f * M_PI);
tomwalters@0 342
tomwalters@0 343 for (int i = channel_count_ - 1; i > -1; --i) {
tomwalters@0 344 // Store the normalised pole frequncy
tomwalters@0 345 pole_frequencies_[i] = pole_frequency;
tomwalters@0 346
tomwalters@0 347 // Calculate the real pole frequency from the normalised pole frequency
tomwalters@0 348 float frequency = pole_frequency / (2.0f * M_PI) * sample_rate_;
tomwalters@0 349
tomwalters@0 350 // Store the real pole frequency as the 'centre frequency' of the filterbank
tomwalters@0 351 // channel
tomwalters@0 352 output_.set_centre_frequency(i, frequency);
tomwalters@0 353
tomwalters@0 354 // From PZFC_Small_Signal_Params.m { From PZFC_Params.m {
tomwalters@0 355 float DpndF = ERBTools::Freq2ERB(frequency)
tomwalters@0 356 / ERBTools::Freq2ERB(1000.0f) - 1.0f;
tomwalters@0 357
tomwalters@0 358 float p[8]; // Parameters (short name for ease of reading)
tomwalters@0 359
tomwalters@0 360 // Use parameter_values to recover the parameter values for this frequency
tomwalters@0 361 for (int param = 0; param < 7; ++param)
tomwalters@0 362 p[param] = parameter_values[param * 3]
tomwalters@0 363 + parameter_values[param * 3 + 1] * DpndF
tomwalters@0 364 + parameter_values[param * 3 + 2] * DpndF * DpndF;
tomwalters@0 365
tomwalters@0 366 // Calculate the final parameter
tomwalters@0 367 p[7] = p[1] * pow(10.0f, (p[2] / (p[1] * p[4])) * (p[6] - 60.0f) / 20.0f);
tomwalters@0 368 if (p[7] < 0.2f)
tomwalters@0 369 p[7] = 0.2f;
tomwalters@0 370
tomwalters@0 371 // Nominal bandwidth at this frequency
tomwalters@0 372 float fERBw = ERBTools::Freq2ERBw(frequency);
tomwalters@0 373
tomwalters@0 374 // Pole bandwidth
tomwalters@0 375 float fPBW = ((p[7] * fERBw * (2 * M_PI) / sample_rate_) / 2)
tomwalters@0 376 * pow(p[4], 0.5f);
tomwalters@0 377
tomwalters@0 378 // Pole damping
tomwalters@0 379 float pole_damping = fPBW / sqrt(pow(pole_frequency, 2) + pow(fPBW, 2));
tomwalters@0 380
tomwalters@0 381 // Store the pole damping
tomwalters@0 382 pole_dampings_[i] = pole_damping;
tomwalters@0 383
tomwalters@0 384 // Zero bandwidth
tomwalters@0 385 float fZBW = ((p[0] * p[5] * fERBw * (2 * M_PI) / sample_rate_) / 2)
tomwalters@0 386 * pow(p[4], 0.5f);
tomwalters@0 387
tomwalters@0 388 // Zero frequency
tomwalters@0 389 float zero_frequency = p[5] * pole_frequency;
tomwalters@0 390
tomwalters@0 391 if (zero_frequency > M_PI)
tomwalters@0 392 LOG_ERROR(_T("Warning: Zero frequency is above the Nyquist frequency "
tomwalters@0 393 "in ModulePZFC(), continuing anyway but results may not "
tomwalters@0 394 "be accurate."));
tomwalters@0 395
tomwalters@0 396 // Zero damping
tomwalters@0 397 float fZDamp = fZBW / sqrt(pow(zero_frequency, 2) + pow(fZBW, 2));
tomwalters@0 398
tomwalters@0 399 // Impulse-invariance mapping
tomwalters@0 400 float fZTheta = zero_frequency * sqrt(1.0f - pow(fZDamp, 2));
tomwalters@0 401 float fZRho = exp(-fZDamp * zero_frequency);
tomwalters@0 402
tomwalters@0 403 // Direct-form coefficients
tomwalters@0 404 float fA1 = -2.0f * fZRho * cos(fZTheta);
tomwalters@0 405 float fA2 = fZRho * fZRho;
tomwalters@0 406
tomwalters@0 407 // Normalised to unity gain at DC
tomwalters@0 408 float fASum = 1.0f + fA1 + fA2;
tomwalters@0 409 za0_[i] = 1.0f / fASum;
tomwalters@0 410 za1_[i] = fA1 / fASum;
tomwalters@0 411 za2_[i] = fA2 / fASum;
tomwalters@0 412
tomwalters@0 413 // Subtract step factor (1/n2) times current bandwidth from the pole
tomwalters@0 414 // frequency
tomwalters@0 415 pole_frequency -= ((1.0f / p[4])
tomwalters@0 416 * (fERBw * (2.0f * M_PI) / sample_rate_));
tomwalters@0 417 }
tomwalters@0 418 return true;
tomwalters@0 419 }
tomwalters@0 420
tomwalters@0 421 bool ModulePZFC::SetPZBankCoeffs() {
tomwalters@0 422 /*! \todo Re-implement the alternative parameter settings
tomwalters@0 423 */
tomwalters@47 424 if (use_fitted_parameters_) {
tomwalters@47 425 if (!SetPZBankCoeffsERBFitted())
tomwalters@47 426 return false;
tomwalters@47 427 } else {
tomwalters@47 428 if (!SetPZBankCoeffsOrig())
tomwalters@228 429 return false;
tomwalters@47 430 }
tomwalters@0 431
tomwalters@0 432 /*! \todo Make fMindamp and fMaxdamp user-settable?
tomwalters@0 433 */
tomwalters@0 434 mindamp_ = 0.18f;
tomwalters@0 435 maxdamp_ = 0.4f;
tomwalters@0 436
tomwalters@0 437 rmin_.resize(channel_count_);
tomwalters@0 438 rmax_.resize(channel_count_);
tomwalters@0 439 xmin_.resize(channel_count_);
tomwalters@0 440 xmax_.resize(channel_count_);
tomwalters@0 441
tomwalters@0 442 for (int c = 0; c < channel_count_; ++c) {
tomwalters@0 443 // Calculate maximum and minimum damping options
tomwalters@0 444 rmin_[c] = exp(-mindamp_ * pole_frequencies_[c]);
tomwalters@0 445 rmax_[c] = exp(-maxdamp_ * pole_frequencies_[c]);
tomwalters@0 446
tomwalters@0 447 xmin_[c] = rmin_[c] * cos(pole_frequencies_[c]
tomwalters@0 448 * pow((1-pow(mindamp_, 2)), 0.5f));
tomwalters@0 449 xmax_[c] = rmax_[c] * cos(pole_frequencies_[c]
tomwalters@0 450 * pow((1-pow(maxdamp_, 2)), 0.5f));
tomwalters@0 451 }
tomwalters@0 452
tomwalters@0 453 // Set up AGC parameters
tomwalters@0 454 agc_stage_count_ = 4;
tomwalters@0 455 agc_epsilons_.resize(agc_stage_count_);
tomwalters@0 456 agc_epsilons_[0] = 0.0064f;
tomwalters@0 457 agc_epsilons_[1] = 0.0016f;
tomwalters@0 458 agc_epsilons_[2] = 0.0004f;
tomwalters@0 459 agc_epsilons_[3] = 0.0001f;
tomwalters@0 460
tomwalters@0 461 agc_gains_.resize(agc_stage_count_);
tomwalters@0 462 agc_gains_[0] = 1.0f;
tomwalters@0 463 agc_gains_[1] = 1.4f;
tomwalters@0 464 agc_gains_[2] = 2.0f;
tomwalters@0 465 agc_gains_[3] = 2.8f;
tomwalters@0 466
tomwalters@0 467 float mean_agc_gain = 0.0f;
tomwalters@0 468 for (int c = 0; c < agc_stage_count_; ++c)
tomwalters@0 469 mean_agc_gain += agc_gains_[c];
tomwalters@0 470 mean_agc_gain /= static_cast<float>(agc_stage_count_);
tomwalters@0 471
tomwalters@0 472 for (int c = 0; c < agc_stage_count_; ++c)
tomwalters@0 473 agc_gains_[c] /= mean_agc_gain;
tomwalters@0 474
tomwalters@0 475 return true;
tomwalters@0 476 }
tomwalters@0 477
tomwalters@0 478 void ModulePZFC::AGCDampStep() {
tomwalters@0 479 if (detect_.size() == 0) {
tomwalters@0 480 // If detect_ is not initialised, it means that the AGC is not set up.
tomwalters@0 481 // Set up now.
tomwalters@0 482 /*! \todo Make a separate InitAGC function which does this.
tomwalters@0 483 */
tomwalters@44 484 detect_.clear();
tomwalters@44 485 float detect_zero = DetectFun(0.0f);
tomwalters@44 486 detect_.resize(channel_count_, detect_zero);
tomwalters@0 487
tomwalters@0 488 for (int c = 0; c < channel_count_; c++)
tomwalters@0 489 for (int st = 0; st < agc_stage_count_; st++)
tomwalters@0 490 agc_state_[c][st] = (1.2f * detect_[c] * agc_gains_[st]);
tomwalters@0 491 }
tomwalters@0 492
tomwalters@0 493 float fAGCEpsLeft = 0.3f;
tomwalters@0 494 float fAGCEpsRight = 0.3f;
tomwalters@0 495
tomwalters@0 496 for (int c = channel_count_ - 1; c > -1; --c) {
tomwalters@0 497 for (int st = 0; st < agc_stage_count_; ++st) {
tomwalters@0 498 // This bounds checking is ugly and wasteful, and in an inner loop.
tomwalters@0 499 // If this algorithm is slow, this is why!
tomwalters@0 500 /*! \todo Proper non-ugly bounds checking in AGCDampStep()
tomwalters@0 501 */
tomwalters@0 502 float fPrevAGCState;
tomwalters@0 503 float fCurrAGCState;
tomwalters@0 504 float fNextAGCState;
tomwalters@0 505
tomwalters@0 506 if (c < channel_count_ - 1)
tomwalters@0 507 fPrevAGCState = agc_state_[c + 1][st];
tomwalters@0 508 else
tomwalters@0 509 fPrevAGCState = agc_state_[c][st];
tomwalters@0 510
tomwalters@0 511 fCurrAGCState = agc_state_[c][st];
tomwalters@0 512
tomwalters@0 513 if (c > 0)
tomwalters@0 514 fNextAGCState = agc_state_[c - 1][st];
tomwalters@0 515 else
tomwalters@0 516 fNextAGCState = agc_state_[c][st];
tomwalters@0 517
tomwalters@0 518 // Spatial smoothing
tomwalters@0 519 /*! \todo Something odd is going on here
tomwalters@0 520 * I think this line is not quite right.
tomwalters@0 521 */
tomwalters@0 522 float agc_avg = fAGCEpsLeft * fPrevAGCState
tomwalters@0 523 + (1.0f - fAGCEpsLeft - fAGCEpsRight) * fCurrAGCState
tomwalters@0 524 + fAGCEpsRight * fNextAGCState;
tomwalters@0 525 // Temporal smoothing
tomwalters@0 526 agc_state_[c][st] = agc_avg * (1.0f - agc_epsilons_[st])
tomwalters@0 527 + agc_epsilons_[st] * detect_[c] * agc_gains_[st];
tomwalters@0 528 }
tomwalters@0 529 }
tomwalters@0 530
tomwalters@44 531 float offset = 1.0f - agc_factor_ * DetectFun(0.0f);
tomwalters@0 532
tomwalters@0 533 for (int i = 0; i < channel_count_; ++i) {
tomwalters@0 534 float fAGCStateMean = 0.0f;
tomwalters@0 535 for (int j = 0; j < agc_stage_count_; ++j)
tomwalters@0 536 fAGCStateMean += agc_state_[i][j];
tomwalters@0 537
tomwalters@0 538 fAGCStateMean /= static_cast<float>(agc_stage_count_);
tomwalters@0 539
tomwalters@0 540 pole_damps_mod_[i] = pole_dampings_[i] *
tomwalters@44 541 (offset + agc_factor_ * fAGCStateMean);
tomwalters@0 542 }
tomwalters@0 543 }
tomwalters@0 544
tomwalters@0 545 float ModulePZFC::DetectFun(float fIN) {
tomwalters@0 546 if (fIN < 0.0f)
tomwalters@0 547 fIN = 0.0f;
tomwalters@0 548 float fDetect = Minimum(1.0f, fIN);
tomwalters@0 549 float fA = 0.25f;
tomwalters@0 550 return fA * fIN + (1.0f - fA) * (fDetect - pow(fDetect, 3) / 3.0f);
tomwalters@0 551 }
tomwalters@0 552
tomwalters@0 553 inline float ModulePZFC::Minimum(float a, float b) {
tomwalters@0 554 if (a < b)
tomwalters@0 555 return a;
tomwalters@0 556 else
tomwalters@0 557 return b;
tomwalters@0 558 }
tomwalters@0 559
tomwalters@0 560 void ModulePZFC::Process(const SignalBank& input) {
tomwalters@0 561 // Set the start time of the output buffer
tomwalters@0 562 output_.set_start_time(input.start_time());
tomwalters@0 563
tomwalters@44 564 for (int s = 0; s < input.buffer_length(); ++s) {
tomwalters@44 565 float input_sample = input.sample(0, s);
tomwalters@0 566
tomwalters@0 567 // Lowpass filter the input with a zero at PI
tomwalters@44 568 input_sample = 0.5f * input_sample + 0.5f * last_input_;
tomwalters@44 569 last_input_ = input.sample(0, s);
tomwalters@0 570
tomwalters@44 571 inputs_[channel_count_ - 1] = input_sample;
tomwalters@0 572 for (int c = 0; c < channel_count_ - 1; ++c)
tomwalters@0 573 inputs_[c] = previous_out_[c + 1];
tomwalters@0 574
tomwalters@0 575 // PZBankStep2
tomwalters@0 576 // to save a bunch of divides
tomwalters@0 577 float damp_rate = 1.0f / (maxdamp_ - mindamp_);
tomwalters@0 578
tomwalters@0 579 for (int c = channel_count_ - 1; c > -1; --c) {
tomwalters@44 580 float interp_factor = (pole_damps_mod_[c] - mindamp_) * damp_rate;
tomwalters@0 581
tomwalters@0 582 float x = xmin_[c] + (xmax_[c] - xmin_[c]) * interp_factor;
tomwalters@0 583 float r = rmin_[c] + (rmax_[c] - rmin_[c]) * interp_factor;
tomwalters@0 584
tomwalters@0 585 // optional improvement to constellation adds a bit to r
tomwalters@0 586 float fd = pole_frequencies_[c] * pole_damps_mod_[c];
tomwalters@0 587 // quadratic for small values, then linear
tomwalters@0 588 r = r + 0.25f * fd * Minimum(0.05f, fd);
tomwalters@0 589
tomwalters@0 590 float zb1 = -2.0f * x;
tomwalters@0 591 float zb2 = r * r;
tomwalters@0 592
tomwalters@0 593 /* canonic poles but with input provided where unity DC gain is assured
tomwalters@0 594 * (mean value of state is always equal to mean value of input)
tomwalters@0 595 */
tomwalters@0 596 float new_state = inputs_[c] - (state_1_[c] - inputs_[c]) * zb1
tomwalters@0 597 - (state_2_[c] - inputs_[c]) * zb2;
tomwalters@0 598
tomwalters@0 599 // canonic zeros part as before:
tomwalters@0 600 float output = za0_[c] * new_state + za1_[c] * state_1_[c]
tomwalters@0 601 + za2_[c] * state_2_[c];
tomwalters@0 602
tomwalters@0 603 // cubic compression nonlinearity
tomwalters@44 604 output -= 0.0001f * pow(output, 3);
tomwalters@0 605
tomwalters@44 606 output_.set_sample(c, s, output);
tomwalters@0 607 detect_[c] = DetectFun(output);
tomwalters@0 608 state_2_[c] = state_1_[c];
tomwalters@0 609 state_1_[c] = new_state;
tomwalters@0 610 }
tomwalters@0 611
tomwalters@0 612 if (do_agc_step_)
tomwalters@0 613 AGCDampStep();
tomwalters@0 614
tomwalters@0 615 for (int c = 0; c < channel_count_; ++c)
tomwalters@44 616 previous_out_[c] = output_[c][s];
tomwalters@0 617 }
tomwalters@0 618 PushOutput();
tomwalters@0 619 }
tomwalters@0 620 } // namespace aimc