CheckBadValues should run on the first sample as well
[supercollider.git] / HelpSource / Guides / Tour_of_UGens.schelp
blob890fcd6f401b20fde91d7c076e0955d2e6e7add0
1 title:: Tour of UGens
2 summary:: Signal Processing in SuperCollider
3 related:: Browse#UGens
4 categories:: UGens, Server>Nodes
6 definitionlist::
7 ## 1. A Tour of available Unit Generators.
8 || SuperCollider has over 250 unit generators. 
9    If you count the unary and binary operators, there are over 300. 
10    This tour covers many, but not all of them.
11         
12     categories of unit generators:
13     list::
14     ## sources: periodic, aperiodic 
15     ## filters
16     ## distortion 
17     ## panning
18     ## reverbs
19     ## delays and buffer ugens
20     ## granular synthesis
21     ## control: envelopes, triggers, counters, gates, lags, decays
22     ## spectral
23     ::
25 ## 2. Techniques
27     list::
28     ## artificial space - decorrelation, beat frequencies, delays.
29     ## series and parallel structures.
30     ::
33 Note: The link::Browse#UGens#category browser:: contains a category for UGens, which provides another useful way to get an overview of the available UGens, including those which were created since this tour was written.
35 code::
37 s = Server.internal;
38 Server.default = s;
39 s.boot;
43 section:: Periodic Sources: Oscillators.
45 subsection:: LF - "Low Frequency" Unit Generators.
47 link::Classes/LFPar::, link::Classes/LFCub::, link::Classes/LFTri::, link::Classes/Impulse::, link::Classes/LFSaw::, link::Classes/LFPulse::, link::Classes/VarSaw::, link::Classes/SyncSaw:: - has geometric waveforms, not band limited.
48 will cause aliasing at higher frequencies.
50 definitionlist::
51 ## link::Classes/LFPar::, link::Classes/LFCub::, link::Classes/LFTri::, link::Classes/LFSaw::, link::Classes/Impulse::
52 || arguments: code::frequency, phase, mul, add::
54 code::
55 // parabolic approximation of sine
56 { LFPar.ar(LFPar.kr(LFPar.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
57 { LFPar.ar(LFPar.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
58 { LFPar.ar(800,0,0.1) }.scope(1, zoom: 4);
59 // since it is not band limited, there are aliasing artifacts
60 { LFPar.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);
62 code::
63 // cubic approximation of sine
64 { LFCub.ar(LFCub.kr(LFCub.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
65 { LFCub.ar(LFCub.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
66 { LFCub.ar(800,0,0.1) }.scope(1, zoom: 4);
67 { LFCub.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);
69 code::
70 { LFTri.ar(LFTri.kr(LFTri.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
71 { LFTri.ar(LFTri.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
72 { LFTri.ar(800,0,0.1) }.scope(1, zoom: 4);
73 { LFTri.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);
75 code::
76 { LFSaw.ar(LFSaw.kr(LFSaw.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
77 { LFSaw.ar(LFSaw.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
78 { LFSaw.ar(100,0,0.1) }.scope(1, zoom: 4);
79 { LFSaw.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);
81 code::
82 { Impulse.ar(LFTri.kr(LFTri.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
83 { Impulse.ar(LFTri.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
84 { Impulse.ar(100,0,0.1) }.scope(1, zoom: 4);
85 { Impulse.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);
88 ## link::Classes/LFPulse::, link::Classes/VarSaw::
89 || arguments: code::frequency, phase, width, mul, add::
91 code::
92 { LFPulse.ar(LFPulse.kr(LFPulse.kr(0.2,0,0.5,8,10),0,0.5, 400,800),0,0.5,0.1) }.scope(1, zoom: 4);
93 { LFPulse.ar(LFPulse.kr(3, 0, 0.3, 200, 200), 0, 0.2, 0.1) }.scope(1, zoom: 4);
94 { LFPulse.ar(XLine.kr(100,15000,6),0,0.5,0.1) }.scope(1, zoom: 4);
96 code::
97 // pulse width modulation
98 { LFPulse.ar(100,0,MouseY.kr(0,1),0.1) }.scope(1, zoom: 4);
99 { LFPulse.ar(100,0,LFTri.kr(0.2,0,0.5,0.5),0.1) }.scope(1, zoom: 4);
101 code::
102 { VarSaw.ar(VarSaw.kr(VarSaw.kr(0.2,0,0.2,8,10),0,0.2, 400,800),0,0.2,0.1) }.scope(1, zoom: 4);
103 { VarSaw.ar(VarSaw.kr(0.2, 0, 0.2, 400,800),0,0.2,0.1) }.scope(1, zoom: 4);
104 { VarSaw.ar(XLine.kr(100,15000,6),0,0.2,0.1) }.scope(1, zoom: 4);
106 code::
107 // pulse width modulation
108 { VarSaw.ar(100,0,MouseY.kr(0,1),0.1) }.scope(1, zoom: 4);
109 { VarSaw.ar(100,0,LFTri.kr(0.2,0,0.5,0.5),0.1) }.scope(1, zoom: 4);
112 ## link::Classes/SyncSaw::
113 || arguments: code::syncFreq, sawFreq, mul, add::
115 code::
116 { SyncSaw.ar(100, MouseX.kr(100, 1000), 0.1) }.scope(1, zoom: 4);
117 { SyncSaw.ar(100, Line.kr(100, 800, 12), 0.1) }.scope(1, zoom: 4);
121 subsection:: Band Limited Oscillators
123 link::Classes/SinOsc::, link::Classes/FSinOsc::, link::Classes/Blip::, link::Classes/Saw::, link::Classes/Pulse:: - will not alias. 
125 definitionlist::
126 ## link::Classes/SinOsc::, link::Classes/FSinOsc::
127 || arguments: code::frequency, phase, mul, add::
128 code::
129 { SinOsc.ar(SinOsc.kr(SinOsc.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
130 { SinOsc.ar(SinOsc.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
131 { SinOsc.ar(800,0,0.1) }.scope(1, zoom: 4);
132 { SinOsc.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);
134 code::
135 { FSinOsc.ar(800,0,0.1) }.scope(1, zoom: 4);
136 // FSinOsc should not be frequency modulated. 
137 // Since it is based on a filter at the edge of stability, it will blow up:
138 { FSinOsc.ar(FSinOsc.kr(FSinOsc.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
141 ## link::Classes/Blip::
142 || arguments: code::frequency, numHarmonics, mul, add::
143 code::
144 { Blip.ar(XLine.kr(20000,200,6),100,0.2) }.scope(1);
145 { Blip.ar(XLine.kr(100,15000,6),100,0.2) }.scope(1); // no aliasing
146 // modulate number of harmonics
147 { Blip.ar(200,Line.kr(1,100,20),0.2) }.scope(1);
150 ## link::Classes/Saw::
151 || arguments: code::frequency, mul, add::
152 code::
153 { Saw.ar(XLine.kr(20000,200,6),0.2) }.scope(1);
154 { Saw.ar(XLine.kr(100,15000,6),0.2) }.scope(1); // no aliasing
157 ## link::Classes/Pulse::
158 || arguments: code::frequency, width, mul, add::
159 code::
160 { Pulse.ar(XLine.kr(20000,200,6),0.3,0.2) }.scope(1);
161 { Pulse.ar(XLine.kr(100,15000,6),0.3,0.2) }.scope(1); // no aliasing
163 // modulate pulse width
164 { Pulse.ar(200, Line.kr(0.01,0.99,8), 0.2) }.scope(1);
166 // two band limited square waves thru a resonant low pass filter
167 { RLPF.ar(Pulse.ar([100,250],0.5,0.1), XLine.kr(8000,400,5), 0.05) }.scope(1);
170 ## link::Classes/Klang:: - sine oscillator bank
171 || arguments: code:: `[ frequencies, amplitudes, phases ], mul, add ::
172 code::
173 { Klang.ar(`[ [800, 1000, 1200],[0.3, 0.3, 0.3],[pi,pi,pi]], 1, 0) * 0.4}.scope(1);
175 { Klang.ar(`[ {exprand(400, 2000)}.dup(16), nil, nil ], 1, 0) * 0.04 }.scope(1);
179 subsection:: Table Oscillators
181 link::Classes/Osc::, link::Classes/COsc::, link::Classes/VOsc::, link::Classes/VOsc3:: - uses a buffer allocated on the server.
183 code::
185 b = Buffer.alloc(s, 2048, 1, bufnum: 80);
186 b.sine1(1.0/(1..6), true, true, true);
190 definitionlist::
191 ## link::Classes/Osc::
192 || arguments: code:: buffer number, frequency, phase, mul, add ::
194 code::
195 { Osc.ar(80, 100, 0, 0.1) }.scope(1, zoom:4);
197 b.sine1(1.0/(1..12));
198 b.sine1(1.0/(1..24));
199 b.sine1(1.0/(1..32));
200 b.sine1([1.0/(1,3..12), 0].flop.flat.postln);
201 b.sine1([1.0/(1,3..32).squared, 0].flop.flat.postln);
202 b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
203 b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
204 b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
205 b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
206 b.sine1({1.0.rand2.cubed}.dup(8).round(1e-3).postln);
207 b.sine1({1.0.rand2.cubed}.dup(12).round(1e-3).postln);
208 b.sine1({1.0.rand2.cubed}.dup(16).round(1e-3).postln);
209 b.sine1({1.0.rand2.cubed}.dup(24).round(1e-3).postln);
212 ## link::Classes/COsc:: - two oscillators, detuned
213 || arguments: code:: buffer number, frequency, beat frequency, mul, add ::
214 code::
215 b.sine1(1.0/(1..6), true, true, true);
217 { COsc.ar(80, 100, 1, 0.1) }.scope(1, zoom:4);
218 // change buffer as above.
221 ## link::Classes/VOsc:: - multiple wave table crossfade oscillators
222 || arguments: code:: buffer number, frequency, phase, mul, add ::
223 code::
225 // allocate tables 80 to 87
226 8.do {|i| s.sendMsg(\b_alloc, 80+i, 1024); };
230 // fill tables 80 to 87
231 8.do({|i|
232         var n, a;
233         // generate array of harmonic amplitudes
234         n = (i+1)**2; // num harmonics for each table: [1,4,9,16,25,36,49,64]
235         a = {|j| ((n-j)/n).squared }.dup(n);
236         // fill table
237         s.listSendMsg([\b_gen, 80+i, \sine1, 7] ++ a);
241 { VOsc.ar(MouseX.kr(80,87), 120, 0, 0.3) }.scope(1, zoom:4);
244 // allocate and fill tables 80 to 87
245 8.do({|i|
246         // generate array of harmonic amplitudes
247         a = {1.0.rand2.cubed }.dup((i+1)*4);
248         // fill table
249         s.listSendMsg([\b_gen, 80+i, \sine1, 7] ++ a);
254 ## link::Classes/VOsc3:: - three VOscs summed.
255 || arguments: code:: buffer number, freq1, freq2, freq3, beat frequency, mul, add ::
256 code::
257 // chorusing
258 { VOsc3.ar(MouseX.kr(80,87), 120, 121.04, 119.37, 0.2) }.scope(1, zoom:4);
260 // chords
261 { VOsc3.ar(MouseX.kr(80,87), 120, 151.13, 179.42, 0.2) }.scope(1, zoom:4);
265 section:: Aperiodic Sources: Noise.
267 subsection:: LF "Low Frequency" Noise Generators.
269 definitionlist::
270 ## link::Classes/LFNoise0::, link::Classes/LFNoise1::, link::Classes/LFNoise2::, link::Classes/LFClipNoise::
271 || arguments: code:: frequency, mul, add ::
272 code::
273 { LFClipNoise.ar(MouseX.kr(200, 10000, 1), 0.125) }.scope(1);
274 { LFNoise0.ar(MouseX.kr(200, 10000, 1), 0.25) }.scope(1);
275 { LFNoise1.ar(MouseX.kr(200, 10000, 1), 0.25) }.scope(1);
276 { LFNoise2.ar(MouseX.kr(200, 10000, 1), 0.25) }.scope(1);
278 // used as controls
279 { LFPar.ar(LFClipNoise.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
280 { LFPar.ar(LFNoise0.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
281 { LFPar.ar(LFNoise1.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
282 { LFPar.ar(LFNoise2.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
286 subsection:: Broad Spectrum Noise Generators
288 definitionlist::
289 ## link::Classes/ClipNoise::, link::Classes/WhiteNoise::, link::Classes/PinkNoise::, link::Classes/BrownNoise::, link::Classes/GrayNoise::
290 || arguments: code:: mul, add ::
291 code::
292 { ClipNoise.ar(0.2) }.scope(1);
293 { WhiteNoise.ar(0.2) }.scope(1);
294 { PinkNoise.ar(0.4) }.scope(1);
295 { BrownNoise.ar(0.2) }.scope(1);
296 { GrayNoise.ar(0.2) }.scope(1);
300 subsection:: Impulse Noise Generators
302 definitionlist::
303 ## link::Classes/Dust::, link::Classes/Dust2::
304 || arguments: code:: density, mul, add ::
305 code::
306 { Dust.ar(MouseX.kr(1,10000,1), 0.4) }.scope(1, zoom:4);
307 { Dust2.ar(MouseX.kr(1,10000,1), 0.4) }.scope(1, zoom:4);
311 subsection:: Chaotic Noise Generators
313 definitionlist::
314 ## link::Classes/Crackle::
315 || arguments: code:: chaosParam, mul, add ::
316 code::
317 { Crackle.ar(MouseX.kr(1,2), 0.5) }.scope(1);
321 section:: Filters
323 subsection:: Low Pass, High Pass
325 definitionlist::
326 ## link::Classes/LPF::, link::Classes/HPF:: - 12 dB / octave
327 || arguments: code:: in, freq, mul, add ::
328 code::
329 { LPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
330 { HPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
331 { LPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
332 { HPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
336 subsection:: Band Pass, Band Cut
338 definitionlist::
339 ## link::Classes/BPF::, link::Classes/BRF:: - 12 dB / octave
340 || arguments: code:: in, freq, rq, mul, add ::
342 rq is the reciprocal of the Q of the filter,
343 or in other words: the bandwidth in Hertz = rq * freq.
344 code::
345 { BPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.4, 0.4) }.scope(1);
346 { BRF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.4, 0.2) }.scope(1);
347 { BPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.4, 0.4) }.scope(1);
348 { BRF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.4, 0.2) }.scope(1);
350 // modulating the bandwidth
351 { BPF.ar(WhiteNoise.ar, 3000, MouseX.kr(0.01,0.7,1), 0.4) }.scope(1);
355 subsection:: Resonant Low Pass, High Pass, Band Pass
357 definitionlist::
358 ## link::Classes/RLPF::, link::Classes/RHPF:: - 12 dB / octave
359 || arguments: code:: in, freq, rq, mul, add ::
360 code::
361 { RLPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
362 { RHPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
363 { RLPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
364 { RHPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
367 ## link::Classes/Resonz:: - resonant band pass filter with uniform amplitude
368 || arguments: code:: in, freq, rq, mul, add ::
369 code::
370 // modulate frequency
371 { Resonz.ar(WhiteNoise.ar(0.5), XLine.kr(1000,8000,10), 0.05) }.scope(1);
373 // modulate bandwidth
374 { Resonz.ar(WhiteNoise.ar(0.5), 2000, XLine.kr(1, 0.001, 8)) }.scope(1);
376 // modulate bandwidth opposite direction
377 { Resonz.ar(WhiteNoise.ar(0.5), 2000, XLine.kr(0.001, 1, 8)) }.scope(1);
380 ## link::Classes/Ringz:: - ringing filter.
381 || arguments: code:: in, frequency, ring time, mul, add ::
383 Internally it is the same as Resonz but the bandwidth is expressed as a ring time.
384 code::
385 { Ringz.ar(Dust.ar(3, 0.3), 2000, 2) }.scope(1, zoom:4);
387 { Ringz.ar(WhiteNoise.ar(0.005), 2000, 0.5) }.scope(1);
389 // modulate frequency
390 { Ringz.ar(WhiteNoise.ar(0.005), XLine.kr(100,3000,10), 0.5) }.scope(1, zoom:4);
392 { Ringz.ar(Impulse.ar(6, 0, 0.3),  XLine.kr(100,3000,10), 0.5) }.scope(1, zoom:4);
394 // modulate ring time
395 { Ringz.ar(Impulse.ar(6, 0, 0.3), 2000, XLine.kr(0.04, 4, 8)) }.scope(1, zoom:4);
399 subsection:: Simpler Filters
400 definitionlist::
401 ## link::Classes/OnePole::, link::Classes/OneZero:: - 6 dB / octave
403 code::
404 { OnePole.ar(WhiteNoise.ar(0.5), MouseX.kr(-0.99, 0.99)) }.scope(1);
405 { OneZero.ar(WhiteNoise.ar(0.5), MouseX.kr(-0.49, 0.49)) }.scope(1);
409 subsection:: NonLinear Filters
410 definitionlist::
411 ## link::Classes/Median::, link::Classes/Slew::
413 code::
414 // a signal with impulse noise.
415 { Saw.ar(500, 0.1) + Dust2.ar(100, 0.9) }.scope(1);
416 // after applying median filter
417 { Median.ar(3, Saw.ar(500, 0.1) + Dust2.ar(100, 0.9)) }.scope(1);
419 // a signal with impulse noise.
420 { Saw.ar(500, 0.1) + Dust2.ar(100, 0.9) }.scope(1);
421 // after applying slew rate limiter
422 { Slew.ar(Saw.ar(500, 0.1) + Dust2.ar(100, 0.9),1000,1000) }.scope(1);
426 subsection:: Formant Filter
427 definitionlist::
428 ## link::Classes/Formlet:: - A filter whose impulse response is similar to a FOF grain.
430 code::
431 { Formlet.ar(Impulse.ar(MouseX.kr(2,300,1), 0, 0.4), 800, 0.01, 0.1) }.scope(1, zoom:4);
434 ## link::Classes/Klank:: - resonant filter bank
435 || arguments: code:: `[ frequencies, amplitudes, ring times ], mul, add ::
437 code::
438 { Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], Impulse.ar(2, 0, 0.1)) }.play;
440 { Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], Dust.ar(8, 0.1)) }.play;
442 { Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar(0.007)) }.play;
444 { Klank.ar(`[ {exprand(200, 4000)}.dup(12), nil, nil ], PinkNoise.ar(0.007)) }.scope(1);
446 { Klank.ar(`[ (1..13)*200, 1/(1..13), nil ], PinkNoise.ar(0.01)) }.scope(1);
448 { Klank.ar(`[ (1,3..13)*200, 1/(1,3..13), nil ], PinkNoise.ar(0.01)) }.scope(1);
452 section:: Distortion
454 definitionlist::
455 ## abs, max, squared, cubed
457 code::
458 { SinOsc.ar(300, 0, 0.2) }.scope(1);
459 { SinOsc.ar(300, 0, 0.2).abs }.scope(1);
460 { SinOsc.ar(300, 0, 0.2).max(0) }.scope(1);
461 { SinOsc.ar(300, 0).squared * 0.2 }.scope(1);
462 { SinOsc.ar(300, 0).cubed * 0.2 }.scope(1);
465 ## distort, softclip, clip2, fold2, wrap2, 
467 code::
468 { SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).distort * 0.2 }.scope(1);
469 { SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).softclip * 0.2 }.scope(1);
470 { SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).clip2(1) * 0.2 }.scope(1);
471 { SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).fold2(1) * 0.2 }.scope(1);
472 { SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).wrap2(1) * 0.2 }.scope(1);
473 { SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).wrap2(1) * 0.2 }.scope(1);
476 ## scaleneg
478 code::
479 { SinOsc.ar(200, 0, 0.2).scaleneg(MouseX.kr(-1,1)) }.scope(1);
482 ## waveshaping by phase modulating a 0 Hz sine oscillator
483 || (currently there is a limit of 8pi)
484 code::
487         var in;
488         in = SinOsc.ar(300, 0, MouseX.kr(0.1,8pi,1));
489         SinOsc.ar(0, in, 0.2); // 0 Hz sine oscillator
490 }.scope(1);
494 ## link::Classes/Shaper:: - input is used to look up a value in a table.
495 || Chebyshev polynomials are typically used to fill the table.
497 code::
498 s.sendMsg(\b_alloc, 80, 1024); // allocate table
499 // fill with chebyshevs
500 s.listSendMsg([\b_gen, 80, \cheby, 7] ++ {1.0.rand2.squared}.dup(6));
502 { Shaper.ar(80, SinOsc.ar(600, 0, MouseX.kr(0,1))) * 0.3; }.scope(1);
504 s.listSendMsg([\b_gen, 80, \cheby, 7] ++ {1.0.rand2.squared}.dup(6));
505 s.listSendMsg([\b_gen, 80, \cheby, 7] ++ {1.0.rand2.squared}.dup(6));
509 section:: Panning
510 code::
512 s = Server.internal;
513 Server.default = s;
514 s.quit;
515 s.options.numOutputBusChannels = 8;
516 s.options.numInputBusChannels = 8;
517 s.boot;
521 definitionlist::
522 ## link::Classes/Pan2:: - equal power stereo pan a mono source
523 || arguments: code:: in, pan position, level ::
525 pan controls typically range from -1 to +1
527 code::
528 { Pan2.ar(BrownNoise.ar, MouseX.kr(-1,1), 0.3) }.scope(2);
529 { Pan2.ar(BrownNoise.ar, SinOsc.kr(0.2), 0.3) }.scope(2);
532 ## link::Classes/LinPan2:: - linear pan a mono source (not equal power)
533 || arguments: code:: in, pan position, level ::
535 code::
536 { LinPan2.ar(BrownNoise.ar, MouseX.kr(-1,1), 0.3) }.scope(2);
537 { LinPan2.ar(BrownNoise.ar, SinOsc.kr(0.2), 0.3) }.scope(2);
540 ## link::Classes/Balance2:: - balance a stereo source
541 || arguments: code:: left in, right in, pan position, level ::
542 code::
543 { Balance2.ar(BrownNoise.ar, BrownNoise.ar, MouseX.kr(-1,1), 0.3) }.scope(2);
546 ## link::Classes/Pan4:: - equal power quad panner
548 code::
549 { Pan4.ar(BrownNoise.ar, MouseX.kr(-1,1), MouseY.kr(1,-1), 0.3) }.scope(4);
552 ## link::Classes/PanAz:: - azimuth panner to any number of channels
553 || arguments: code:: num channels, in, pan position, level, width ::
554 code::
555 { PanAz.ar(5, BrownNoise.ar, MouseX.kr(-1,1), 0.3, 2) }.scope(5);
557 // change width to 3
558 { PanAz.ar(5, BrownNoise.ar, MouseX.kr(-1,1), 0.3, 3) }.scope(5);
561 ## link::Classes/XFade2:: - equal power cross fade between two inputs
562 || arguments: code:: in1, in2, crossfade, level ::
563 code::
564 { XFade2.ar(BrownNoise.ar, SinOsc.ar(500), MouseX.kr(-1,1), 0.3) }.scope(1);
567 ## link::Classes/PanB2:: and link::Classes/DecodeB2:: - 2D ambisonics panner and decoder
569 code::
572         var w, x, y, p, lf, rf, rr, lr;
573         
574         p = BrownNoise.ar; // source
575         
576         // B-format encode
577         #w, x, y = PanB2.ar(p, MouseX.kr(-1,1), 0.3); 
578         
579         // B-format decode to quad. outputs in clockwise order
580         #lf, rf, rr, lr = DecodeB2.ar(4, w, x, y);
581         
582         [lf, rf, lr, rr] // reorder to my speaker arrangement: Lf Rf Lr Rr
583 }.scope(4);
587 ## link::Classes/Rotate2:: - rotate a sound field of ambisonic or even stereo sound.
589 code::
592         // rotation of stereo sound via mouse 
593         var x, y;
594         x = Mix.fill(4, { LFSaw.ar(200 + 2.0.rand2, 0, 0.1) }); // left in
595         y = WhiteNoise.ar * LFPulse.kr(3,0,0.7,0.2); // right in
596         #x, y = Rotate2.ar(x, y, MouseX.kr(0,2));
597         [x,y]
598 }.scope(2);
603 section:: Reverbs
605 definitionlist::
606 ## link::Classes/FreeVerb::
608 code::
611         // play with the room size
612         var x;
613         x = Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], Dust.ar(2, 0.1));
614         x = Pan2.ar(x, -0.2);
615         x = [x[0], DelayC.ar(x[1], 0.01, 0.01)]; // de-correlate
616         FreeVerb.ar(x, 0.75, 0.9, 0.4);
617 }.scope;
621 ## link::Classes/GVerb::
623 code::
626         // play with the room size
627         var x;
628         x = Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], Dust.ar(2, 0.1));
629         GVerb.ar(x, 105, 5, 0.7, 0.8, 60, 0.1, 0.5, 0.4) + x;
630 }.scope;
635 section:: Delays and Buffer UGens
637 definitionlist::
638 ## link::Classes/DelayN::, link::Classes/DelayL::, link::Classes/DelayC:: - simple delays
640 list::
641 ## N - no interpolation
642 ## L - linear interpolation
643 ## C - cubic interpolation
645 arguments: code:: in, maximum delay time, current delay time, mul, add ::
647 code::
649 // Dust randomly triggers Decay to create an exponential 
650 // decay envelope for the WhiteNoise input source
652 z = Decay.ar(Dust.ar(1,0.5), 0.3, WhiteNoise.ar);
653 DelayN.ar(z, 0.1, 0.1, 1, z); // input is mixed with delay via the add input
654 }.scope(1, zoom: 4)
657 code::
660 z = Decay.ar(Impulse.ar(2,0,0.4), 0.3, WhiteNoise.ar);
661 DelayL.ar(z, 0.3, MouseX.kr(0,0.3), 1, z); // input is mixed with delay via the add input
662 }.scope(1, zoom: 4)
666 ## link::Classes/CombN::, link::Classes/CombL::, link::Classes/CombC:: - feedback delays
667 || arguments: code:: in, maximum delay time, current delay time, echo decay time, mul, add ::
669 code::
670 // used as an echo. 
671 { CombN.ar(Decay.ar(Dust.ar(1,0.5), 0.2, WhiteNoise.ar), 0.2, 0.2, 3) }.scope(1, zoom:4);
673 // Comb used as a resonator. The resonant fundamental is equal to 
674 // reciprocal of the delay time.
675 { CombN.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), 0.2) }.scope(1);
677 { CombL.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), 0.2) }.scope(1);
679 { CombC.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), 0.2) }.scope(1);
681 // with negative feedback:
682 { CombN.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), -0.2) }.scope(1);
684 { CombL.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), -0.2) }.scope(1);
686 { CombC.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), -0.2) }.scope(1);
688 { CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/100, 1/100, 3) }.play;
689 { CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/200, 1/200, 3) }.play;
690 { CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/300, 1/300, 3) }.play;
691 { CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/400, 1/400, 3) }.scope(1, zoom:4);
694 ## link::Classes/AllpassN::, link::Classes/AllpassL::, link::Classes/AllpassC:: - allpass delay
695 || arguments: code:: in, maximum delay time, current delay time, echo decay time, mul, add ::
696 code::
699         var z;
700         z = Decay.ar(Dust.ar(1,0.5), 0.1, WhiteNoise.ar);
701         8.do { z = AllpassL.ar(z, 0.04, 0.04.rand, 2) };
702         z
703 }.scope(1);
707 ## link::Classes/PlayBuf:: - buffer playback
708 || arguments: code:: numChannels, buffer number, rate, trigger, start pos, loop ::
709 code::
710 // read sound
711 b = Buffer.read(s, "sounds/a11wlk01.wav");
713 { SinOsc.ar(800 + (700 * PlayBuf.ar(1,b, BufRateScale.kr(b),  loop:1)),0,0.3) }.scope(1);
715 // loop is true
716 { PlayBuf.ar(1,b, BufRateScale.kr(b), loop:1) }.scope(1);
718 code::
719 // trigger one shot on each pulse
722         var trig;
723         trig = Impulse.kr(2.0);
724         PlayBuf.ar(1,b,BufRateScale.kr(b),trig,0,0);
725 }.scope(1);
728 // trigger one shot on each pulse
731         var trig;
732         trig = Impulse.kr(XLine.kr(0.1,100,30));
733         PlayBuf.ar(1,b,BufRateScale.kr(b),trig,5000,0);
734 }.scope(1);
737 code::
738 // mouse control of trigger rate and startpos
741         var trig;
742         trig = Impulse.kr(MouseY.kr(0.5,200,1));
743         PlayBuf.ar(1,b,BufRateScale.kr(b),trig,MouseX.kr(0,BufFrames.kr(b)),1)
744 }.scope(1);
747 // accelerating pitch
750         var rate;
751         rate = XLine.kr(0.1,100,60);
752         PlayBuf.ar(1, b, rate, 1.0,0.0, 1.0)
753 }.scope(1);
756 // sine wave control of playback rate. negative rate plays backwards
759         var rate;
760         rate = FSinOsc.kr(XLine.kr(0.2,8,30), 0, 3, 0.6);
761         PlayBuf.ar(1,b,BufRateScale.kr(b)*rate,1,0,1)
762 }.scope(1);
765 // zig zag around sound 
768         var rate;
769         rate = LFNoise2.kr(XLine.kr(1,20,60), 2);
770         PlayBuf.ar(1,b,BufRateScale.kr(b) * rate,1,0,1)
771 }.scope(1);
775 // free sound
776 b.free;
780 section:: Granular Synthesis.
782 definitionlist::
783 ## link::Classes/TGrains:: - granulation of a buffer
784 || arguments: code:: numChannels, trigger, buffer number, rate, center pos, dur, pan, amp, interpolation ::
785 code::
786 // read sound
787 b = Buffer.read(s, "sounds/a11wlk01.wav");
791         var trate, dur;
792         trate = MouseY.kr(2,200,1);
793         dur = 4 / trate;
794         TGrains.ar(2, Impulse.ar(trate), b, 1, MouseX.kr(0,BufDur.kr(b)), dur, 0, 0.1, 2);
795 }.scope(2, zoom: 4);
800         var trate, dur, clk, pos, pan;
801         trate = MouseY.kr(8,120,1);
802         dur = 12 / trate;
803         clk = Impulse.kr(trate);
804         pos = MouseX.kr(0,BufDur.kr(b)) + TRand.kr(0, 0.01, clk);
805         pan = WhiteNoise.kr(0.6);
806         TGrains.ar(2, clk, b, 1, pos, dur, pan, 0.1);
807 }.scope(2, zoom: 4);
810 // 4 channels
813         var trate, dur, clk, pos, pan;
814         trate = MouseY.kr(8,120,1);
815         dur = 12 / trate;
816         clk = Impulse.kr(trate);
817         pos = MouseX.kr(0,BufDur.kr(b)) + TRand.kr(0, 0.01, clk);
818         pan = WhiteNoise.kr(0.6);
819         TGrains.ar(4, clk, b, 1, pos, dur, pan, 0.1);
820 }.scope(4, zoom: 4);
825         var trate, dur, clk, pos, pan;
826         trate = MouseY.kr(8,120,1);
827         dur = 4 / trate;
828         clk = Dust.kr(trate);
829         pos = MouseX.kr(0,BufDur.kr(b)) + TRand.kr(0, 0.01, clk);
830         pan = WhiteNoise.kr(0.6);
831         TGrains.ar(2, clk, b, 1, pos, dur, pan, 0.1);
832 }.scope(2, zoom: 4);
839         var trate, dur, clk, pos, pan;
840         trate = LinExp.kr(LFTri.kr(MouseY.kr(0.1,2,1)),-1,1,8,120);
841         dur = 12 / trate;
842         clk = Impulse.ar(trate);
843         pos = MouseX.kr(0,BufDur.kr(b));
844         pan = WhiteNoise.kr(0.6);
845         TGrains.ar(2, clk, b, 1, pos, dur, pan, 0.1);
846 }.scope(2, zoom: 4);
852         var trate, dur, clk, pos, pan;
853         trate = 12;
854         dur = MouseY.kr(0.2,24,1) / trate;
855         clk = Impulse.kr(trate);
856         pos = MouseX.kr(0,BufDur.kr(b)) + TRand.kr(0, 0.01, clk);
857         pan = WhiteNoise.kr(0.6);
858         TGrains.ar(2, clk, b, 1, pos, dur, pan, 0.1);
859 }.scope(2, zoom: 4);
864         var trate, dur, clk, pos, pan;
865         trate = 100;
866         dur = 8 / trate;
867         clk = Impulse.kr(trate);
868         pos = Integrator.kr(BrownNoise.kr(0.001));
869         pan = WhiteNoise.kr(0.6);
870         TGrains.ar(2, clk, b, 1, pos, dur, pan, 0.1);
871 }.scope(2, zoom: 4);
876         var trate, dur, clk, pos, pan;
877         trate = MouseY.kr(1,400,1);
878         dur = 8 / trate;
879         clk = Impulse.kr(trate);
880         pos = MouseX.kr(0,BufDur.kr(b));
881         pan = WhiteNoise.kr(0.8);
882         TGrains.ar(2, clk, b, 2 ** WhiteNoise.kr(2), pos, dur, pan, 0.1);
883 }.scope(2, zoom: 4);
888         var trate, dur;
889         trate = MouseY.kr(2,120,1);
890         dur = 1.2 / trate;
891         TGrains.ar(2, Impulse.ar(trate), b, (1.2 ** WhiteNoise.kr(3).round(1)), MouseX.kr(0,BufDur.kr(b)), dur, WhiteNoise.kr(0.6), 0.1);
892 }.scope(2, zoom: 4);
895 // free sound
896 b.free;
899 ## link::Classes/GrainSin:: - sine grain
900 || arguments: code:: numChannels, trigger, dur, freq, pan, envbufnum ::
902 code::
903 ( // using default window
905         var trigrate, winsize, trig;
906         trigrate = MouseX.kr(2, 120);
907         winsize = trigrate.reciprocal;
908         trig = Impulse.ar(trigrate);
909         GrainSin.ar(2, trig, winsize, TRand.ar(440.0, 880.0, trig), LFNoise1.kr(0.2),
910                 -1, 0.2)
911 }.scope(2, zoom: 4);
914 b = Buffer.sendCollection(s, Env([0, 1, 0], [0.5, 0.5], [8, -8]).discretize, 1);
916 ( // using user supplied window
918         var trigrate, winsize, trig;
919         trigrate = MouseX.kr(2, 120);
920         winsize = trigrate.reciprocal;
921         trig = Impulse.ar(trigrate);
922         GrainSin.ar(2, trig, winsize, TRand.ar(440.0, 880.0, trig), LFNoise1.kr(0.2),
923                 b, 0.2)
924 }.scope(2, zoom: 4);
928 see also link::Classes/GrainFM::, link::Classes/GrainBuf:: and link::Classes/GrainIn::
930 section:: Control
932 subsection:: Filters for Controls
934 definitionlist::
935 ## link::Classes/Decay:: - triggered exponential decay
936 || arguments: code:: in, decay time, mul, add ::
937 code::
938 { WhiteNoise.ar * Decay.ar(Impulse.ar(1), 0.9, 0.2) }.scope(1, zoom:4);
939 { WhiteNoise.ar * Decay.ar(Dust.ar(3), 0.9, 0.2) }.scope(1, zoom:4);
940 { SinOsc.ar(Decay.ar(Dust.ar(4), 0.5, 1000, 400), 0, 0.2) }.scope(1, zoom:4);
943 ## link::Classes/Decay2:: - triggered exponential attack and exponential decay 
944 || arguments: code:: trigger, attack time, decay time, mul, add ::
945 code::
946 { WhiteNoise.ar * Decay2.ar(Impulse.ar(1), 0.2, 0.9, 0.2) }.scope(1, zoom:4);
947 { WhiteNoise.ar * Decay2.ar(Dust.ar(3), 0.2, 0.9, 0.2) }.scope(1, zoom:4);
950 ## link::Classes/Lag::
951 || arguments: code:: trigger, duration ::
952 code::
953 { SinOsc.ar(Lag.ar(LFPulse.ar(2,0,0.5,800,400), MouseX.kr(0,0.5)), 0, 0.2) }.scope(1, zoom:4);
956 ## link::Classes/Integrator:: - leaky integrator
958 code::
959 { SinOsc.ar(Integrator.ar(Dust2.ar(8), 0.99999, 200, 800), 0, 0.2) }.scope(1)
963 subsection:: Triggers
965 definitionlist::
966 ## link::Classes/Trig::, link::Classes/Trig1:: - timed duration gate
967 || arguments: code:: trigger, duration ::
968 code::
969 // amplitude determined by amplitude of trigger
970 { Trig.ar(Dust.ar(2), 0.2) * FSinOsc.ar(800, 0, 0.4) }.scope(1, zoom:4);
971 // amplitude always the same.
972 { Trig1.ar(Dust.ar(2), 0.2) * FSinOsc.ar(800, 0, 0.4) }.scope(1, zoom:4)
975 ## link::Classes/TDelay:: - delays a trigger. only delays one pending trigger at a time.
976 || arguments: code:: trigger, delay time ::
977 code::
980         var trig;
981         trig = Dust.ar(2);
982         [(Trig1.ar(trig, 0.05) * FSinOsc.ar(600, 0, 0.2)),
983         (Trig1.ar(TDelay.ar(trig, 0.1), 0.05) * FSinOsc.ar(800, 0, 0.2))]
984 }.scope(2, zoom:4);
988 ## link::Classes/Latch:: - sample and hold
989 || arguments: code:: in, trigger ::
990 code::
991 { Blip.ar(Latch.ar(WhiteNoise.ar, Impulse.ar(9)) * 400 + 500, 4, 0.2) }.play;
992 { Blip.ar(Latch.ar(SinOsc.ar(0.3), Impulse.ar(9)) * 400 + 500, 4, 0.2) }.play;
995 ## link::Classes/Gate:: - pass or hold
996 || arguments: code:: in, trigger ::
997 code::
998 { Blip.ar(Gate.ar(LFNoise2.ar(40), LFPulse.ar(1)) * 400 + 500, 4, 0.2) }.scope(1, zoom:4);
1001 ## link::Classes/PulseCount:: - count triggers
1002 || arguments: code:: trigger, reset ::
1003 code::
1006 SinOsc.ar(
1007                         PulseCount.ar(Impulse.ar(10), Impulse.ar(0.4)) * 200, 
1008                         0, 0.05
1009                 )
1010 }.scope(2, zoom:4);
1014 ## link::Classes/PulseDivider::
1015 || arguments: code:: trigger, div, start ::
1016 code::
1018 {       
1019         var p, a, b;
1020         p = Impulse.ar(8);
1021         a = SinOsc.ar(1200, 0, Decay2.ar(p, 0.005, 0.1));
1022         b = SinOsc.ar(600,  0, Decay2.ar(PulseDivider.ar(p, MouseX.kr(1,8).round(1)), 0.005, 0.5));
1023         
1024         [a, b] * 0.4
1025 }.scope(2, zoom:4);
1029 ## link::Classes/EnvGen:: - envelope generator
1030 || envelope is specified using an instance of the link::Classes/Env:: class.
1031 code::
1032 { EnvGen.kr(Env.perc, doneAction:2) * SinOsc.ar(880,0,0.2) }.play;
1033 { EnvGen.kr(Env.perc(1,0.005,1,4), doneAction:2) * SinOsc.ar(880,0,0.2) }.play;
1035 { EnvGen.kr(Env.perc, Impulse.kr(2)) * SinOsc.ar(880,0,0.2) }.play;
1036 { EnvGen.kr(Env.perc, Dust.kr(3)) * SinOsc.ar(880,0,0.2) }.play;
1038 // for sustain envelopes a gate is required
1039 z = { arg gate=1; EnvGen.kr(Env.adsr, gate, doneAction:2) * SinOsc.ar(880,0,0.2) }.play;
1040 z.release;
1043 // randomly generated envelope
1044 z = { arg gate=1; 
1045         var env, n=32;
1046         env = Env(
1047                                 [0]++{1.0.rand.squared}.dup(n-1) ++ [0], 
1048                                 {rrand(0.005,0.2)}.dup(n),
1049                                 \lin, n-8, 8 );
1050         EnvGen.kr(env, gate, doneAction: 2) * LFTri.ar(220,0,0.4) 
1051 }.scope(1, zoom:4);
1053 z.release;
1057 section:: Spectral
1059 FFT, IFFT and the phase vocoder ugens.
1061 link::Classes/FFT:: calculates the spectrum of a sound, puts it into a buffer, and outputs a trigger each time the
1062 buffer is ready to process. The PV UGens process the spectrum when they receive the trigger.
1063 link::Classes/IFFT:: converts the spectrum back into sound.
1065 code::
1066 // alloc a buffer for the FFT
1067 b = Buffer.alloc(s,2048,1);
1068 // read a sound
1069 c = Buffer.read(s, "sounds/a11wlk01.wav");
1073 // do nothing
1075         var in, chain;
1076         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1077         chain = FFT(b, in);
1078         0.5 * IFFT(chain);
1079 }.scope(1);
1083 // pass only magnitudes above a threshold
1085         var in, chain;
1086         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1087         chain = FFT(b, in);
1088         chain = PV_MagAbove(chain, MouseX.kr(0.1,512,1)); 
1089         0.5 * IFFT(chain);
1090 }.scope(1);
1094 // pass only magnitudes below a threshold
1096         var in, chain;
1097         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1098         chain = FFT(b, in);
1099         chain = PV_MagBelow(chain, MouseX.kr(0.1,512,1)); 
1100         0.5 * IFFT(chain);
1101 }.scope(1);
1105 // brick wall filter.
1107         var in, chain;
1108         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1109         chain = FFT(b, in);
1110         chain = PV_BrickWall(chain, MouseX.kr(-1,1)); 
1111         0.5 * IFFT(chain);
1112 }.scope(1);
1116 // pass random frequencies. Mouse controls how many to pass.
1117 // trigger changes the frequencies periodically
1119         var in, chain;
1120         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1121         chain = FFT(b, in);
1122         chain = PV_RandComb(chain, MouseX.kr(0,1), Impulse.kr(0.4));
1123         0.5 * IFFT(chain);
1124 }.scope(1);
1128 // rectangular comb filter
1130         var in, chain;
1131         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1132         chain = FFT(b, in);
1133         chain = PV_RectComb(chain, 8, MouseY.kr(0,1), MouseX.kr(0,1));
1134         0.5 * IFFT(chain);
1135 }.scope(1);
1139 // freeze magnitudes
1141         var in, chain;
1142         in = PlayBuf.ar(1,c, BufRateScale.kr(c), loop:1);
1143         chain = FFT(b, in);
1144         chain = PV_MagFreeze(chain, LFPulse.kr(1, 0.75));
1145         0.5 * IFFT(chain);
1146 }.scope(1);
1151 section:: Techniques
1153 subsection:: Artificial Space
1154 Building a sense of space into a sound by setting up phase differences between the speakers.
1156 code::
1157 { var x; x = BrownNoise.ar(0.2); [x,x] }.scope(2); // correlated
1158 { {BrownNoise.ar(0.2)}.dup }.scope(2); // not correlated
1160 // correlated
1161 { var x; x = LPF.ar(BrownNoise.ar(0.2), MouseX.kr(100,10000)); [x,x] }.scope(2);
1162 // not correlated
1163 { LPF.ar({BrownNoise.ar(0.2)}.dup, MouseX.kr(100,10000)) }.scope(2);
1166 // correlated
1168 { var x; 
1169         x = Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar(7e-3)); 
1170         [x,x] 
1171 }.scope(2))
1172 // not correlated
1173 { Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar([7e-3,7e-3])) }.scope(2);
1175 // two waves mixed together coming out both speakers
1176 { var x; x = Mix.ar(VarSaw.ar([100,101], 0, 0.1, 0.2)); [x,x] }.scope(2);
1177 // two waves coming out each speaker independantly
1178 { VarSaw.ar([100,101], 0, 0.1, 0.2 * 1.414) }.scope(2); // * 1.414 to compensate for power
1180 // delays as cues to direction
1181 // mono
1182 { var x; x = LFTri.ar(1000,0,Decay2.ar(Impulse.ar(4,0,0.2),0.004,0.2)); [x,x]}.scope(2);
1185 // inter-speaker delays
1186 { var x; x = LFTri.ar(1000,0,Decay2.ar(Impulse.ar(4,0,0.2),0.004,0.2)); 
1187         [DelayC.ar(x,0.01,0.01),DelayC.ar(x,0.02,MouseX.kr(0.02, 0))]
1188 }.scope(2);
1192 // mixing two delays together
1193 // you hear a phasing sound but the sound is still flat.
1194 { var x; x = BrownNoise.ar(0.2); 
1195         x = Mix.ar([DelayC.ar(x,0.01,0.01),DelayC.ar(x,0.02,MouseX.kr(0,0.02))]);
1196         [x,x]
1197 }.scope(2);
1201 // more spatial sounding. phasing causes you to perceive directionality
1202 { var x; x = BrownNoise.ar(0.2); 
1203         [DelayC.ar(x,0.01,0.01),DelayC.ar(x,0.02,MouseX.kr(0.02, 0))]
1204 }.scope(2);
1208 subsection:: Parallel Structures
1209 code::
1212         // mixing sine oscillators in parallel
1213         var n = 16; // number of structures to make
1214         // mix together  parallel structures
1215         Mix.fill(n,             
1216                         // this function creates an oscillator at a random frequency
1217                         { FSinOsc.ar(200 + 1000.0.rand) }
1218         ) / (2*n)                       // scale amplitude
1219 }.scope(1);
1224         // mixing sine oscillators in parallel
1225         var n = 16; // number of structures to make
1226         // mix together  parallel structures
1227         Mix.fill(n,             
1228                         // this function creates an oscillator at a random frequency
1229                         { FSinOsc.ar(200 + 1000.0.rand + [0, 0.5]) }
1230         ) / (2*n)                       // scale amplitude
1231 }.scope(2);
1236         // mixing sine oscillators in parallel
1237         var n = 16; // number of structures to make
1238         // mix together  parallel structures
1239         Mix.fill(n,             
1240                         { 
1241                                 var amp;
1242                                 amp = FSinOsc.kr(exprand(0.1,1),2pi.rand).max(0);
1243                                 Pan2.ar(
1244                                         FSinOsc.ar(exprand(100,1000.0), 0, amp),
1245                                         1.0.rand2)
1246                         }
1247         ) / (2*n)                       // scale amplitude
1248 }.scope(2);
1254         var n;
1255         n = 8; // number of 'voices'
1256         Mix.ar( // mix all stereo pairs down.
1257                 Pan2.ar( // pan the voice to a stereo position
1258                         CombL.ar( // a comb filter used as a string resonator
1259                                 Dust.ar( // random impulses as an excitation function
1260                                         // an array to cause expansion of Dust to n channels
1261                                         // 1 means one impulse per second on average
1262                                         1.dup(n), 
1263                                         0.3 // amplitude
1264                                 ), 
1265                                 0.01, // max delay time in seconds
1266                                 // array of different random lengths for each 'string'
1267                                 {0.004.rand+0.0003}.dup(n), 
1268                                 4 // decay time in seconds
1269                         ),
1270                         {1.0.rand2}.dup(n) // give each voice a different pan position
1271                 )
1272         )
1273 }.scope(2, zoom:4);
1277 subsection:: Serial structures
1278 code::
1280 play {
1281     var sig, chain;
1283     // The original sound source
1284     sig = sum({ SinOsc.ar(rrand(50,6000),0,2*Decay.ar(Dust2.ar(1),0.1)).tanh } ! 7);
1286     chain = sig;    // Start with the original signal
1287     8.do {|i|       // Loop 8 times. For each loop, connect the signal through something.
1289         // A simple reverb
1290         chain = LeakDC.ar(AllpassL.ar(LPF.ar(chain*0.9,3000), 0.2, {0.19.rand+0.01}!2, 3));
1291     };
1293     Limiter.ar(sig+chain);    // dry + wet