History

implemented basic DSP for Spectacle

Joel Matthys committed 12 years ago

Commit 4325a601 parent 0ecc72732 files · +3252 −1434Browse files

Showing the changes to Spectacle/Spectacle-dsp.cpp (1 of 32 files). Show all

Unified · Split

Spectacle/Spectacle-dsp.cpp+382−0
@@ -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
29const float kMaxDelayTime = 20.0f;
30#ifdef ANTI_DENORM
31 const float kAntiDenormConstant = 1e-18f;
32#endif
33
34
35// ---------------------------------------------------------------- Spectacle_dsp --
36Spectacle_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 --
49Spectacle_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
68int 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;
99bad_alloc:
100 //error("%s: Not enough memory for delay lines.", instname());
101 return -1;
102}
103
104
105// -------------------------------------------------------------------- clear --
106void 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 --
117void 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.
134void 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 --
146void 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 --
171void 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 --
195void 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.
215bool 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
239void 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
255void 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 --
267void 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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t