2 summary:: Real-time fixed kernel convolver.
3 related:: Classes/Convolution, Classes/Convolution2L, Classes/Convolution3
4 categories:: UGens>FFT, UGens>Convolution
9 Strict convolution with fixed kernel which can be updated using a trigger
13 See also link::http://www.dspguide.com/ch18.htm:: by Steven W.
28 Buffer index for the fixed kernel, may be modulated in
29 combination with the trigger.
34 Update the kernel on a change from non-positive to positive
40 Size of FFT frame, must be a power of two. Convolution uses twice
41 this number internally, maximum value you can give this argument
42 is 2^16 = 65536. Note that it gets progressively more expensive to run for higher powers! 512, 1024,
52 ( // allocate three buffers
53 b = Buffer.alloc(s,2048);
54 c = Buffer.alloc(s,2048);
55 d = Buffer.alloc(s,2048);
63 50.do({ |it| c.set(20*it+10, 1.0.rand); });
64 3.do({ |it| b.set(400*it+100, 1); });
65 20.do({ |it| d.set(40*it+20, 1); });
70 SynthDef( "conv-test", { arg kernel, trig=0;
75 //must have power of two framesize
76 Out.ar(0,Convolution2.ar(input,kernel,trig,2048, 0.5));
82 x = Synth.new("conv-test",[\kernel,b.bufnum]);
84 // changing the buffer number:
85 x.set(\kernel,c.bufnum);
87 x.set(\trig,1); // after this trigger, the change will take effect.
88 x.set(\kernel,d.bufnum);
90 x.set(\trig,1); // after this trigger, the change will take effect.
93 40.do({ |it| d.set(20*it+10, 1); });// changing the buffers' contents
95 x.set(\trig,1); // after this trigger, the change will take effect.
97 x.set(\kernel,b.bufnum);
99 x.set(\trig,1); // after this trigger, the change will take effect.
103 b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
110 //must have power of two framesize
111 Out.ar(0,Convolution2.ar(input,b.bufnum,0,512, 0.5));
119 //must have power of two framesize- FFT size will be sorted by Convolution2 to be double this
120 //maximum is currently a=8192 for FFT of size 16384
124 g = Buffer.alloc(s,a,1);
129 100.do({arg i; g.set(a.rand, (i+1).reciprocal)});
133 // random impulse response
136 var input,inputAmp,threshhold,gate;
138 input = AudioIn.ar(1);
139 inputAmp = Amplitude.kr(input);
140 threshhold = 0.02; // noise gating threshold
141 gate = Lag.kr(inputAmp > threshhold, 0.01);
143 Out.ar(0,Convolution2.ar(input*gate,g.bufnum,0, a, 0.5));
150 b = Buffer.alloc(s, 512, 1);
151 b.sine1(1.0/[1,2,3,4,5,6], true, true, true);
159 //must have power of two framesize
160 Out.ar(0,Convolution2.ar(input,b.bufnum,0, 512, 0.5));
166 Instead of triggering the kernel update yourself, as in the first example, you can use a UGen trigger signal to do so. In the next example, we use two Convolution2 UGens in order to continuously and smoothly change the impulse response: link::Classes/RecordBuf:: is used to record a random frequency link::Classes/Saw:: oscillator every code::trigPeriod:: seconds.
167 Right after the recording (trigPeriod gets delayed by the buffer duration link::Classes/BufDur::, using the link::Classes/TDelay:: UGen) the two convolution UGens alternatingly update their kernels (using two triggers convTrigs). At the frequency of the kernel updates a crossfader link::Classes/XFade2:: moves between conv1 and conv2, using a triangle oscillator link::Classes/LFTri:: at half the trigger frequency as a panning input. The result is a constantly shifting spectral colorization of the Dust impulses:
170 b = Buffer.alloc( s, 2048, 1, _.zeroMsg );
172 x = { arg i_kernel, density = 100, trigPeriod = 5.0, cutOff = 1000, minFreq = 200, maxFreq = 2000;
173 var input, trigFreq, recTrig, irSig, convTrig, convTrigs, bufFrames, conv1, conv2;
175 input = LPF.ar( Dust2.ar( density ), cutOff );
176 trigFreq = trigPeriod.reciprocal;
177 recTrig = Impulse.kr( trigFreq );
178 irSig = Saw.ar( TExpRand.kr( minFreq, maxFreq, recTrig ), 0.4 );
179 RecordBuf.ar( irSig, i_kernel, recTrig, loop: 0, trigger: recTrig );
180 convTrig = TDelay.kr( recTrig, BufDur.ir( i_kernel ));
181 // split updates across two triggers. Note that [ 1, 0 ] creates
182 // a MultiChannel expansion!
183 convTrigs = PulseDivider.kr( convTrig, 2, [ 1, 0 ]);
184 bufFrames = BufFrames.ir( i_kernel );
185 // create the two alternatingly updated convolution ugens
186 #conv1, conv2 = Convolution2.ar( input, i_kernel, convTrigs, bufFrames );
188 XFade2.ar( conv1, conv2, LFTri.kr( trigFreq * 0.5, 1 )) ! 2;
189 }.play( s, [ \i_kernel, b ]);
192 x.set( \trigPeriod, 0.1 ); // fast changes
193 x.set( \trigPeriod, 10.0 ); // slow changes
194 x.free; // delete synth