FFT: Prevent user from attempting hops smaller than SC's block size
[supercollider.git] / server / plugins / PV_UGens.cpp
blob4c268cb2c671aae7b7a84d595e5593f0183b3fec
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "FFT_UGens.h"
25 struct PV_OutOfPlace : Unit
27 int m_numbins;
28 float *m_tempbuf;
31 struct PV_MagSmear : PV_OutOfPlace
35 struct PV_MagShift : PV_OutOfPlace
39 struct PV_BinShift : PV_OutOfPlace
43 struct PV_Diffuser : Unit
45 int m_numbins;
46 float m_prevtrig, *m_shift;
47 bool m_triggered;
50 struct PV_MagFreeze : Unit
52 int m_numbins;
53 float *m_mags, m_dc, m_nyq;
56 struct PV_RandWipe : Unit
58 int *m_ordering, m_numbins;
59 float m_prevtrig;
60 bool m_triggered;
63 struct PV_RandComb : Unit
65 int *m_ordering, m_numbins;
66 float m_prevtrig;
67 bool m_triggered;
70 struct PV_BinScramble : Unit
72 int *m_from, *m_to, m_numbins;
73 float m_prevtrig;
74 float *m_tempbuf;
75 bool m_triggered;
78 struct PV_Conj : PV_Unit {};
80 //////////////////////////////////////////////////////////////////////////////////////////////////
82 extern "C"
84 void PV_PhaseShift_Ctor(PV_Unit *unit);
85 void PV_PhaseShift_next(PV_Unit *unit, int inNumSamples);
87 void PV_PhaseShift90_Ctor(PV_Unit *unit);
88 void PV_PhaseShift90_next(PV_Unit *unit, int inNumSamples);
90 void PV_PhaseShift270_Ctor(PV_Unit *unit);
91 void PV_PhaseShift270_next(PV_Unit *unit, int inNumSamples);
93 void PV_MagClip_Ctor(PV_Unit *unit);
94 void PV_MagClip_next(PV_Unit *unit, int inNumSamples);
96 void PV_MagAbove_Ctor(PV_Unit *unit);
97 void PV_MagAbove_next(PV_Unit *unit, int inNumSamples);
99 void PV_MagBelow_Ctor(PV_Unit *unit);
100 void PV_MagBelow_next(PV_Unit *unit, int inNumSamples);
102 void PV_Min_Ctor(PV_Unit *unit);
103 void PV_Min_next(PV_Unit *unit, int inNumSamples);
105 void PV_Max_Ctor(PV_Unit *unit);
106 void PV_Max_next(PV_Unit *unit, int inNumSamples);
108 void PV_Mul_Ctor(PV_Unit *unit);
109 void PV_Mul_next(PV_Unit *unit, int inNumSamples);
111 void PV_Div_Ctor(PV_Unit *unit);
112 void PV_Div_next(PV_Unit *unit, int inNumSamples);
114 void PV_Add_Ctor(PV_Unit *unit);
115 void PV_Add_next(PV_Unit *unit, int inNumSamples);
117 void PV_RectComb_Ctor(PV_Unit *unit);
118 void PV_RectComb_next(PV_Unit *unit, int inNumSamples);
120 void PV_RectComb2_Ctor(PV_Unit *unit);
121 void PV_RectComb2_next(PV_Unit *unit, int inNumSamples);
123 void PV_MagSquared_Ctor(PV_Unit *unit);
124 void PV_MagSquared_next(PV_Unit *unit, int inNumSamples);
126 void PV_MagMul_Ctor(PV_Unit *unit);
127 void PV_MagMul_next(PV_Unit *unit, int inNumSamples);
129 void PV_MagDiv_Ctor(PV_Unit *unit);
130 void PV_MagDiv_next(PV_Unit *unit, int inNumSamples);
132 void PV_Copy_Ctor(PV_Unit *unit);
133 void PV_Copy_next(PV_Unit *unit, int inNumSamples);
135 void PV_CopyPhase_Ctor(PV_Unit *unit);
136 void PV_CopyPhase_next(PV_Unit *unit, int inNumSamples);
138 void PV_MagSmear_Ctor(PV_MagSmear *unit);
139 void PV_MagSmear_Dtor(PV_MagSmear *unit);
140 void PV_MagSmear_next(PV_MagSmear *unit, int inNumSamples);
142 void PV_BinShift_Ctor(PV_BinShift *unit);
143 void PV_BinShift_Dtor(PV_BinShift *unit);
144 void PV_BinShift_next(PV_BinShift *unit, int inNumSamples);
146 void PV_MagShift_Ctor(PV_MagShift *unit);
147 void PV_MagShift_Dtor(PV_MagShift *unit);
148 void PV_MagShift_next(PV_MagShift *unit, int inNumSamples);
150 void PV_MagNoise_Ctor(PV_Unit *unit);
151 void PV_MagNoise_next(PV_Unit *unit, int inNumSamples);
153 void PV_BrickWall_Ctor(PV_Unit *unit);
154 void PV_BrickWall_next(PV_Unit *unit, int inNumSamples);
156 void PV_BinWipe_Ctor(PV_Unit *unit);
157 void PV_BinWipe_next(PV_Unit *unit, int inNumSamples);
159 void PV_LocalMax_Ctor(PV_Unit *unit);
160 void PV_LocalMax_next(PV_Unit *unit, int inNumSamples);
162 void PV_RandComb_Ctor(PV_RandComb *unit);
163 void PV_RandComb_Dtor(PV_RandComb *unit);
164 void PV_RandComb_next(PV_RandComb *unit, int inNumSamples);
166 void PV_RandWipe_Ctor(PV_RandWipe *unit);
167 void PV_RandWipe_Dtor(PV_RandWipe *unit);
168 void PV_RandWipe_next(PV_RandWipe *unit, int inNumSamples);
170 void PV_Diffuser_Ctor(PV_Diffuser *unit);
171 void PV_Diffuser_Dtor(PV_Diffuser *unit);
172 void PV_Diffuser_next(PV_Diffuser *unit, int inNumSamples);
174 void PV_MagFreeze_Ctor(PV_MagFreeze *unit);
175 void PV_MagFreeze_Dtor(PV_MagFreeze *unit);
176 void PV_MagFreeze_next(PV_MagFreeze *unit, int inNumSamples);
178 void PV_BinScramble_Ctor(PV_BinScramble *unit);
179 void PV_BinScramble_Dtor(PV_BinScramble *unit);
180 void PV_BinScramble_next(PV_BinScramble *unit, int inNumSamples);
182 void PV_Conj_Ctor(PV_Unit *unit);
183 void PV_Conj_next(PV_Unit *unit, int inNumSamples);
185 /* spectral feature extractors? :
186 bin freq
187 bin magnitude
188 bin phase
189 bin laden ;-}
190 average magnitude over a range of bins
191 max magnitude over a range of bins
192 max magnitude bin freq
199 //////////////////////////////////////////////////////////////////////////////////////////////////
202 //SCPolarBuf* ToPolarApx(SndBuf *buf);
204 SCPolarBuf* ToPolarApx(SndBuf *buf)
206 if (buf->coord == coord_Complex) {
207 SCComplexBuf* p = (SCComplexBuf*)buf->data;
208 int numbins = buf->samples - 2 >> 1;
209 for (int i=0; i<numbins; ++i) {
210 p->bin[i].ToPolarApxInPlace();
212 buf->coord = coord_Polar;
214 return (SCPolarBuf*)buf->data;
217 //SCComplexBuf* ToComplexApx(SndBuf *buf);
219 SCComplexBuf* ToComplexApx(SndBuf *buf)
221 if (buf->coord == coord_Polar) {
222 SCPolarBuf* p = (SCPolarBuf*)buf->data;
223 int numbins = buf->samples - 2 >> 1;
224 for (int i=0; i<numbins; ++i) {
225 p->bin[i].ToComplexApxInPlace();
227 buf->coord = coord_Complex;
229 return (SCComplexBuf*)buf->data;
233 /////////////////////////////////////////////////////////////////////////////////////////////
235 void PV_MagAbove_next(PV_Unit *unit, int inNumSamples)
237 PV_GET_BUF
239 SCPolarBuf *p = ToPolarApx(buf);
241 float thresh = ZIN0(1);
243 if(std::abs(p->dc ) < thresh) p->dc = 0.f;
244 if(std::abs(p->nyq) < thresh) p->nyq = 0.f;
245 for (int i=0; i<numbins; ++i) {
246 float mag = p->bin[i].mag;
247 if (mag < thresh) p->bin[i].mag = 0.f;
251 void PV_MagAbove_Ctor(PV_Unit *unit)
253 SETCALC(PV_MagAbove_next);
254 ZOUT0(0) = ZIN0(0);
257 void PV_MagBelow_next(PV_Unit *unit, int inNumSamples)
259 PV_GET_BUF
261 SCPolarBuf *p = ToPolarApx(buf);
263 float thresh = ZIN0(1);
265 if(std::abs(p->dc ) > thresh) p->dc = 0.f;
266 if(std::abs(p->nyq) > thresh) p->nyq = 0.f;
267 for (int i=0; i<numbins; ++i) {
268 float mag = p->bin[i].mag;
269 if (mag > thresh) p->bin[i].mag = 0.f;
273 void PV_MagBelow_Ctor(PV_Unit *unit)
275 SETCALC(PV_MagBelow_next);
276 ZOUT0(0) = ZIN0(0);
279 void PV_MagClip_next(PV_Unit *unit, int inNumSamples)
281 PV_GET_BUF
283 SCPolarBuf *p = ToPolarApx(buf);
285 float thresh = ZIN0(1);
287 if(std::abs(p->dc ) > thresh) p->dc = p->dc < 0.f ? -thresh : thresh;
288 if(std::abs(p->nyq) > thresh) p->nyq = p->nyq < 0.f ? -thresh : thresh;
289 for (int i=0; i<numbins; ++i) {
290 float mag = p->bin[i].mag;
291 if (mag > thresh) p->bin[i].mag = thresh;
295 void PV_MagClip_Ctor(PV_Unit *unit)
297 SETCALC(PV_MagClip_next);
298 ZOUT0(0) = ZIN0(0);
301 void PV_LocalMax_next(PV_Unit *unit, int inNumSamples)
303 PV_GET_BUF
305 SCPolarBuf *p = ToPolarApx(buf);
307 float thresh = ZIN0(1);
308 float dc, nyq, mag;
310 // DC is only compared with the one above it
311 dc = std::abs(p->dc);
312 mag = p->bin[0].mag;
313 if(dc < thresh || dc < mag) p->dc = 0.f;
314 // 0th bin compared against DC and 1th
315 if(mag < thresh || mag < dc || mag < p->bin[1].mag) p->bin[0].mag = 0.f;
316 // All the middling bins
317 for (int i=1; i<numbins-1; ++i) {
318 float mag = p->bin[i].mag;
319 if (mag < thresh || mag < p->bin[i-1].mag || mag < p->bin[i+1].mag) {
320 p->bin[i].mag = 0.f;
323 // Penultimate is compared against the one below and the nyq
324 nyq = std::abs(p->nyq);
325 mag = p->bin[numbins-1].mag;
326 if(mag < thresh || mag < nyq || mag < p->bin[numbins-2].mag) p->bin[numbins-1].mag = 0.f;
327 // Nyquist compared against penultimate
328 if(nyq < thresh || nyq < mag) p->nyq = 0.f;
331 void PV_LocalMax_Ctor(PV_Unit *unit)
333 SETCALC(PV_LocalMax_next);
334 ZOUT0(0) = ZIN0(0);
337 void PV_MagSmear_next(PV_MagSmear *unit, int inNumSamples)
339 PV_GET_BUF
340 MAKE_TEMP_BUF
342 SCPolarBuf *p = ToPolarApx(buf);
343 SCPolarBuf *q = (SCPolarBuf*)unit->m_tempbuf;
345 int width = (int)ZIN0(1);
346 width = sc_clip(width, 0, numbins-1);
347 float scale = 1.f / (2*width+1);
349 q->dc = p->dc;
350 q->nyq = p->nyq;
351 for (int j=0; j<numbins; j++) {
352 float sum = 0.0;
353 for (int pos = j-width; pos <= j+width; pos++) {
354 if (pos >= 0 && pos < numbins) {
355 sum += p->bin[pos].mag;
358 q->bin[j].Set( sum * scale, p->bin[j].phase );
360 for (int i=0; i<numbins; i++) {
361 p->bin[i] = q->bin[i];
365 void PV_MagSmear_Ctor(PV_MagSmear *unit)
367 SETCALC(PV_MagSmear_next);
368 ZOUT0(0) = ZIN0(0);
369 unit->m_tempbuf = 0;
372 void PV_MagSmear_Dtor(PV_MagSmear *unit)
374 RTFree(unit->mWorld, unit->m_tempbuf);
377 void PV_BinShift_next(PV_BinShift *unit, int inNumSamples)
379 PV_GET_BUF
380 MAKE_TEMP_BUF
382 // get shift and stretch params
383 float stretch = ZIN0(1);
384 float shift = ZIN0(2);
386 SCComplexBuf *p = ToComplexApx(buf);
387 SCComplexBuf *q = (SCComplexBuf*)unit->m_tempbuf;
389 // initialize output buf to zeroes
390 for (int i=0; i<numbins; ++i) {
391 q->bin[i] = 0.f;
394 float fpos;
395 int i;
396 q->dc = p->dc;
397 q->nyq = p->nyq;
398 for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) {
399 int32 pos = (int32)(fpos + 0.5);
400 if (pos >= 0 && pos < numbins) {
401 q->bin[pos] += p->bin[i];
404 memcpy(p->bin, q->bin, numbins * sizeof(SCComplex));
408 void PV_BinShift_Ctor(PV_BinShift *unit)
410 SETCALC(PV_BinShift_next);
411 ZOUT0(0) = ZIN0(0);
412 unit->m_tempbuf = 0;
415 void PV_BinShift_Dtor(PV_BinShift *unit)
417 RTFree(unit->mWorld, unit->m_tempbuf);
420 void PV_MagShift_next(PV_MagShift *unit, int inNumSamples)
422 PV_GET_BUF
423 MAKE_TEMP_BUF
425 // get shift and stretch params
426 float stretch = ZIN0(1);
427 float shift = ZIN0(2);
429 SCPolarBuf *p = ToPolarApx(buf);
430 SCPolarBuf *q = (SCPolarBuf*)unit->m_tempbuf;
432 // initialize output buf to zeroes
433 for (int i=0; i<numbins; ++i) {
434 q->bin[i].mag = 0.f;
435 q->bin[i].phase = p->bin[i].phase;
438 float fpos;
439 int i;
440 q->dc = p->dc;
441 q->nyq = p->nyq;
442 for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) {
443 int32 pos = (int32)(fpos + 0.5);
444 if (pos >= 0 && pos < numbins) {
445 q->bin[pos].mag += p->bin[i].mag;
448 memcpy(p->bin, q->bin, numbins * sizeof(SCComplex));
451 void PV_MagShift_Ctor(PV_MagShift *unit)
453 SETCALC(PV_MagShift_next);
454 ZOUT0(0) = ZIN0(0);
455 unit->m_tempbuf = 0;
458 void PV_MagShift_Dtor(PV_MagShift *unit)
460 RTFree(unit->mWorld, unit->m_tempbuf);
463 void PV_MagNoise_next(PV_Unit *unit, int inNumSamples)
465 PV_GET_BUF
467 RGET
468 if (buf->coord == coord_Complex) {
469 SCComplexBuf *p = (SCComplexBuf*)buf->data;
470 for (int i=0; i<numbins; ++i) {
471 float r = frand2(s1, s2, s3);
472 p->bin[i].real *= r;
473 p->bin[i].imag *= r;
475 p->dc *= frand2(s1, s2, s3);
476 p->nyq *= frand2(s1, s2, s3);
477 } else {
478 SCPolarBuf *p = (SCPolarBuf*)buf->data;
479 for (int i=0; i<numbins; ++i) {
480 float r = frand2(s1, s2, s3);
481 p->bin[i].mag *= r;
483 p->dc *= frand2(s1, s2, s3);
484 p->nyq *= frand2(s1, s2, s3);
486 RPUT
489 void PV_MagNoise_Ctor(PV_Unit *unit)
491 SETCALC(PV_MagNoise_next);
492 ZOUT0(0) = ZIN0(0);
495 void PV_PhaseShift_next(PV_Unit *unit, int inNumSamples)
497 PV_GET_BUF
499 SCPolarBuf *p = ToPolarApx(buf);
501 float shift = ZIN0(1);
503 for (int i=0; i<numbins; ++i) {
504 p->bin[i].phase += shift;
508 void PV_PhaseShift_Ctor(PV_Unit *unit)
510 SETCALC(PV_PhaseShift_next);
511 ZOUT0(0) = ZIN0(0);
514 void PV_PhaseShift90_next(PV_Unit *unit, int inNumSamples)
516 PV_GET_BUF
518 SCComplexBuf *p = ToComplexApx(buf);
520 for (int i=0; i<numbins; ++i) {
521 float temp = p->bin[i].real;
522 p->bin[i].real = -p->bin[i].imag;
523 p->bin[i].imag = temp;
527 void PV_PhaseShift90_Ctor(PV_Unit *unit)
529 SETCALC(PV_PhaseShift90_next);
530 ZOUT0(0) = ZIN0(0);
533 void PV_PhaseShift270_next(PV_Unit *unit, int inNumSamples)
535 PV_GET_BUF
537 SCComplexBuf *p = ToComplexApx(buf);
539 for (int i=0; i<numbins; ++i) {
540 float temp = p->bin[i].real;
541 p->bin[i].real = p->bin[i].imag;
542 p->bin[i].imag = -temp;
546 void PV_PhaseShift270_Ctor(PV_Unit *unit)
548 SETCALC(PV_PhaseShift270_next);
549 ZOUT0(0) = ZIN0(0);
552 void PV_MagSquared_next(PV_Unit *unit, int inNumSamples)
554 PV_GET_BUF
556 SCPolarBuf *p = ToPolarApx(buf);
558 p->dc = p->dc * p->dc;
559 p->nyq = p->nyq * p->nyq;
560 for (int i=0; i<numbins; ++i) {
561 float mag = p->bin[i].mag;
562 p->bin[i].mag = mag * mag;
566 void PV_MagSquared_Ctor(PV_Unit *unit)
568 SETCALC(PV_MagSquared_next);
569 ZOUT0(0) = ZIN0(0);
572 void PV_BrickWall_next(PV_Unit *unit, int inNumSamples)
574 PV_GET_BUF
576 SCComplexBuf *p = (SCComplexBuf*)buf->data;
578 int wipe = (int)(ZIN0(1) * numbins);
579 if (wipe > 0) {
580 wipe = sc_min(wipe, numbins);
581 p->dc = 0.f;
582 for (int i=0; i < wipe; ++i) {
583 p->bin[i] = 0.f;
585 if(wipe==numbins) p->nyq = 0.f;
586 } else if (wipe < 0) {
587 wipe = sc_max(wipe, -numbins);
588 if(wipe==-numbins) p->dc = 0.f;
589 for (int i=numbins+wipe; i < numbins; ++i) {
590 p->bin[i] = 0.f;
592 p->nyq = 0.f;
596 void PV_BrickWall_Ctor(PV_Unit *unit)
598 SETCALC(PV_BrickWall_next);
599 ZOUT0(0) = ZIN0(0);
602 void PV_BinWipe_next(PV_Unit *unit, int inNumSamples)
604 PV_GET_BUF2
606 SCComplexBuf *p = (SCComplexBuf*)buf1->data;
607 SCComplexBuf *q = (SCComplexBuf*)buf2->data;
609 int wipe = (int)(ZIN0(2) * numbins);
610 if (wipe > 0) {
611 wipe = sc_min(wipe, numbins);
612 p->dc = q->dc;
613 for (int i=0; i < wipe; ++i) {
614 p->bin[i] = q->bin[i];
616 if(wipe==numbins) p->nyq = q->nyq;
617 } else if (wipe < 0) {
618 wipe = sc_max(wipe, -numbins);
619 if(wipe==-numbins) p->dc = q->dc;
620 for (int i=numbins+wipe; i < numbins; ++i) {
621 p->bin[i] = q->bin[i];
623 p->nyq = q->nyq;
627 void PV_BinWipe_Ctor(PV_Unit *unit)
629 SETCALC(PV_BinWipe_next);
630 ZOUT0(0) = ZIN0(0);
633 void PV_MagMul_next(PV_Unit *unit, int inNumSamples)
635 PV_GET_BUF2
637 SCPolarBuf *p = ToPolarApx(buf1);
638 SCPolarBuf *q = ToPolarApx(buf2);
640 p->dc *= q->dc;
641 p->nyq *= q->nyq;
642 for (int i=0; i<numbins; ++i) {
643 p->bin[i].mag *= q->bin[i].mag;
647 void PV_MagMul_Ctor(PV_Unit *unit)
649 SETCALC(PV_MagMul_next);
650 ZOUT0(0) = ZIN0(0);
653 void PV_MagDiv_next(PV_Unit *unit, int inNumSamples)
655 PV_GET_BUF2
657 SCPolarBuf *p = ToPolarApx(buf1);
658 SCPolarBuf *q = ToPolarApx(buf2);
660 float zeroed = ZIN0(2);
662 p->dc /= sc_max(q->dc, zeroed);
663 p->nyq /= sc_max(q->nyq, zeroed);
664 for (int i=0; i<numbins; ++i) {
665 p->bin[i].mag /= sc_max(q->bin[i].mag, zeroed);
669 void PV_MagDiv_Ctor(PV_Unit *unit)
671 SETCALC(PV_MagDiv_next);
672 ZOUT0(0) = ZIN0(0);
675 void PV_Copy_next(PV_Unit *unit, int inNumSamples)
677 float fbufnum1 = ZIN0(0);
678 float fbufnum2 = ZIN0(1);
679 if (fbufnum1 < 0.f || fbufnum2 < 0.f) { ZOUT0(0) = -1.f; return; }
680 ZOUT0(0) = fbufnum2;
681 uint32 ibufnum1 = (int)fbufnum1;
682 uint32 ibufnum2 = (int)fbufnum2;
683 World *world = unit->mWorld;
684 SndBuf *buf1;
685 SndBuf *buf2;
686 if (ibufnum1 >= world->mNumSndBufs) {
687 int localBufNum = ibufnum1 - world->mNumSndBufs;
688 Graph *parent = unit->mParent;
689 if(localBufNum <= parent->localBufNum) {
690 buf1 = parent->mLocalSndBufs + localBufNum;
691 } else {
692 buf1 = world->mSndBufs;
694 } else {
695 buf1 = world->mSndBufs + ibufnum1;
697 if (ibufnum2 >= world->mNumSndBufs) {
698 int localBufNum = ibufnum2 - world->mNumSndBufs;
699 Graph *parent = unit->mParent;
700 if(localBufNum <= parent->localBufNum) {
701 buf2 = parent->mLocalSndBufs + localBufNum;
702 } else {
703 buf2 = world->mSndBufs;
705 } else {
706 buf2 = world->mSndBufs + ibufnum2;
709 if (buf1->samples != buf2->samples) return;
710 int numbins = buf1->samples - 2 >> 1;
712 // copy to buf2
713 LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2);
714 buf2->coord = buf1->coord;
715 memcpy(buf2->data, buf1->data, buf1->samples * sizeof(float));
718 void PV_Copy_Ctor(PV_Unit *unit)
720 SETCALC(PV_Copy_next);
721 ZOUT0(0) = ZIN0(1);
724 void PV_CopyPhase_next(PV_Unit *unit, int inNumSamples)
726 PV_GET_BUF2
728 SCPolarBuf *p = ToPolarApx(buf1);
729 SCPolarBuf *q = ToPolarApx(buf2);
731 if((p->dc > 0.f) == (q->dc < 0.f)) p->dc = -p->dc ;
732 if((p->nyq > 0.f) == (q->nyq < 0.f)) p->nyq = -p->nyq;
733 for (int i=0; i<numbins; ++i) {
734 p->bin[i].phase = q->bin[i].phase;
738 void PV_CopyPhase_Ctor(PV_Unit *unit)
740 SETCALC(PV_CopyPhase_next);
741 ZOUT0(0) = ZIN0(0);
744 void PV_Mul_next(PV_Unit *unit, int inNumSamples)
746 PV_GET_BUF2
748 SCComplexBuf *p = ToComplexApx(buf1);
749 SCComplexBuf *q = ToComplexApx(buf2);
751 float preal, realmul, imagmul;
753 p->dc *= q->dc;
754 p->nyq *= q->nyq;
755 for (int i=0; i<numbins; ++i) {
756 preal = p->bin[i].real;
757 // Complex multiply using only 3 multiplications rather than 4. http://mathworld.wolfram.com/ComplexMultiplication.html
758 realmul = (preal * q->bin[i].real);
759 imagmul = (p->bin[i].imag * q->bin[i].imag);
760 p->bin[i].real = realmul - imagmul;
761 p->bin[i].imag = (preal + p->bin[i].imag) * (q->bin[i].real + q->bin[i].imag) - realmul - imagmul;
765 void PV_Mul_Ctor(PV_Unit *unit)
767 SETCALC(PV_Mul_next);
768 ZOUT0(0) = ZIN0(0);
771 void PV_Div_next(PV_Unit *unit, int inNumSamples)
773 PV_GET_BUF2
775 SCComplexBuf *p = ToComplexApx(buf1);
776 SCComplexBuf *q = ToComplexApx(buf2);
778 p->dc /= q->dc;
779 p->nyq /= q->nyq;
780 for (int i=0; i<numbins; ++i) {
781 // See http://gcc.gnu.org/ml/fortran/2004-05/msg00029.html
782 // Note that hypot has danger of overflow (see URL above),
783 // however FFT values typically stay within a small range,
784 // so I'm considering this OK for now.
785 float hypot = q->bin[i].real * q->bin[i].real + q->bin[i].imag * q->bin[i].imag;
786 float preal = p->bin[i].real;
787 p->bin[i].real = (preal * q->bin[i].real + p->bin[i].imag * q->bin[i].imag) / hypot;
788 p->bin[i].imag = (p->bin[i].imag * q->bin[i].real - preal * q->bin[i].imag) / hypot;
792 void PV_Div_Ctor(PV_Unit *unit)
794 SETCALC(PV_Div_next);
795 ZOUT0(0) = ZIN0(0);
798 void PV_Add_next(PV_Unit *unit, int inNumSamples)
800 PV_GET_BUF2
802 SCComplexBuf *p = ToComplexApx(buf1);
803 SCComplexBuf *q = ToComplexApx(buf2);
805 p->dc += q->dc;
806 p->nyq += q->nyq;
807 for (int i=0; i<numbins; ++i) {
808 p->bin[i].real += q->bin[i].real;
809 p->bin[i].imag += q->bin[i].imag;
813 void PV_Add_Ctor(PV_Unit *unit)
815 SETCALC(PV_Add_next);
816 ZOUT0(0) = ZIN0(0);
819 void PV_Max_next(PV_Unit *unit, int inNumSamples)
821 PV_GET_BUF2
823 SCPolarBuf *p = ToPolarApx(buf1);
824 SCPolarBuf *q = ToPolarApx(buf2);
826 if(std::abs(q->dc ) > std::abs(p->dc )) p->dc = q->dc ;
827 if(std::abs(q->nyq) > std::abs(p->nyq)) p->nyq = q->nyq;
828 for (int i=0; i<numbins; ++i) {
829 if (q->bin[i].mag > p->bin[i].mag) {
830 p->bin[i] = q->bin[i];
835 void PV_Max_Ctor(PV_Unit *unit)
837 SETCALC(PV_Max_next);
838 ZOUT0(0) = ZIN0(0);
841 void PV_Min_next(PV_Unit *unit, int inNumSamples)
843 PV_GET_BUF2
845 SCPolarBuf *p = ToPolarApx(buf1);
846 SCPolarBuf *q = ToPolarApx(buf2);
848 if(std::abs(q->dc ) < std::abs(p->dc )) p->dc = q->dc ;
849 if(std::abs(q->nyq) < std::abs(p->nyq)) p->nyq = q->nyq;
850 for (int i=0; i<numbins; ++i) {
851 if (q->bin[i].mag < p->bin[i].mag) {
852 p->bin[i] = q->bin[i];
857 void PV_Min_Ctor(PV_Unit *unit)
859 SETCALC(PV_Min_next);
860 ZOUT0(0) = ZIN0(0);
863 void PV_RectComb_next(PV_Unit *unit, int inNumSamples)
865 PV_GET_BUF
867 float numTeeth = ZIN0(1);
868 float phase = ZIN0(2);
869 float width = ZIN0(3);
870 float freq = numTeeth / (numbins + 1);
872 SCComplexBuf *p = (SCComplexBuf*)buf->data;
874 if (phase > width) p->dc = 0.f;
875 phase += freq;
876 if (phase >= 1.f) phase -= 1.f;
877 else if (phase < 0.f) phase += 1.f;
879 for (int i=0; i < numbins; ++i) {
880 if (phase > width) p->bin[i] = 0.f;
881 phase += freq;
882 if (phase >= 1.f) phase -= 1.f;
883 else if (phase < 0.f) phase += 1.f;
886 if (phase > width) p->nyq = 0.f;
889 void PV_RectComb_Ctor(PV_Unit *unit)
891 SETCALC(PV_RectComb_next);
892 ZOUT0(0) = ZIN0(0);
895 void PV_RectComb2_next(PV_Unit *unit, int inNumSamples)
897 PV_GET_BUF2
899 float numTeeth = ZIN0(2);
900 float phase = ZIN0(3);
901 float width = ZIN0(4);
902 float freq = numTeeth / (numbins + 1);
904 SCComplexBuf *p = (SCComplexBuf*)buf1->data;
905 SCComplexBuf *q = (SCComplexBuf*)buf2->data;
907 if (phase > width) p->dc = q->dc;
908 phase += freq;
909 if (phase >= 1.f) phase -= 1.f;
910 else if (phase < 0.f) phase += 1.f;
912 for (int i=0; i < numbins; ++i) {
913 if (phase > width) p->bin[i] = q->bin[i];
914 phase += freq;
915 if (phase >= 1.f) phase -= 1.f;
916 else if (phase < 0.f) phase += 1.f;
919 if (phase > width) p->nyq = q->nyq;
922 void PV_RectComb2_Ctor(PV_Unit *unit)
924 SETCALC(PV_RectComb2_next);
925 ZOUT0(0) = ZIN0(0);
929 static void PV_RandComb_choose(PV_RandComb* unit)
931 int numbins = unit->m_numbins;
932 for (int i=0; i<numbins; ++i) {
933 unit->m_ordering[i] = i;
935 RGET
936 for (int i=0; i<numbins; ++i) {
937 int32 j = (int32)(frand(s1,s2,s3) * (numbins - i));
938 int32 temp = unit->m_ordering[i];
939 unit->m_ordering[i] = unit->m_ordering[j];
940 unit->m_ordering[j] = temp;
942 RPUT
945 void PV_RandComb_next(PV_RandComb *unit, int inNumSamples)
947 float trig = ZIN0(2);
948 if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
949 unit->m_prevtrig = trig;
951 PV_GET_BUF
953 if (!unit->m_ordering) {
954 unit->m_ordering = (int*)RTAlloc(unit->mWorld, numbins * sizeof(int));
955 unit->m_numbins = numbins;
956 PV_RandComb_choose(unit);
957 } else {
958 if (numbins != unit->m_numbins) return;
959 if (unit->m_triggered) {
960 unit->m_triggered = false;
961 PV_RandComb_choose(unit);
965 int n = (int)(ZIN0(1) * numbins);
966 n = sc_clip(n, 0, numbins);
968 SCComplexBuf *p = (SCComplexBuf*)buf->data;
970 int *ordering = unit->m_ordering;
971 for (int i=0; i<n; ++i) {
972 p->bin[ordering[i]] = 0.f;
974 if(n==numbins){
975 // including dc and nyq in the above shuffle would add too much complexity. but at full "wipe" we should get silence.
976 p->dc = 0.f;
977 p->nyq = 0.f;
982 void PV_RandComb_Ctor(PV_RandComb* unit)
984 SETCALC(PV_RandComb_next);
985 ZOUT0(0) = ZIN0(0);
986 unit->m_ordering = 0;
987 unit->m_prevtrig = 0.f;
988 unit->m_triggered = false;
991 void PV_RandComb_Dtor(PV_RandComb* unit)
993 RTFree(unit->mWorld, unit->m_ordering);
996 //////////////////////
998 static void PV_RandWipe_choose(PV_RandWipe* unit)
1000 int numbins = unit->m_numbins;
1001 for (int i=0; i<numbins; ++i) {
1002 unit->m_ordering[i] = i;
1004 RGET
1005 for (int i=0; i<numbins; ++i) {
1006 int32 j = (int32)(frand(s1,s2,s3) * (numbins - i));
1007 int32 temp = unit->m_ordering[i];
1008 unit->m_ordering[i] = unit->m_ordering[j];
1009 unit->m_ordering[j] = temp;
1011 RPUT
1014 void PV_RandWipe_next(PV_RandWipe *unit, int inNumSamples)
1016 float trig = ZIN0(3);
1017 if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
1018 unit->m_prevtrig = trig;
1020 PV_GET_BUF2
1022 if (!unit->m_ordering) {
1023 unit->m_ordering = (int*)RTAlloc(unit->mWorld, numbins * sizeof(int));
1024 unit->m_numbins = numbins;
1025 PV_RandWipe_choose(unit);
1026 } else {
1027 if (numbins != unit->m_numbins) return;
1028 if (unit->m_triggered) {
1029 unit->m_triggered = false;
1030 PV_RandWipe_choose(unit);
1034 int n = (int)(ZIN0(2) * numbins);
1035 n = sc_clip(n, 0, numbins);
1037 SCComplexBuf *p = (SCComplexBuf*)buf1->data;
1038 SCComplexBuf *q = (SCComplexBuf*)buf2->data;
1040 int *ordering = unit->m_ordering;
1041 for (int i=0; i<n; ++i) {
1042 p->bin[ordering[i]] = q->bin[ordering[i]];
1047 void PV_RandWipe_Ctor(PV_RandWipe* unit)
1049 SETCALC(PV_RandWipe_next);
1050 ZOUT0(0) = ZIN0(0);
1051 unit->m_ordering = 0;
1052 unit->m_prevtrig = 0.f;
1053 unit->m_triggered = false;
1056 void PV_RandWipe_Dtor(PV_RandWipe* unit)
1058 RTFree(unit->mWorld, unit->m_ordering);
1061 //////////////////////
1063 static void PV_Diffuser_choose(PV_Diffuser* unit)
1065 RGET
1066 for (int i=0; i<unit->m_numbins; ++i) {
1067 unit->m_shift[i] = frand(s1,s2,s3) * twopi;
1069 RPUT
1072 void PV_Diffuser_next(PV_Diffuser *unit, int inNumSamples)
1074 float trig = ZIN0(1);
1075 if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
1076 unit->m_prevtrig = trig;
1078 PV_GET_BUF
1080 if (!unit->m_shift) {
1081 unit->m_shift = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float));
1082 unit->m_numbins = numbins;
1083 PV_Diffuser_choose(unit);
1084 } else {
1085 if (numbins != unit->m_numbins) return;
1086 if (unit->m_triggered) {
1087 unit->m_triggered = false;
1088 PV_Diffuser_choose(unit);
1092 int n = (int)(ZIN0(1) * numbins);
1093 n = sc_clip(n, 0, numbins);
1095 SCPolarBuf *p = ToPolarApx(buf);
1097 float *shift = unit->m_shift;
1098 for (int i=0; i<n; ++i) {
1099 p->bin[i].phase += shift[i];
1104 void PV_Diffuser_Ctor(PV_Diffuser* unit)
1106 SETCALC(PV_Diffuser_next);
1107 ZOUT0(0) = ZIN0(0);
1108 unit->m_shift = 0;
1109 unit->m_prevtrig = 0.f;
1110 unit->m_triggered = false;
1113 void PV_Diffuser_Dtor(PV_Diffuser* unit)
1115 RTFree(unit->mWorld, unit->m_shift);
1118 //////////////////////
1120 void PV_MagFreeze_next(PV_MagFreeze *unit, int inNumSamples)
1122 PV_GET_BUF
1124 float freeze = ZIN0(1);
1126 if (!unit->m_mags) {
1127 unit->m_mags = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float));
1128 unit->m_numbins = numbins;
1129 // The first fft frame must use the else branch below
1130 // so that unit->m_mags gets populated with actual mag data
1131 // before reading; otherwise it might be used uninitialized.
1132 freeze = 0.f;
1133 } else if (numbins != unit->m_numbins) return;
1135 SCPolarBuf *p = ToPolarApx(buf);
1137 float *mags = unit->m_mags;
1138 if (freeze > 0.f) {
1139 for (int i=0; i<numbins; ++i) {
1140 p->bin[i].mag = mags[i];
1142 p->dc = unit->m_dc;
1143 p->nyq = unit->m_nyq;
1144 } else {
1145 for (int i=0; i<numbins; ++i) {
1146 mags[i] = p->bin[i].mag;
1148 unit->m_dc = p->dc;
1149 unit->m_nyq = p->nyq;
1154 void PV_MagFreeze_Ctor(PV_MagFreeze* unit)
1156 SETCALC(PV_MagFreeze_next);
1157 ZOUT0(0) = ZIN0(0);
1158 unit->m_mags = 0;
1161 void PV_MagFreeze_Dtor(PV_MagFreeze* unit)
1163 RTFree(unit->mWorld, unit->m_mags);
1166 //////////////////////
1168 static void PV_BinScramble_choose(PV_BinScramble* unit)
1170 int numbins = unit->m_numbins;
1171 int *to = unit->m_to;
1172 int *from = unit->m_from;
1174 for (int i=0; i<numbins; ++i) {
1175 to[i] = i;
1177 RGET
1178 for (int i=0; i<numbins; ++i) {
1179 int32 j = (int32)(frand(s1,s2,s3) * (numbins - i));
1180 int32 temp = to[i];
1181 to[i] = to[j];
1182 to[j] = temp;
1185 int32 width = (int32)(ZIN0(2) * numbins);
1186 for (int i=0; i<numbins; ++i) {
1187 int32 k = to[i];
1188 int32 minr = sc_max(0, k-width);
1189 int32 maxr = sc_min(numbins-1, k+width);
1190 int32 j = (int32)(frand(s1,s2,s3) * (maxr - minr) + minr);
1191 from[i] = j;
1193 RPUT
1196 void PV_BinScramble_next(PV_BinScramble *unit, int inNumSamples)
1198 float trig = ZIN0(3);
1199 if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true;
1200 unit->m_prevtrig = trig;
1202 PV_GET_BUF
1204 if (!unit->m_to) {
1205 unit->m_to = (int*)RTAlloc(unit->mWorld, numbins * 2 * sizeof(int));
1206 unit->m_from = unit->m_to + numbins;
1207 unit->m_numbins = numbins;
1208 unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, buf->samples * sizeof(float));
1209 PV_BinScramble_choose(unit);
1210 } else {
1211 if (numbins != unit->m_numbins) return;
1212 if (unit->m_triggered) {
1213 unit->m_triggered = false;
1214 PV_BinScramble_choose(unit);
1218 SCComplexBuf *p = (SCComplexBuf*)buf->data;
1219 SCComplexBuf *q = (SCComplexBuf*)unit->m_tempbuf;
1221 float wipe = ZIN0(1);
1222 int32 scrambleBins = (int32)(numbins * sc_clip(wipe, 0.f, 1.f));
1224 int *to = unit->m_to;
1225 int *from = unit->m_from;
1226 for (int j=0; j<scrambleBins; j++) {
1227 q->bin[to[j]] = p->bin[from[j]];
1229 for (int j=scrambleBins; j<numbins; j++) {
1230 int32 a = to[j];
1231 q->bin[a] = p->bin[a];
1233 q->dc = p->dc;
1234 q->nyq = p->nyq;
1235 memcpy(p->bin, q->bin, numbins * sizeof(SCComplex));
1239 void PV_BinScramble_Ctor(PV_BinScramble* unit)
1241 SETCALC(PV_BinScramble_next);
1242 ZOUT0(0) = ZIN0(0);
1243 unit->m_to = 0;
1244 unit->m_prevtrig = 0.f;
1245 unit->m_triggered = false;
1246 unit->m_tempbuf = 0;
1249 void PV_BinScramble_Dtor(PV_BinScramble* unit)
1251 RTFree(unit->mWorld, unit->m_to);
1252 RTFree(unit->mWorld, unit->m_tempbuf);
1256 void PV_Conj_Ctor(PV_Unit *unit)
1258 SETCALC(PV_Conj_next);
1259 ZOUT0(0) = ZIN0(0);
1262 void PV_Conj_next(PV_Unit *unit, int inNumSamples)
1264 PV_GET_BUF
1266 SCComplexBuf *p = ToComplexApx(buf);
1268 for (int i=0; i<numbins; ++i) {
1269 p->bin[i].imag = 0.f - p->bin[i].imag;
1274 ////////////////////////////////////////////////////////////////////////////////////////////////////////
1276 #define DefinePVUnit(name) \
1277 (*ft->fDefineUnit)(#name, sizeof(PV_Unit), (UnitCtorFunc)&name##_Ctor, 0, 0);
1280 void initPV(InterfaceTable *inTable)
1282 DefinePVUnit(PV_MagAbove);
1283 DefinePVUnit(PV_MagBelow);
1284 DefinePVUnit(PV_MagClip);
1285 DefinePVUnit(PV_MagMul);
1286 DefinePVUnit(PV_MagDiv);
1287 DefinePVUnit(PV_MagSquared);
1288 DefinePVUnit(PV_MagNoise);
1289 DefinePVUnit(PV_Copy);
1290 DefinePVUnit(PV_CopyPhase);
1291 DefinePVUnit(PV_PhaseShift);
1292 DefinePVUnit(PV_PhaseShift90);
1293 DefinePVUnit(PV_PhaseShift270);
1294 DefinePVUnit(PV_Min);
1295 DefinePVUnit(PV_Max);
1296 DefinePVUnit(PV_Mul);
1297 DefinePVUnit(PV_Div);
1298 DefinePVUnit(PV_Add);
1299 DefinePVUnit(PV_RectComb);
1300 DefinePVUnit(PV_RectComb2);
1301 DefinePVUnit(PV_BrickWall);
1302 DefinePVUnit(PV_BinWipe);
1303 DefinePVUnit(PV_LocalMax);
1304 DefinePVUnit(PV_Conj);
1306 DefineDtorUnit(PV_BinScramble);
1307 DefineDtorUnit(PV_MagSmear);
1308 DefineDtorUnit(PV_MagShift);
1309 DefineDtorUnit(PV_BinShift);
1310 DefineDtorUnit(PV_RandWipe);
1311 DefineDtorUnit(PV_Diffuser);
1312 DefineDtorUnit(PV_RandComb);
1313 DefineDtorUnit(PV_MagFreeze);