Showing the changes to Spectacle/Spectacle-dsp.cpp (1 of 32 files). Show all
Unified · Split
| @@ -0,0 +1,382 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007 John Gibson | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License, version 2, as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | // derived from RTcmix SPECTACLE2.cpp, (C) John Gibson 2005. | ||
| 15 | |||
| 16 | |||
| 17 | #include "Spectacle-dsp.h" | ||
| 18 | #include <float.h> | ||
| 19 | #include <cstddef> | ||
| 20 | |||
| 21 | //#define DEBUG | ||
| 22 | //#define PRINT_DELTIMES | ||
| 23 | //#define PRINT_DELTIME_CHANGES | ||
| 24 | |||
| 25 | #if defined(PRINT_DELTIME_CHANGES) && !defined(PRINT_DELTIMES) | ||
| 26 | #define PRINT_DELTIMES | ||
| 27 | #endif | ||
| 28 | |||
| 29 | const float kMaxDelayTime = 20.0f; | ||
| 30 | #ifdef ANTI_DENORM | ||
| 31 | const float kAntiDenormConstant = 1e-18f; | ||
| 32 | #endif | ||
| 33 | |||
| 34 | |||
| 35 | // ---------------------------------------------------------------- Spectacle_dsp -- | ||
| 36 | Spectacle_dsp::Spectacle_dsp() | ||
| 37 | : _maxdelsamps(0L), _maxdeltime(0.0f), _eqconst(0.0f), _deltimeconst(0.0f), | ||
| 38 | _feedbackconst(0.0f), _delay_minfreq(-FLT_MAX), _delay_maxfreq(-FLT_MAX), | ||
| 39 | _eqtable(NULL), _deltimetable(NULL), _feedbacktable(NULL), | ||
| 40 | _delay_bin_groups(NULL), _delay_binmap_table(NULL), _delay_table_size(0) | ||
| 41 | { | ||
| 42 | #ifdef ANTI_DENORM | ||
| 43 | _antidenorm_offset = kAntiDenormConstant; | ||
| 44 | #endif | ||
| 45 | } | ||
| 46 | |||
| 47 | |||
| 48 | // --------------------------------------------------------------- ~Spectacle_dsp -- | ||
| 49 | Spectacle_dsp::~Spectacle_dsp() | ||
| 50 | { | ||
| 51 | // NB: we don't own the EQ, delay time, and feedback tables. | ||
| 52 | |||
| 53 | for (int i = 0; i < _half_fftlen; i++) { | ||
| 54 | if (_real_delay[i]) | ||
| 55 | delete _real_delay[i]; | ||
| 56 | if (_imag_delay[i]) | ||
| 57 | delete _imag_delay[i]; | ||
| 58 | } | ||
| 59 | |||
| 60 | delete [] _delay_bin_groups; | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | // --------------------------------------------------------------------- init -- | ||
| 65 | // Invoke base init, and perform any initialization specific to this subclass. | ||
| 66 | // Return 0 if okay, -1 if not. | ||
| 67 | |||
| 68 | int Spectacle_dsp::init(int fftlen, int windowlen, int overlap, float srate, | ||
| 69 | float maxdeltime) | ||
| 70 | { | ||
| 71 | if (SpectacleBase::init(fftlen, windowlen, overlap, srate) != 0) | ||
| 72 | return -1; | ||
| 73 | |||
| 74 | // Compute maximum delay lag and create delay lines for FFT real and | ||
| 75 | // imaginary values. Remember that these delays function at the decimation | ||
| 76 | // rate, not at the audio rate, so the memory footprint is not as large | ||
| 77 | // as you would expect -- about 44100 samples per second at fftlen=1024, | ||
| 78 | // overlap=2 and SR=44100. | ||
| 79 | |||
| 80 | _maxdeltime = maxdeltime; | ||
| 81 | _maxdelsamps = long(maxdeltime * get_srate() / float(_decimation) + 0.5); | ||
| 82 | |||
| 83 | for (int i = 0; i < _half_fftlen; i++) { | ||
| 84 | Odelay *delay = new Odelay(_maxdelsamps); | ||
| 85 | if (delay == NULL) | ||
| 86 | goto bad_alloc; | ||
| 87 | _real_delay[i] = delay; | ||
| 88 | delay = new Odelay(_maxdelsamps); | ||
| 89 | if (delay == NULL) | ||
| 90 | goto bad_alloc; | ||
| 91 | _imag_delay[i] = delay; | ||
| 92 | } | ||
| 93 | |||
| 94 | _delay_bin_groups = new int [_half_fftlen]; | ||
| 95 | |||
| 96 | set_delay_freqrange(0.0f, 0.0f); | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | bad_alloc: | ||
| 100 | //error("%s: Not enough memory for delay lines.", instname()); | ||
| 101 | return -1; | ||
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | // -------------------------------------------------------------------- clear -- | ||
| 106 | void Spectacle_dsp::clear() | ||
| 107 | { | ||
| 108 | for (int i = 0; i < _half_fftlen; i++) { | ||
| 109 | _real_delay[i]->clear(); | ||
| 110 | _imag_delay[i]->clear(); | ||
| 111 | } | ||
| 112 | SpectacleBase::clear(); | ||
| 113 | } | ||
| 114 | |||
| 115 | |||
| 116 | // ---------------------------------------------------------------- set_srate -- | ||
| 117 | void Spectacle_dsp::set_srate(float srate) | ||
| 118 | { | ||
| 119 | if (_delay_maxfreq == _nyquist) | ||
| 120 | _delay_maxfreq = 0.0f; | ||
| 121 | SpectacleBase::set_srate(srate); | ||
| 122 | if (_delay_maxfreq == 0.0f) // nyquist might have changed | ||
| 123 | _delay_maxfreq = _nyquist; | ||
| 124 | set_maxdeltime(_maxdeltime); | ||
| 125 | update_bin_groups(_delay_bin_groups, _delay_binmap_table, | ||
| 126 | _delay_minfreq, _delay_maxfreq, _delay_table_size); | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | // ----------------------------------------------------------- set_maxdeltime -- | ||
| 131 | // Reset delay lines to accommodate a maximum delay of <time> seconds at the | ||
| 132 | // current sampling rate. Assumes that caller constrains all delay times to | ||
| 133 | // fit this new maximum. | ||
| 134 | void Spectacle_dsp::set_maxdeltime(float time) | ||
| 135 | { | ||
| 136 | _maxdeltime = time; | ||
| 137 | _maxdelsamps = long(time * get_srate() / float(_decimation) + 0.5); | ||
| 138 | for (int i = 0; i < _half_fftlen; i++) { | ||
| 139 | _real_delay[i]->resize(_maxdelsamps); | ||
| 140 | _imag_delay[i]->resize(_maxdelsamps); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | |||
| 145 | // -------------------------------------------------------------- set_eqtable -- | ||
| 146 | void Spectacle_dsp::set_eqtable(float *table, int len) | ||
| 147 | { | ||
| 148 | if (len == 0) { // no table set yet by caller | ||
| 149 | _eqconst = 0.0; | ||
| 150 | _eqtable = NULL; | ||
| 151 | _control_table_size = 0; | ||
| 152 | } | ||
| 153 | else if (len == 1) { | ||
| 154 | _eqconst = table[0]; | ||
| 155 | _eqtable = NULL; | ||
| 156 | _control_table_size = 0; | ||
| 157 | } | ||
| 158 | else { | ||
| 159 | _eqconst = 0.0; | ||
| 160 | _eqtable = table; | ||
| 161 | if (len != _control_table_size) { | ||
| 162 | _control_table_size = len; | ||
| 163 | update_bin_groups(_bin_groups, NULL, get_minfreq(), get_maxfreq(), | ||
| 164 | _control_table_size); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | |||
| 170 | // ------------------------------------------------------------- set_deltable -- | ||
| 171 | void Spectacle_dsp::set_deltable(float *table, int len) | ||
| 172 | { | ||
| 173 | if (len == 0) { // no table set yet by caller | ||
| 174 | _deltimeconst = 0.0; | ||
| 175 | _deltimetable = NULL; | ||
| 176 | } | ||
| 177 | else if (len == 1) { | ||
| 178 | _deltimeconst = table[0]; | ||
| 179 | _deltimetable = NULL; | ||
| 180 | // NB: don't set _delay_table_size to zero | ||
| 181 | } | ||
| 182 | else { | ||
| 183 | _deltimeconst = 0.0; | ||
| 184 | _deltimetable = table; | ||
| 185 | if (len != _delay_table_size) { | ||
| 186 | _delay_table_size = len; | ||
| 187 | update_bin_groups(_delay_bin_groups, _delay_binmap_table, | ||
| 188 | _delay_minfreq, _delay_maxfreq, _delay_table_size); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | // ------------------------------------------------------------ set_feedtable -- | ||
| 195 | void Spectacle_dsp::set_feedtable(float *table, int len) | ||
| 196 | { | ||
| 197 | if (len == 0) { // no table set yet by caller | ||
| 198 | _feedbackconst = 0.0; | ||
| 199 | _feedbacktable = NULL; | ||
| 200 | } | ||
| 201 | else if (len == 1) { | ||
| 202 | _feedbackconst = table[0]; | ||
| 203 | _feedbacktable = NULL; | ||
| 204 | } | ||
| 205 | else if (len == _delay_table_size) { | ||
| 206 | _feedbackconst = 0.0; | ||
| 207 | _feedbacktable = table; | ||
| 208 | } | ||
| 209 | // else don't do anything -- spectacle_fb_msg insures we never get here | ||
| 210 | } | ||
| 211 | |||
| 212 | |||
| 213 | // ------------------------------------------------------ set_delay_freqrange -- | ||
| 214 | // Similar to set_freqrange in base class, but for _delay_bin_groups. | ||
| 215 | bool Spectacle_dsp::set_delay_freqrange(float min, float max) | ||
| 216 | { | ||
| 217 | if (min != _delay_minfreq || max != _delay_maxfreq) { | ||
| 218 | if (max == 0.0f) | ||
| 219 | max = _nyquist; | ||
| 220 | if (max < min) | ||
| 221 | _fswap(&min, &max); | ||
| 222 | if (max > _nyquist) | ||
| 223 | max = _nyquist; | ||
| 224 | _delay_maxfreq = max; | ||
| 225 | _delay_minfreq = _fclamp(0.0f, min, max); | ||
| 226 | update_bin_groups(_delay_bin_groups, _delay_binmap_table, | ||
| 227 | _delay_minfreq, max, _delay_table_size); | ||
| 228 | return true; | ||
| 229 | } | ||
| 230 | return false; | ||
| 231 | } | ||
| 232 | |||
| 233 | |||
| 234 | // --------------------------------------------------------- set_binmap_table -- | ||
| 235 | // Set pointer to externally allocated table. Pass table=NULL for no table. | ||
| 236 | // <len> must be the same as the current control table size, or else we use | ||
| 237 | // no table, without warning -- responsibility of caller to handle this. | ||
| 238 | |||
| 239 | void Spectacle_dsp::set_binmap_table(int *table, int len) | ||
| 240 | { | ||
| 241 | if (table == NULL || len == 0 || len != _control_table_size) | ||
| 242 | _binmaptable = NULL; | ||
| 243 | else | ||
| 244 | _binmaptable = table; | ||
| 245 | update_bin_groups(_bin_groups, NULL, get_minfreq(), get_maxfreq(), | ||
| 246 | _control_table_size); | ||
| 247 | } | ||
| 248 | |||
| 249 | |||
| 250 | // --------------------------------------------------- set_delay_binmap_table -- | ||
| 251 | // Set pointer to externally allocated table. Pass table=NULL for no table. | ||
| 252 | // <len> must be the same as the current delay table size, or else we use | ||
| 253 | // no table, without warning -- responsibility of caller to handle this. | ||
| 254 | |||
| 255 | void Spectacle_dsp::set_delay_binmap_table(int *table, int len) | ||
| 256 | { | ||
| 257 | if (table == NULL || len == 0 || len != _delay_table_size) | ||
| 258 | _delay_binmap_table = NULL; | ||
| 259 | else | ||
| 260 | _delay_binmap_table = table; | ||
| 261 | update_bin_groups(_delay_bin_groups, _delay_binmap_table, | ||
| 262 | _delay_minfreq, _delay_maxfreq, _delay_table_size); | ||
| 263 | } | ||
| 264 | |||
| 265 | |||
| 266 | // ---------------------------------------------------------- modify_analysis -- | ||
| 267 | void Spectacle_dsp::modify_analysis(bool reading_input) | ||
| 268 | { | ||
| 269 | DPRINT("modify_analysis: ....................."); | ||
| 270 | |||
| 271 | #ifdef PRINT_DELTIMES | ||
| 272 | static float *prevdeltimes = NULL; | ||
| 273 | if (prevdeltimes == NULL) { | ||
| 274 | prevdeltimes = new float [_delay_table_size]; | ||
| 275 | post("\nmodify_analysis: delay times --------------------------"); | ||
| 276 | for (int i = 0; i < _delay_table_size; i++) { | ||
| 277 | prevdeltimes[i] = _deltimetable[i]; | ||
| 278 | post("[%d] %f", i, _deltimetable[i]); | ||
| 279 | } | ||
| 280 | #ifdef PRINT_DELTIME_CHANGES | ||
| 281 | post("\nmodify_analysis: delay time changes -------------------"); | ||
| 282 | #endif | ||
| 283 | } | ||
| 284 | #endif | ||
| 285 | |||
| 286 | const bool posteq = get_posteq(); | ||
| 287 | float eq; | ||
| 288 | |||
| 289 | // NB: check EQ table size, rather than table pointer, to determine whether | ||
| 290 | // we should use an EQ constant. Otherwise, there's a danger we could read | ||
| 291 | // a null EQ table pointer, if set_eqtable called by non-perf thread. | ||
| 292 | if (_control_table_size == 0) | ||
| 293 | eq = _ampdb(_eqconst); | ||
| 294 | |||
| 295 | for (int i = 0; i < _half_fftlen; i++) { | ||
| 296 | int index = i << 1; | ||
| 297 | |||
| 298 | if (_control_table_size > 0) { | ||
| 299 | // EQ uses base class bin groups array. | ||
| 300 | const int bg = _bin_groups[i]; | ||
| 301 | eq = _ampdb(_eqtable[bg]); | ||
| 302 | } | ||
| 303 | |||
| 304 | float real, imag; | ||
| 305 | if (reading_input) { | ||
| 306 | if (posteq) { | ||
| 307 | real = _fft_buf[index]; | ||
| 308 | imag = _fft_buf[index + 1]; | ||
| 309 | } | ||
| 310 | else { | ||
| 311 | real = _fft_buf[index] * eq; | ||
| 312 | imag = _fft_buf[index + 1] * eq; | ||
| 313 | } | ||
| 314 | } | ||
| 315 | else { | ||
| 316 | real = 0.0f; | ||
| 317 | imag = 0.0f; | ||
| 318 | } | ||
| 319 | |||
| 320 | const int bg = _delay_bin_groups[i]; | ||
| 321 | |||
| 322 | // NB: caller must assure that deltime is in range | ||
| 323 | const float deltime = _deltimetable ? _deltimetable[bg] : _deltimeconst; | ||
| 324 | |||
| 325 | #ifdef PRINT_DELTIME_CHANGES | ||
| 326 | if (deltime != prevdeltimes[bg]) { | ||
| 327 | post("[%d] %f", bg, deltime); | ||
| 328 | prevdeltimes[bg] = deltime; | ||
| 329 | } | ||
| 330 | #endif | ||
| 331 | |||
| 332 | if (deltime == 0.0f) { | ||
| 333 | if (posteq) { | ||
| 334 | _fft_buf[index] = real * eq; | ||
| 335 | _fft_buf[index + 1] = imag * eq; | ||
| 336 | } | ||
| 337 | else { | ||
| 338 | _fft_buf[index] = real; | ||
| 339 | _fft_buf[index + 1] = imag; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | else { | ||
| 343 | const long delsamps = long((deltime * get_srate()) + 0.5) | ||
| 344 | / _decimation; | ||
| 345 | const float newreal = _real_delay[i]->getsamp(delsamps); | ||
| 346 | const float newimag = _imag_delay[i]->getsamp(delsamps); | ||
| 347 | const float feedback = _feedbacktable ? _feedbacktable[bg] | ||
| 348 | : _feedbackconst; | ||
| 349 | if (feedback != 0.0) { | ||
| 350 | #ifdef ANTI_DENORM | ||
| 351 | float fbsig = (newreal * feedback) + _antidenorm_offset; | ||
| 352 | _real_delay[i]->putsamp(real + fbsig); | ||
| 353 | fbsig = (newimag * feedback) + _antidenorm_offset; | ||
| 354 | _imag_delay[i]->putsamp(imag + fbsig); | ||
| 355 | #else | ||
| 356 | _real_delay[i]->putsamp(real + (newreal * feedback)); | ||
| 357 | _imag_delay[i]->putsamp(imag + (newimag * feedback)); | ||
| 358 | #endif | ||
| 359 | } | ||
| 360 | else { | ||
| 361 | _real_delay[i]->putsamp(real); | ||
| 362 | _imag_delay[i]->putsamp(imag); | ||
| 363 | } | ||
| 364 | if (posteq) { | ||
| 365 | _fft_buf[index] = newreal * eq; | ||
| 366 | _fft_buf[index + 1] = newimag * eq; | ||
| 367 | } | ||
| 368 | else { | ||
| 369 | _fft_buf[index] = newreal; | ||
| 370 | _fft_buf[index + 1] = newimag; | ||
| 371 | } | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | _fft_buf[1] = 0.0f; // clear Nyquist real value | ||
| 376 | |||
| 377 | #ifdef ANTI_DENORM | ||
| 378 | _antidenorm_offset = -_antidenorm_offset; | ||
| 379 | #endif | ||
| 380 | } | ||
| 381 | |||
| 382 | |||