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.cpp (1 of 32 files). Show all

Unified · Split

Spectacle/Spectacle.cpp+84−375
@@ -7,10 +7,11 @@ · 6 unmodified lines
77 #include "chuck_dl.h"
88 #include "chuck_def.h"
99
10+#include "Spectacle-dsp.h"
11+
1012 // general includes
1113 #include <stdio.h>
1214 #include <limits.h>
13−#include "DLineN.h"
1415
1516 // declaration of chugin constructor
1617 CK_DLL_CTOR(spectacle_ctor);
@@ -21,23 +22,42 @@ CK_DLL_DTOR(spectacle_dtor); · 4 unmodified lines
2122 CK_DLL_MFUN(spectacle_setParam);
2223 CK_DLL_MFUN(spectacle_getParam);
2324
24−// for Chugins extending UGen, this is stereo synthesis for 8 samples
25+CK_DLL_MFUN(spectacle_setFFTlen);
26+CK_DLL_MFUN(spectacle_getFFTlen);
27+
28+CK_DLL_MFUN(spectacle_setOverlap);
29+CK_DLL_MFUN(spectacle_getOverlap);
30+
31+CK_DLL_MFUN(spectacle_setMaxDelay);
32+CK_DLL_MFUN(spectacle_getMaxDelay);
33+
34+CK_DLL_MFUN(spectacle_clear);
35+CK_DLL_MFUN(spectacle_hold);
36+CK_DLL_MFUN(spectacle_posteq);
37+
38+CK_DLL_MFUN(spectacle_setMinFreq);
39+CK_DLL_MFUN(spectacle_getMinFreq);
40+
41+CK_DLL_MFUN(spectacle_setMaxFreq);
42+CK_DLL_MFUN(spectacle_getMaxFreq);
43+
44+
45+// for Chugins extending UGen, this is mono synthesis function for 1 sample
2546 CK_DLL_TICKF(spectacle_tick);
2647
2748 // this is a special offset reserved for Chugin internal data
2849 t_CKINT spectacle_data_offset = 0;
2950
30−#define MAXFFTLEN 4096
31−#define MAXWINDOWLEN MAXFFTLEN * 8
32−#define MINOVERLAP 0.25
33−#define MAXOVERLAP 64.0
34−#define MAXDELTIME 20.0
35−#define FFTLEN 1024
36−
37−typedef enum {
38− Hamming = 0,
39− Rectangle
40−} WindowType;
51+#define CONFORM_INPUT
52+#define CLIP(a, lo, hi) ( (a)>(lo)?( (a)<(hi)?(a):(hi) ):(lo) )
53+
54+#define kDefaultFFTLen 1024
55+#define kDefaultWindowLen 2048
56+#define kDefaultOverlap 2
57+#define kDefaultMaxDelTime 6.0f
58+#define kMinMaxDelTime 0.1f
59+#define kMaxMaxDelTime 20.0f
60+#define kMaxTableLen 512
4161
4262 // class definition for internal Chugin data
4363 // (note: this isn't strictly necessary, but serves as example
@@ -48,87 +68,52 @@ public: · 4 unmodified lines
4868 // constructor
4969 Spectacle( t_CKFLOAT fs)
5070 {
51− /* create segmented input buffer */
52− int num_segments = (window_len / FFTLEN) + 2;
53− int extrasamps = FFTLEN - framesToRun();
54− if (extrasamps)
55− num_segments++;
56− int inbuf_samps = num_segments * FFTLEN * inputChannels();
57− inbuf = new float [inbuf_samps];
58− for (int i = 0; i < inbuf_samps; i++)
59− inbuf[i] = 0.0;
60−
61− /* Read ptr chases write ptr by <window_len>. Set read ptr to a position
62− <window_len> frames from right end of input buffer. Set write ptr to
63− beginning of buffer, or, if framesToRun() is not the same as the RTcmix
64− buffer size, set it so that the next run invocation after this one
65− will find the write ptr at the start of the second buffer segment.
66− */
67− inbuf_readptr = inbuf + (inbuf_samps - (window_len * inputChannels()));
68− inbuf_startptr = inbuf + (extrasamps * inputChannels());
69− inbuf_writeptr = inbuf_startptr;
70− inbuf_endptr = inbuf + inbuf_samps;
71−
72− int outbuf_samps = num_segments * FFTLEN * outputChannels();
73− outbuf = new float [outbuf_samps];
74− for (int i = 0; i < outbuf_samps; i++)
75− outbuf[i] = 0.0;
76−
77− outbuf_readptr = outbuf + (outbuf_samps
78− - (framesToRun() * outputChannels()));
79− outbuf_writeptr = outbuf_readptr;
80− outbuf_endptr = outbuf + outbuf_samps;
81− first_time = 0;
71+ m_param = 0;
72+ fftlen = kDefaultFFTLen;
73+ windowlen = kDefaultWindowLen;
74+ overlap = kDefaultOverlap;
75+ maxdeltime = kDefaultMaxDelTime;
76+ maxdeltime = CLIP(maxdeltime, kMinMaxDelTime, kMaxMaxDelTime);
77+ srate = fs;
78+ spectdelay = NULL;
79+ float *del = dttable;
80+ float *eq = eqtable;
81+ float *feed = fbtable;
82+ int *bm = eqbinmap;
83+ int *dbm = delaybinmap;
84+ for (int i = 0; i < kMaxTableLen; i++)
85+ {
86+ *del++ = 0.0;
87+ *eq++ = 0.0;
88+ *feed++ = 0.0;
89+ *bm++ = 0;
90+ *dbm++ = 0;
91+ }
92+ dttablen = eqtablen = fbtablen = 0;
93+ eqbinmaplen = delaybinmaplen = 0;
94+ dminfreq = dmaxfreq = minfreq = maxfreq = 0.0;
95+ posteq = hold = false;
96+
97+ spectdelay = new Spectacle_dsp();
98+ spectdelay->init(fftlen, windowlen, overlap, srate, maxdeltime);
8299 }
83100
84101 ~Spectacle()
85102 {
86− delete [] anal_window;
87− delete [] synth_window;
88− delete [] fft_buf;
89− delete [] anal_chans;
90− delete [] drybuf;
91− delete [] inbuf;
92− delete [] outbuf;
93− delete dry_delay;
103+ delete spectdelay;
94104 }
95−
105+
96106 // for Chugins extending UGen
97− void tick( SAMPLE *in, SAMPLE *out, int nframes )
98− {
99− memset(out, 0, sizeof(SAMPLE)*nframes);
100−
101− for (int i=0; i < nframes; i++)
102− {
103− shiftin();
104− fold();
105− JGrfft(fft_buf, half_fft_len, FORWARD);
106− leanconvert();
107− }
108− flush_dry_delay();
109− modify_analysis();
110− leanunconvert();
111− JGrfft(fft_buf, half_fft_len, INVERSE);
112− overlapadd(currentFrame());
113− shiftout();
114−
115− increment(decimation);
107+ void tick( SAMPLE* in, SAMPLE* out, int nframes)
108+ {
109+ memset (out, 0, sizeof(SAMPLE)*nframes);
110+ // process a block of samples
111+ spectdelay->run(in, out, nframes);
116112 }
117113
118− if (currentFrame() < input_end_frame) {
119− inbuf_writeptr += insamps;
120− if (inbuf_writeptr >= inbuf_endptr)
121− inbuf_writeptr = inbuf;
122− }
123−
124− rtbaddout(outbuf_readptr, framesToRun());
125− outbuf_readptr += framesToRun() * outputChannels();
126− if (outbuf_readptr >= outbuf_endptr)
127− outbuf_readptr = outbuf;
128−
129− return framesToRun();
130−
131− // sythesis function here
114+ void clear()
115+ {
116+ spectdelay->clear();
132117 }
133118
134119 // set parameter example
@@ -141,297 +126,21 @@ public: · 6 unmodified lines
141126 // get parameter example
142127 float getParam() { return m_param; }
143128
144− /* ---------------------------------------------------------- make_windows -- */
145−/* Make balanced pair of analysis and synthesis windows.
146−*/
147− int make_windows()
148− {
149− switch (window_type) {
150− case Hamming:
151− for (int i = 0; i < window_len; i++)
152− anal_window[i] = synth_window[i] = 0.54 - 0.46
153− * cos(TWO_PI * i / (window_len - 1));
154− break;
155− case Rectangle:
156− //FIXME: is this right?
157− for (int i = 0; i < window_len; i++)
158− anal_window[i] = synth_window[i] = 1.0;
159− break;
160− }
161−
162− /* When window_len > fft_len, also apply interpolating (sinc) windows to
163− ensure that window are 0 at increments of fft_len away from the center
164− of the analysis window and of decimation away from the center of the
165− synthesis window.
166− */
167− if (window_len > fft_len) {
168− float x;
169−
170− /* Take care to create symmetrical windows. */
171− x = -(window_len - 1) / 2.;
172− for (int i = 0; i < window_len; i++, x += 1.)
173− if (x != 0.) {
174− anal_window[i] *= fft_len * sin(PI * x / fft_len) / (PI * x);
175− if (decimation)
176− synth_window[i] *= decimation * sin(PI * x / decimation)
177− / (PI * x);
178− }
179− }
180−
181− /* Normalize windows for unity gain across unmodified
182− analysis-synthesis procedure.
183− */
184− float sum = 0.0;
185− for (int i = 0; i < window_len; i++)
186− sum += anal_window[i];
187−
188− for (int i = 0; i < window_len; i++) {
189− float afac = 2. / sum;
190− float sfac = window_len > fft_len ? 1. / afac : afac;
191− anal_window[i] *= afac;
192− synth_window[i] *= sfac;
193− }
194−
195− if (window_len <= fft_len && decimation) {
196− sum = 0.0;
197− for (int i = 0; i < window_len; i += decimation)
198− sum += synth_window[i] * synth_window[i];
199− sum = 1.0 / sum;
200− for (int i = 0; i < window_len; i++)
201− synth_window[i] *= sum;
202− }
203−
204− return 0;
205− }
206−
207− double * resample_functable(double *table, int oldsize, int newsize)
208− {
209− double *newtable = new double [newsize];
210−
211− if (newsize == oldsize) { // straight copy
212− for (int i = 0; i < newsize; i++)
213− newtable[i] = table[i];
214− }
215− else {
216− double incr = (double) oldsize / (double) newsize;
217− double f = 0.0;
218− for (int i = 0; i < newsize; i++) {
219− int n = (int) f;
220− double frac = f - (double) n;
221− double diff = 0.0;
222− if (frac) {
223− double next = (n + 1 < oldsize) ? table[n + 1] : table[oldsize - 1];
224− diff = next - table[n];
225− }
226− newtable[i] = table[n] + (diff * frac);
227− f += incr;
228− }
229− }
230− return newtable;
231− }
232−
233− /* ------------------------------------------------------------------ init -- */
234− WindowType getWindowType(double pval)
235− {
236− int intval = int(pval);
237− WindowType type;
238−
239− switch (intval) {
240− case 1:
241− type = Rectangle;
242− break;
243− default:
244− type = Hamming;
245− }
246− return type;
247− }
248−
249− /* ---------------------------------------------------------------- shiftin -- */
250− void shiftin()
251− {
252− int _cursamp = currentFrame();
253−
254− /* Shift samples in <input> from right to left by <decimation>. */
255− for (int i = 0; i < window_len_minus_decimation; i++)
256− input[i] = input[i + decimation];
257−
258− /* Copy <decimation> samples from <inbuf> to right end of <input> and
259− to left end of <drybuf>.
260− */
261− int j = 0;
262− for (int i = window_len_minus_decimation; i < window_len; i++, j++)
263− {
264− if (--iamp_branch <= 0)
265− {
266− /* Since inbuf_readptr trails inbuf_writeptr, we delay the start of
267− the envelope until we reach actual input rather than zero padding.
268− */
269− if (iamparray && _cursamp >= window_len)
270− iamp = tablei(_cursamp - window_len, iamparray, iamptabs);
271− iamp_branch = skip;
272− }
273− float sig = inbuf_readptr[inchan] * iamp;
274− drybuf[j] = dry_delay->tick(sig);
275− input[i] = sig;
276− inbuf_readptr += inputChannels();
277− if (inbuf_readptr >= inbuf_endptr)
278− {
279− inbuf_readptr = inbuf_startptr;
280− /* <inbuf_startptr> might not == <inbuf> in first call to run(). */
281− inbuf_startptr = inbuf;
282− }
283− _cursamp++;
284− }
285− }
286−
287− void fold(int n)
288− {
289− for (int i = 0; i < fft_len; i++)
290− fft_buf[i] = 0.0;
291−
292− n %= fft_len;
293−
294− for (int i = 0; i < window_len; i++) {
295− fft_buf[n] += input[i] * anal_window[i];
296− if (++n == fft_len)
297− n = 0;
298− }
299− }
300−
301−/* ----------------------------------------------------------- leanconvert -- */
302−/* <fft_buf> is a spectrum in JGrfft format, i.e. it contains <half_fft_len> * 2
303− real values, arranged in pairs of real and imaginary values, except for
304− the first two values, which are the real parts of 0 and Nyquist frequencies.
305− Converts these into <half_fft_len> + 1 pairs of magnitude and phase values,
306− and stores them into the output array <anal_chans>.
307−*/
308− void leanconvert()
309− {
310− int real_index, imag_index, amp_index, phase_index;
311− float a, b;
312−
313− for (int i = 0; i <= half_fft_len; i++) {
314− real_index = amp_index = i << 1;
315− imag_index = phase_index = real_index + 1;
316− if (i == half_fft_len) {
317− a = fft_buf[1];
318− b = 0.0;
319− }
320− else {
321− a = fft_buf[real_index];
322− b = (i == 0) ? 0.0 : fft_buf[imag_index];
323− }
324− anal_chans[amp_index] = hypot(a, b);
325− anal_chans[phase_index] = -atan2(b, a);
326− }
327− }
328−
329− /* ------------------------------------------------------- flush_dry_delay -- */
330− void flush_dry_delay()
331− {
332− if (currentFrame() < input_end_frame + window_len_minus_decimation) {
333− for (int i = 0; i < decimation; i++)
334− drybuf[i] = dry_delay->tick(0.0);
335− }
336− }
337−
338−
339− /* --------------------------------------------------------- leanunconvert -- */
340− /* leanunconvert essentially undoes what leanconvert does, i.e., it turns
341− <half_fft_len> + 1 pairs of amplitude and phase values in <anal_chans>
342− into <half_fft_len> pairs of complex spectrum data (in JGrfft format) in
343− output array <fft_buf>.
344− */
345− void leanunconvert()
346− {
347− int real_index, imag_index, amp_index, phase_index;
348− float mag, phase;
349−
350− for (int i = 0; i <= half_fft_len; i++) {
351− real_index = amp_index = i << 1;
352− imag_index = phase_index = real_index + 1;
353− if (i == half_fft_len)
354− real_index = 1;
355− mag = anal_chans[amp_index];
356− phase = anal_chans[phase_index];
357− fft_buf[real_index] = mag * cos(phase);
358− if (i != half_fft_len)
359− fft_buf[imag_index] = -mag * sin(phase);
360− }
361− }
362−
363−
364− /* ------------------------------------------------------------ overlapadd -- */
365− /* <fft_buf> is a folded spectrum of length <fft_len>. <output> and
366− <synth_window> are of length <window_len>. Overlap-add windowed,
367− unrotated, unfolded <fft_buf> data into <output>.
368− */
369− void overlapadd(int n)
370− {
371− n %= fft_len;
372− for (int i = 0; i < window_len; i++) {
373− output[i] += fft_buf[n] * synth_window[i];
374− if (++n == fft_len)
375− n = 0;
376− }
377− }
378−
379−
380− /* -------------------------------------------------------------- shiftout -- */
381− void shiftout()
382− {
383− int _cursamp = currentFrame();
384−
385− for (int i = 0; i < decimation; i++) {
386− if (--oamp_branch <= 0) {
387− if (oamparray && (_cursamp >= latency))
388− oamp = tablei(_cursamp - latency, oamparray, oamptabs) * amp;
389− oamp_branch = skip;
390− }
391− float sig;
392− if (_cursamp < input_end_frame)
393− sig = ((output[i] * wetdry) + ((1.0 - wetdry) * drybuf[i])) * oamp;
394− else
395− sig = output[i] * wetdry * oamp;
396− if (outputChannels() == 2) {
397− *outbuf_writeptr++ = sig * pctleft;
398− *outbuf_writeptr++ = sig * (1.0 - pctleft);
399− }
400− else
401− *outbuf_writeptr++ = sig;
402− if (outbuf_writeptr >= outbuf_endptr) {
403− outbuf_writeptr = outbuf;
404− }
405− _cursamp++;
406− }
407−
408− /* shift samples in <output> from right to left by <decimation> */
409− for (int i = 0; i < window_len_minus_decimation; i++)
410− output[i] = output[i + decimation];
411− for (int i = window_len_minus_decimation; i < window_len; i++)
412− output[i] = 0.0;
413− }
414−
415−
416129 private:
417130 // instance data
418131 float m_param;
419− float *anal_window, *synth_window, *input, *output, *fft_buf, *drybuf;
420− float *inbuf, *inbuf_startptr, *inbuf_readptr, *inbuf_writeptr,
421− *inbuf_endptr;
422− float *outbuf, *outbuf_startptr, *outbuf_readptr, *outbuf_writeptr,
423− *outbuf_endptr;
424− float iamptabs[2], oamptabs[2];
425− double *iamparray, *oamparray;
426− DLineN *dry_delay;
427− WindowType window_type;
428−protected:
429− int inchan, skip, total_insamps, first_time, int_overlap;
430− int fft_len, window_len, decimation, window_len_minus_decimation,
431− half_fft_len, latency, input_end_frame;
432− float wetdry, pctleft, inputdur, ringdur, fund_anal_freq;
433− float *anal_chans;
434−
132+
133+ int fftlen, windowlen, overlap;
134+ float srate, maxdeltime;
135+ Spectacle_dsp *spectdelay;
136+ float eqtable[kMaxTableLen];
137+ float dttable[kMaxTableLen];
138+ float fbtable[kMaxTableLen];
139+ int eqbinmap[kMaxTableLen];
140+ int delaybinmap[kMaxTableLen];
141+ int eqtablen, dttablen, fbtablen, eqbinmaplen, delaybinmaplen;
142+ float minfreq, maxfreq, dminfreq, dmaxfreq;
143+ bool hold, posteq;
435144 };
436145
437146
@@ -518,7 +227,7 @@ CK_DLL_TICKF(spectacle_tick) · 80 unmodified lines
518227
519228 // invoke our tick function; store in the magical out variable
520229 if(c) c->tick(in,out, nframes);
521−
230+
522231 // yes
523232 return TRUE;
524233 }

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