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 | + | |