// ---------------------------------------------------------------- subupdate -- void SPECTEQ2::subupdate() { // NB: update EQ table, so that live table draw will work double p[15]; update(p, 15, 1 << 3 | 1 << 8 | 1 << 9 | 1 << 10 | 1 << 12 | 1 << 14); set_oamp(p[3]); set_freqrange(p[9], p[10], "EQ"); set_wet(bool(p[12]) ? 0.0f : 1.0f); if (_nargs > 14) set_pan(p[14]); }
// ---------------------------------------------------------------- subupdate -- void SPECTACLE2::subupdate() { // NB: update EQ, deltime, fdback tables, so that live table draw will work, // and so that we can retrieve changing monolithic values instead of tables. // NB: input amp is updated in base class. double p[21]; update(p, 21, 1 << 3 | 1 << 10 | 1 << 11 | 1 << 12 | 1 << 13 | 1 << 14 | 1 << 15 | 1 << 16 | 1 << 18 | 1 << 20); set_oamp(p[3]); set_eq_freqrange(p[13], p[14]); set_freqrange(p[15], p[16]); if (_nargs > 18) set_wet(p[18]); if (_nargs > 20) set_pan(p[20]); if (_eqtable == NULL) _eqconst = p[10]; if (_deltimetable == NULL) _deltimeconst = p[11]; if (_feedbacktable == NULL) _feedbackconst = p[12]; }
int SPECTACLE2::subinit(double p[], int n_args) { _eqtable = (double *) getPFieldTable(10, &_eqtablen); if (!_eqtable) _eqconst = p[10]; int deltimetablen; _deltimetable = (double *) getPFieldTable(11, &deltimetablen); if (!_deltimetable) _deltimeconst = p[11]; // read later in this function int feedbacktablen; _feedbacktable = (double *) getPFieldTable(12, &feedbacktablen); if (!_feedbacktable) _feedbackconst = p[12]; // Delay and feedback tables, if they exist, must be the same size. int cntltablen = 0; if (_deltimetable) cntltablen = deltimetablen; if (_feedbacktable) { cntltablen = feedbacktablen; if (_deltimetable && (feedbacktablen != deltimetablen)) return die(instname(), "Delay time and feedback tables must be the " "same size."); } _control_table_size = cntltablen; int binmaptablen; double *binmaptable = (double *) getPFieldTable(17, &binmaptablen); if (binmaptable) { if (binmaptablen != _eqtablen || binmaptablen != _control_table_size) die(instname(), "The bin-mapping table (p17) must be the same size as " "the EQ and delay tables (p10-12)."); set_binmap_table(binmaptable); if (p[13] != 0.0 || (p[14] != 0.0 || p[14] != _nyquist) || p[15] != 0.0 || (p[16] != 0.0 || p[16] != _nyquist)) rtcmix_warn(instname(), "Use of the bin-mapping table ignores the freq. " "ranges set in p13-16."); } // Init delay minfreq and maxfreq, so that bin groups will be ready for use // below. This calls update_bin_groups, which reads _control_table_size. set_freqrange(p[15], p[16]); // Compute maximum delay lag and create delay lines for FFT magnitude // and phase values. Make ringdur at least as long as the longest // delay time. Remember that these delays function at the decimation // rate, not at the audio rate, so the memory footprint is not as large // as you would expect -- about 44100 samples per second at fftlen=1024, // overlap=2 and SR=44100. // Set max delay time and bounds-check initial state of delay time array. // Also increase ringdur to accommodate longest delay time, if necessary. // Note that if user updates delay time table while running, values are // pinned to max delay time without notification. _maxdelsamps = long(kMaxDelayTime * SR / float(_decimation) + 0.5); float maxtime = 0.0f; float deltime = _deltimeconst; for (int i = 0; i <= _half_fftlen; i++) { if (_deltimetable) deltime = _deltimetable[_bin_groups[i]]; if (deltime < 0.0f || deltime > kMaxDelayTime) return die(instname(), "Delay times must be between 0 and %g seconds.", kMaxDelayTime); if (deltime > maxtime) maxtime = deltime; } float ringdur = p[5]; if (ringdur < maxtime) ringdur = maxtime; // but will still cut off any trailing feedback set_ringdur(ringdur); DPRINT3("decimation=%d, _maxdelsamps=%ld, ringdur=%g\n", _decimation, _maxdelsamps, ringdur); return 0; }
// --------------------------------------------------------------------- init -- int SpectacleBase::init(int fftlen, int windowlen, int overlap, float srate) { _fftlen = fftlen; _window_len = windowlen; _overlap = overlap; // Make sure FFT length is a power of 2 <= kMaxFFTLen. bool valid = false; for (int x = 1; x <= kMaxFFTLen; x *= 2) { if (_fftlen == x) { valid = true; break; } } if (!valid) { post("%s: FFT length must be a power of two <= %d. Setting to 1024...", instname(), kMaxFFTLen); _fftlen = 1024; } _half_fftlen = _fftlen / 2; // Make sure window length is a power of 2 >= FFT length. valid = false; for (int x = _fftlen; x <= kMaxWindowLen; x *= 2) { if (_window_len == x) { valid = true; break; } } if (!valid) { post("%s: Window length must be a power of two >= FFT length (%d)\n" "and <= %d. Setting to 2048...", instname(), _fftlen, kMaxWindowLen); _window_len = _fftlen * 2; } // Make sure _overlap is a power of 2 in allowed range. valid = false; for (int x = kMinOverlap; x <= kMaxOverlap; x *= 2) { if (_overlap == x) { valid = true; break; } } if (!valid) { post("%s: Overlap must be a power of two between %d and %d. " "Setting to 2...", instname(), kMinOverlap, kMaxOverlap); _overlap = 2; } _bin_groups = new int [_half_fftlen]; set_srate(srate); set_freqrange(0.0f, 0.0f); // derive decimation from overlap _decimation = int(_fftlen / _overlap); _window_len_minus_decimation = _window_len - _decimation; DPRINT2("_fftlen=%d, _decimation=%d", _fftlen, _decimation); _input = new float [_window_len]; // interior input buffer _output = new float [_window_len]; // interior output buffer if (_input == NULL || _output == NULL) return -1; for (int i = 0; i < _window_len; i++) _input[i] = _output[i] = 0.0f; // Read index chases write index by _decimation; add 2 extra locations to // keep read point from stepping on write point. Verify with asserts in // increment_out_*_index(). _outframes = _decimation + 2; _out_read_index = _outframes - _decimation; _out_write_index = 0; _outbuf = new float [_outframes]; if (_outbuf == NULL) return -1; for (int i = 0; i < _outframes; i++) _outbuf[i] = 0.0f; DPRINT1("_outframes: %d", _outframes); _anal_window = new float [_window_len]; _synth_window = new float [_window_len]; if (_anal_window == NULL || _synth_window == NULL) return -1; if (make_windows() != 0) return -1; _bucket = new Obucket(_decimation, process_wrapper, (void *) this); _fft = new Offt(_fftlen); _fft_buf = _fft->getbuf(); return 0; }