scide: implement selectionLength for openDocument
[supercollider.git] / HelpSource / Classes / Convolution2.schelp
blob17c0aa28028a82b7a8af4c25a711ae616ff38fb1
1 class:: Convolution2
2 summary:: Real-time fixed kernel convolver.
3 related:: Classes/Convolution, Classes/Convolution2L, Classes/Convolution3
4 categories::  UGens>FFT, UGens>Convolution
7 Description::
9 Strict convolution with fixed kernel which can be updated using a trigger
10 signal.
13 See also  link::http://www.dspguide.com/ch18.htm::  by Steven W.
14 Smith.
17 classmethods::
19 method::ar
21 argument::in
23 Processing target.
26 argument::kernel
28 Buffer index for the fixed kernel, may be modulated in
29 combination with the trigger.
32 argument::trigger
34 Update the kernel on a change from non-positive to positive
35 value.
38 argument::framesize
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,
43 2048, 4096 standard.
45 argument::mul
47 argument::add
49 Examples::
51 code::
52 ( // allocate three buffers
53 b = Buffer.alloc(s,2048);
54 c = Buffer.alloc(s,2048);
55 d = Buffer.alloc(s,2048);
57 b.zero;
58 c.zero;
59 d.zero;
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;
71         var input;
73         input=Impulse.ar(1);
75         //must have power of two framesize
76         Out.ar(0,Convolution2.ar(input,kernel,trig,2048, 0.5));
77 }).send(s)
82 x = Synth.new("conv-test",[\kernel,b.bufnum]);
84 // changing the buffer number:
85 x.set(\kernel,c.bufnum);
86 x.set(\trig,0);
87 x.set(\trig,1); // after this trigger, the change will take effect.
88 x.set(\kernel,d.bufnum);
89 x.set(\trig,0);
90 x.set(\trig,1); // after this trigger, the change will take effect.
92 d.zero;
93 40.do({ |it| d.set(20*it+10, 1); });// changing the buffers' contents
94 x.set(\trig,0);
95 x.set(\trig,1); // after this trigger, the change will take effect.
97 x.set(\kernel,b.bufnum);
98 x.set(\trig,0);
99 x.set(\trig,1); // after this trigger, the change will take effect.
102 // next example
103 b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");
106         { var input, kernel;
108         input=AudioIn.ar(1);
110         //must have power of two framesize
111         Out.ar(0,Convolution2.ar(input,b.bufnum,0,512, 0.5));
112          }.play;
117 // another example
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
121 a=2048;
122 s = Server.local;
123 //kernel buffer
124 g = Buffer.alloc(s,a,1);
128 g.set(0,1.0);
129 100.do({arg i; g.set(a.rand, (i+1).reciprocal)});
133 // random impulse response
135         {
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));
144          }.play;
148 // one last example
150 b = Buffer.alloc(s, 512, 1);
151 b.sine1(1.0/[1,2,3,4,5,6], true, true, true);
155         { var input, kernel;
157         input=AudioIn.ar(1);
159         //must have power of two framesize
160         Out.ar(0,Convolution2.ar(input,b.bufnum,0, 512, 0.5));
161          }.play;
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:
169 code::
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