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,
49 ( // allocate three buffers
50 b = Buffer.alloc(s,2048);
51 c = Buffer.alloc(s,2048);
52 d = Buffer.alloc(s,2048);
60 50.do({ |it| c.set(20*it+10, 1.0.rand); });
61 3.do({ |it| b.set(400*it+100, 1); });
62 20.do({ |it| d.set(40*it+20, 1); });
67 SynthDef( "conv-test", { arg kernel, trig=0;
72 //must have power of two framesize
73 Out.ar(0,Convolution2.ar(input,kernel,trig,2048, 0.5));
79 x = Synth.new("conv-test",[\kernel,b.bufnum]);
81 // changing the buffer number:
82 x.set(\kernel,c.bufnum);
84 x.set(\trig,1); // after this trigger, the change will take effect.
85 x.set(\kernel,d.bufnum);
87 x.set(\trig,1); // after this trigger, the change will take effect.
90 40.do({ |it| d.set(20*it+10, 1); });// changing the buffers' contents
92 x.set(\trig,1); // after this trigger, the change will take effect.
94 x.set(\kernel,b.bufnum);
96 x.set(\trig,1); // after this trigger, the change will take effect.
100 b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
107 //must have power of two framesize
108 Out.ar(0,Convolution2.ar(input,b.bufnum,0,512, 0.5));
116 //must have power of two framesize- FFT size will be sorted by Convolution2 to be double this
117 //maximum is currently a=8192 for FFT of size 16384
121 g = Buffer.alloc(s,a,1);
126 100.do({arg i; g.set(a.rand, (i+1).reciprocal)});
130 // random impulse response
133 var input,inputAmp,threshhold,gate;
135 input = AudioIn.ar(1);
136 inputAmp = Amplitude.kr(input);
137 threshhold = 0.02; // noise gating threshold
138 gate = Lag.kr(inputAmp > threshhold, 0.01);
140 Out.ar(0,Convolution2.ar(input*gate,g.bufnum,0, a, 0.5));
147 b = Buffer.alloc(s, 512, 1);
148 b.sine1(1.0/[1,2,3,4,5,6], true, true, true);
156 //must have power of two framesize
157 Out.ar(0,Convolution2.ar(input,b.bufnum,0, 512, 0.5));
163 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.
164 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:
167 b = Buffer.alloc( s, 2048, 1, _.zeroMsg );
169 x = { arg i_kernel, density = 100, trigPeriod = 5.0, cutOff = 1000, minFreq = 200, maxFreq = 2000;
170 var input, trigFreq, recTrig, irSig, convTrig, convTrigs, bufFrames, conv1, conv2;
172 input = LPF.ar( Dust2.ar( density ), cutOff );
173 trigFreq = trigPeriod.reciprocal;
174 recTrig = Impulse.kr( trigFreq );
175 irSig = Saw.ar( TExpRand.kr( minFreq, maxFreq, recTrig ), 0.4 );
176 RecordBuf.ar( irSig, i_kernel, recTrig, loop: 0, trigger: recTrig );
177 convTrig = TDelay.kr( recTrig, BufDur.ir( i_kernel ));
178 // split updates across two triggers. Note that [ 1, 0 ] creates
179 // a MultiChannel expansion!
180 convTrigs = PulseDivider.kr( convTrig, 2, [ 1, 0 ]);
181 bufFrames = BufFrames.ir( i_kernel );
182 // create the two alternatingly updated convolution ugens
183 #conv1, conv2 = Convolution2.ar( input, i_kernel, convTrigs, bufFrames );
185 XFade2.ar( conv1, conv2, LFTri.kr( trigFreq * 0.5, 1 )) ! 2;
186 }.play( s, [ \i_kernel, b ]);
189 x.set( \trigPeriod, 0.1 ); // fast changes
190 x.set( \trigPeriod, 10.0 ); // slow changes
191 x.free; // delete synth