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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
class:: PV_Copy
summary:: Copy an FFT buffer
categories:: UGens>FFT
description::
Copies the spectral frame in code::bufferA:: to code::bufferB::. This allows for parallel processing of spectral data without the need for multiple FFT UGens. Further it allows to extract data at a given point in the FFT chain e.g. for monitoring purposes.
note::As of SC 3.7 instances of PV_Copy are added automatically where necessary for parallel processing. Please see link::Guides/FFT-Overview:: for the current implementation.
This document is provided for legacy purposes only. Existing code explicitly using PV_Copy should continue to work.::
classmethods::
method:: new
argument:: bufferA
source buffer.
argument:: bufferB
destination buffer.
note::
code::bufferA:: and code::bufferB:: must be the same size.
::
examples::
code::
// read a sound file
d = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
// crossfade between original and magmul-ed whitenoise
(
{
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.2, 1.5pi));
}.play
)
// as previous but with Blip for 'vocoder' cross synthesis effect
(
{
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.2));
}.play
)
// Spectral 'pan'
(
{
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);
IFFT([chain, chainB])
}.play
)
// free sound file buffer
d.free;
// proof of concept: copy has identical data
// global buffers for plotting the data
(
b = Buffer.alloc(s, 2048, 1);
c = Buffer.alloc(s, 2048, 1);
)
// silently record some FFT data into the buffers
(
x = {
var inA, chainA, chainB;
inA = LFClipNoise.ar(100);
chainA = FFT(b, inA);
chainB = PV_Copy(chainA, c);
IFFT(chainA) - IFFT(chainB); // proof of concept: cancels to zero
}.play;
)
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));
)
// free the buffers
[b, c].do(_.free);
// Multiple Magnitude plots
(
~fftSize = 2048;
~allBuffers = ();
~copyToBuffer = { |chain, name|
var buffer = Buffer.alloc(s, ~fftSize);
~allBuffers.put(name, buffer);
PV_Copy(chain, buffer)
};
)
(
x = { var in, chain, chainB, chainC;
in = WhiteNoise.ar;
chain = FFT(LocalBuf(~fftSize), in);
chain = ~copyToBuffer.(chain, 'initial'); // initial spectrum
chain = PV_RectComb(chain, 20, 0, 0.2);
chain = ~copyToBuffer.(chain, 'After RectComb'); // after comb
2.do { chain = PV_MagSquared(chain) };
chain = ~copyToBuffer.(chain, 'After MagSquared'); // after magsquared
0.00001 * Pan2.ar(IFFT(chain)); // silently play back
}.play
)
x.free;
// post all buffers
(
~allBuffers.keysValuesDo { |name, buffer, i|
buffer.getToFloatArray(action: { arg array;
var z, x;
// Initially, data is in complex form
z = array.clump(2).flop;
z = z.collect { |each| Signal.newFrom(each) };
x = Complex(z[0], z[1]);
{ x.magnitude.plot(name, Rect(200, 100 + (230 * i), 700, 200)) }.defer
});
}
)
// free the buffers and clean up
(
~allBuffers.do { |x| x.free };
~allBuffers = nil;
~copyToBuffer = nil;
)
::
|