1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
class:: PV_Copy
summary:: Copy an FFT buffer
categories:: UGens>FFT
description::
Copies the spectral frame in bufferA to bufferB at that point in the chain of PV UGens. This allows for parallel processing of spectral data without the need for multiple FFT UGens, and to copy out data at that point in the chain for other purposes. bufferA and bufferB must be the same size.
classmethods::
method:: new
argument:: bufferA
source buffer.
argument:: bufferB
destination buffer.
examples::
code::
(
s.waitForBoot {
d = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
}
)
//// crossfade between original and magmul-ed whitenoise
(
x = { var in, in2, chain, chainB, chainC;
in = PlayBuf.ar(1, d, BufRateScale.kr(d), loop: 1) * 2;
in2 = WhiteNoise.ar;
chain = FFT(LocalBuf(2048), in);
chainB = FFT(LocalBuf(2048), in2);
chainC = PV_Copy(chain, LocalBuf(2048));
chainB = PV_MagMul(chainB, chainC);
XFade2.ar(IFFT(chain), IFFT(chainB) * 0.1, SinOsc.kr(0.1, 1.5pi));
}.play(s);
)
x.free;
//// as previous but with Blip for 'vocoder' cross synthesis effect
(
x = { var in, in2, chain, chainB, chainC;
in = PlayBuf.ar(1, d, BufRateScale.kr(d), loop: 1) * 2;
in2 = Blip.ar(100, 50);
chain = FFT(LocalBuf(2048), in);
chainB = FFT(LocalBuf(2048), in2);
chainC = PV_Copy(chain, LocalBuf(2048));
chainB = PV_MagMul(chainB, chainC);
XFade2.ar(IFFT(chain), IFFT(chainB) * 0.1, SinOsc.ar(0.1));
}.play(s);
)
x.free;
//// Spectral 'pan'
(
x = { var in, chain, chainB, pan;
in = PlayBuf.ar(1, d, BufRateScale.kr(d), loop: 1);
chain = FFT(LocalBuf(2048), in);
chainB = PV_Copy(chain, LocalBuf(2048));
pan = MouseX.kr(0.001, 1.001, 'exponential') - 0.001;
chain = PV_BrickWall(chain, pan);
chainB = PV_BrickWall(chainB, -1 + pan);
0.5 * IFFT([chain, chainB]);
}.play(s);
)
x.free;
(
s.waitForBoot {
b = Buffer.alloc(s,2048,1);
c = Buffer.alloc(s,2048,1);
d = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
e = Buffer.alloc(s,2048,1);
f = Buffer.alloc(s,2048,1);
}
)
//// proof of concept
(
x = { var inA, chainA, inB, chainB, chain;
inA = LFClipNoise.ar(100);
chainA = FFT(b, inA);
chainB = PV_Copy(chainA, c);
IFFT(chainA) - IFFT(chainB); // cancels to zero so silent!
}.play(s);
)
x.free;
// IFFTed frames contain the same windowed output data
b.plot(\b, Rect(200, 430, 700, 300)); c.plot(\c, Rect(200, 100, 700, 300));
//// Multiple Magnitude plots
(
x = { var in, chain, chainB, chainC;
in = WhiteNoise.ar;
chain = FFT(b, in);
PV_Copy(chain, LocalBuf(2048)); // initial spectrum
chain = PV_RectComb(chain, 20, 0, 0.2);
PV_Copy(chain, LocalBuf(2048)); // after comb
2.do({chain = PV_MagSquared(chain)});
PV_Copy(chain, LocalBuf(2048)); // after magsquared
0.00001 * Pan2.ar(IFFT(chain));
}.play(s);
)
x.free;
(
c.getToFloatArray(action: { arg array;
var z, x;
z = array.clump(2).flop;
// Initially data is in complex form
z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
x = Complex(z[0], z[1]);
{x.magnitude.plot('Initial', Rect(200, 560, 700, 200))}.defer
});
e.getToFloatArray(action: { arg array;
var z, x;
z = array.clump(2).flop;
// RectComb doesn't convert, so it's still complex
z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
x = Complex(z[0], z[1]);
{x.magnitude.plot('After RectComb', Rect(200, 330, 700, 200))}.defer
});
f.getToFloatArray(action: { arg array;
var z, x;
z = array.clump(2).flop;
// MagSquared converts to Polar
x = Signal.newFrom(z[0]); // magnitude first
{x.plot('After MagSquared', Rect(200, 100, 700, 200))}.defer
})
)
[b, c, d, e, f].do(_.free); // free the buffers
::
|