23. Event (2) – added to Event(1)

Event

Inherits from: Object : Collection : Set : Dictionary : IdentityDictionary : Environment
related classes: Pattern

Event는 하나의 Environment로서 Play메세지를 받을 경우에 액션을 취하도록 만들어진 것입니다. 
Event는 defaultParentEvent를 제공하는데 이는 다양한 다른 event type 을 정의해주고 각각의 type에 default key.value pairs를 제공해 줍니다. 
type 은 type, note의 값에 의해 결정됩니다. 

Event 는 다음과 같이 정의되지요

  ( ).play; // the default note
  
  ( freq: 500, pan: -1) .play; // 500 Hz, panned left
  
  ( degree: (0..12)).play // a whole tone cluster
  
Events 와 SynthDefs

SynthDef에서는 하나의 instrument를 정의내려 줍니다. 그 instrument는 ‘Event’에 의해 실행되어 주는 것이지요.
다음의 예제를 보세요.

 SynthDef(“pm”, { | out=0, freq=440, amp=0.1, pan=0, gate=1, ratio = 1, index = 1, ar = 0.1, dr = 0.1 |
  var z;
  z = LPF.ar(
  PMOsc.ar(freq, freq * ratio, Linen.kr(gate, ar,index, dr), 0, 0.3),
  XLine.kr(Rand(4000,5000), Rand(2500,3200), 1)
  ) * Linen.kr(gate, 0.01, 0.7, dr, 2);
  OffsetOut.ar(out, Pan2.ar(z, pan, amp));
  }).store;

 (instrument: “pm”).play;
 
 (instrument: “pm”, ratio: 3.42, index: 12, freq: 150, ar: 8, dr: 3, sustain: 10).play;
 

pm이라는 SynthDef가 정의내려졌고, store에 의해 서버에 보내집니다.
** 서버에 보내진 synthDef를 확인하시려면 Users/Library/ApplicationSupports/SuperCollider3/synthdefs폴더에 저장됩니다. 이를 사용하여 다른곳에서도 SynthDef에 접근 가능한데 참고하세요.
 아래 instrument를 사용하여 pm을 연주해 주는것이 event입니다. 
 
Multi-channel Expansion


만약에 어떤 action과 관련된 key가 array로 주어졌을 경우, 그 액션은 array의 각각 요소에 반복되게 됩니다.
( degree: (0..12)).play; 
만약 여러개의 key들이 array로 주어졌을 경우, 같은 경우가 벌어집니다. 
더 작은 array들이 순환하며 반복됩니다.
  ( degree: (0..12), amp: [0,0.1]).play // every other note of the diatonic cluster: stacked thirds

  ( note: (0..12), amp: [0,0.1]).play // every other note of the semitone cluster: a wholetone cluster again

  ( note: (0..12), amp: [0,0, 0.1]).play // every third note of the semitone cluster: a diminished chord

Arrayed Arguments


array를 SynthDef 을 제어하는데 사용할 수 있습니다.
(
SynthDef(“test”, 
{ | out = 0, amp = 0.01, freq = #[300,400,400], pan, gate = 1 |
 var audio, env;
 audio = Mix.ar(Pulse.ar(freq, 0.5)); // this is a mixture of three oscillators
 env = Linen.kr(gate, susLevel: amp , doneAction: 2); // envelope deletes the synt when done
 audio = audio * env;
 OffsetOut.ar(0, audio );
}).store;
)
어떤 event내에서 이렇게 array로 이루어진 argument들은 Ref나 부가적인 array 이내에 쓰여져야 하는데, 이는 multi-channel expantion을 위해 쓰여진 argument들로부터 구분되기 위함입니다.

(instrument: test, note: `[0,2,4]).play // one synth, use Ref to prevent multi-channel expansion

(instrument: test, note: [[0,2,4]]).play // one synth, use enclosing array to prevent multi-channel expansion

(instrument: test, note: [[0,2,4], 6 +[0,2,4]]).play // two synths



 Events 와 Patterns
 
 이벤트는 페턴 라이브러리와 함께 적용됩니다. pattern은 다른곳에서 다루어 보도록 하겠습니다.
 
 다음은 몇개의 keys가 패턴에 적용된 예제입니다. 여기서 key들은 stepsPerOctave, note, ctranspose, detune, sustain, dur, db가 사용되었습니다. 
 (
p = Pbind(*[
  stepsPerOctave: Pstep(Pseq((2..12).mirror, inf),12), // 3 – 12 tone e.t. scales
  note: Pseq((0..12).mirror, inf),

  ctranspose: Pwhite(-0.2, 0.2), // detune up to +-20 cents
  detune: Pwhite(-1.0, 1.0), // detune up to 1 Hz  
  
  sustain: Prand([0.2, 0.2, 0.2, 4], inf), // notes last 0.2 or 4 seconds
  dur: Prand([0.2, 0.2, 0.2, 0.2, 0.2, 0.8], inf), // 1 in 6 chance note lasts 0.8 seconds
  
  db: Pstep( // 4 beat accent structure  
  Pseq([-15, -25, -20, -25], inf), 
  0.8
  )
 ]);
 p.play  


Event play method.
Event나 다른 Environment가 use(function)메세지를 받으면, 그 즉시 이는 currentEnvironment가 되며, function을 계산하고, currentEnvironment의 원래 값을 다시 저장합니다. 
이렇게 확인합니다. 
currentEnvironment.at(keyName) 
또는 ~keyName
다른 키값을 설정할때에는 
currentEnvironment.put(keyNamem value) 
이는 다음과 같습니다.
~keyName = value
여기서 ~keyName은 물론 저장된 키의 값, 위의 예제로 볼것같으면 ~sustain, 또는 ~dur등등이 되겠지요.
‘~Name'(environment)에 대해서는 다음에 다시 깊게 다루도록 하겠습니다.

다음은 Enevt play method를 정의한 예제입니다.
play {
  if (parent.isNil) { parent = defaultParentEvent };
  this.use { ~play.value };
 }

위에 예제를 설명하자면 ~play에 저장되어 있는 값이 없다면 defaultParentEvent를 재생하라는 뜻입니다.

Timing control with Event’s delta method

Event는 또한 패턴 내에 타이밍을 어떻게 할것인지 설정할 수 있습니다. Event 의 delta는 ~delta의 값을 보내거나, 그 값이 nil일경우, ~dur * ~stretch를 보냅니다.
 
Pattern들은 자체내의 tempo control을 가진 TempoClock에 의해 play됩니다. 이 템포는 ~tempo로 조절합니다. tempo의 변화는 TempoClock에의해 조정된 스케줄 전반에 영향을 끼칩니다. 따라서 템포는 stretch가 하나의 패턴에 제한된 커느롤을 주는동안 global tempo를 제공합니다.

The structure of defaultParentEvent

default parent event 는 default값들과 function들의 collection을 제공하고, 이는 Event에서 여러 다른 사용을 위해 요구되는 사항들입니다. 이 default들은 partialEvents에서 정의되며, 이는 default parent event의 구븐된 양상을 정의해 줍니다. 

 playerEvent defines ~play, ~type and ~eventTypes
 serverEvent server, group, addAction
 durEvent duration, tempo and articulation
 ampEvent volume, pan, MIDI velocity
 pitchEvent pitch specified in many different ways
 bufferEvent buffers on the server
 midiEvent midi
 
 
Useful keys for notes

Event의 사용은 대게 key들을 overwriting하는것입니다. 다음은 note들의 default values들을 정의하는데 유용하게 사용되는 key들로서 그들이 정의된 범위의 partialEvent에 의해 group화 됩니다.

serverEvent에 있는 key들은 그 server에 요구/사용되는 값을 주고, 이는 그 그룹 안에 위치한 node tree내부에 위치합니다.

serverEvent keys:
 server: nil, // nil일 경우, Server.default 가 사용
 instrument: default, // SynthDef의 이름
 group: 1, // server에 있는 그룹(또는 a synth)의 nodeID 
  // 다른 node가 첨가되기 이전 또는 이후
 addAction: 0, // 0, 1, 2, 3 or addToHead, addToTail, addBefore, addAfter
 out: 0, // 보통은 bus number, SynthDef에 의해 결정.

ampEvent는 volume을 결정합니다. ~amp는 ~db로부터 그 값을 결정하는데 쓰이는 function입니다. 우리는 ~amp를 overwriting함으로 바로 amplitude를 변화시킬수 있으며, 또는 ~db를 변화하여 decibel을 변화시킬수 있습니다.

ampEvent keys:
 amp: #{ ~db.dbamp },
 db: -20.0,
 pan: 0.0, 

durEvent 는 여러개의 key를 가지고있는데, 이는 note의 timing을 결정하는데 사용됩니다. ~sustain은 ~legato를 사용하여 sustain(note의 지속)을 결정하는데 사용되는 function입니다. ~amp와 마탄가지로 sustain을 바로 바꾸는데 사용될 수 있습니다. 
durEvent keys:
 tempo: nil, // changes tempo of a TempoClock
 dur: 1.0, // delay until next note
 stretch: 1.0, // inverse of tempo control, specific to the Event’s stream
 legato: 0.8, // ratio of sustain to duration
 sustain: #{ ~dur * ~legato * ~stretch }, 
 lag: 0.0, // delay relative to current time position of Stream
 strum: 0.0 // “breaks” a chord

pitchEvent는 가장 복잡한 시스템을 가진 function으로 pitch를 결정하는데 다양한 방법을 제공합니다.
 ~freq pitch를 바로 frequency in Hertz로 전환.
 ~midinote pitch를 바로 ffractional MIDI note 로 전환(69 -> 440)
 ~note pitch를 scale degree i(~stepsPerOctave)로 전환.-> equal tempered scale
 ~degree pitch를 scale (~scale)내의 degree 로 전환.
 
 
 
Event는 또한 transition key들을 제공합니다. 
 ~mtranspose modal transposition of degree within a scale
 ~root transposes root of the scale  
 ~gtranspose gamut(whole scale) transposition within the~stepsPerOctave equal tempered scale
 ~ctranspose chromatic transposition within the 12 tone equal tempered scale
 ~harmonic multiplies the frequency determined by ~midinote, typically to an overtone
 ~detune directly alters frequency

pitchEvent keys:
 mtranspose: 0, // modal transposition of degree
 gtranspose: 0.0, // gamut transposition of note within a ~stepsPerOctave e.t. scale
 ctranspose: 0.0, // chromatic transposition of midinote within 12 tone e.t. scale
 
 octave: 5.0, // octave offest of note
 root: 0.0, // root of the scale
 degree: 0, // degree in scale
 scale: #[0, 2, 4, 5, 7, 9, 11], // diatonic major scale
 stepsPerOctave: 12.0,
 detune: 0.0, // detune in Hertz
 harmonic: 1.0, // harmonic ratio
 
 note: #{
  (~degree + ~mtranspose).degreeToKey(~scale, ~stepsPerOctave);
 },
 midinote: #{
  ((~note.value + ~gtranspose + ~root) / ~stepsPerOctave + ~octave) * 12.0; 
 },
 freq: #{
  (~midinote.value + ~ctranspose).midicps * ~harmonic;
 },

Event types

Event는 ~play를 통해 play메세지에 응답합니다. 

 { ~eventTypes[~type].value(server); },
위의 function은 ~type값을 사용하여 function을 ~eventTypes에 있는 dictionary로 부터 선택합니다. eventTypes의 collection은 *addEventType(key, function)를 사용하여 쉽게 확장됩니다. 

다름은 group and note의 event types을 사용한 예제입니다. :

 (type: group, id: 2).play // create a group with nodeID 2
 (type: note, freq: 500, group: 2).play // play a synth in that group

다음은 현재 쓰이는 event type들입니다.
 
 group creates group, id must be specified
 note instrument specifies synthdef
 note_score 
 midi
 
 monoNote
 monoSet
 monoOff
 
 on play synth, id must be specified
 off release synth (or free if no gate)
 kill free synth
 set set parameter of synth
 
 
 bus write ~array to control buses starting at ~out
 
 alloc allocate ~bufnum with ~numframes and ~numchannels
 free free ~bufnum
 gen send ~gencmd to ~bufnum
 load load ~filename starting at ~frame into ~bufnum
 read
 
 setProperties ~receiver, ~args 
  sends setter messages to ~receiver for each key in ~args that
  has a nonNil value in the Event 
 tree creates a tree of groups. ~tree can be an array of nodeIDs, and may contain associations to further nested arrays.
 
 phrase instead of playing a single synth from a SynthDef with ~instrument, it looks up a Pdef and plays a cluster of sounds.
 
 


22. A Tour of UGens

SIGNAL PROCESSING in SuperCollider

1. A Tour of available Unit Generators.
 SuperCollider has over 250 unit generators. 
 If you count the unary and binary operators, there are over 300. 
 This tour covers many, but not all of them.
 
 categories of unit generators: 
  sources: periodic, aperiodic 
  filters
  distortion 
  panning
  delays and buffer ugens
  control: envelopes, triggers, counters, gates, lags, decays
  spectral 

2. Techniques  
 broadening a sound: 
  decorrelation, beat frequencies, delays.
 series and parallel structures.


(
s = Server.internal;
Server.default = s;
s.boot;
)

Periodic Sources: Oscillators.

LF – “Low Frequency” Unit Generators.

LFPar, LFCub, LFTri, Impulse, LFSaw, LFPulse, VarSaw, SyncSaw

geometric waveforms, not band limited.
will cause aliasing at higher frequencies.


LFPar, LFCub, LFTri, LFSaw, Impulse
arguments: frequency, phase, mul, add

// parabolic approximation of sine
{ LFPar.ar(LFPar.kr(LFPar.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFPar.ar(LFPar.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFPar.ar(800,0,0.1) }.scope(1, zoom: 4);
// since it is not band limited, there are aliasing artifacts
{ LFPar.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);

// cubic approximation of sine
{ LFCub.ar(LFCub.kr(LFCub.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFCub.ar(LFCub.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFCub.ar(800,0,0.1) }.scope(1, zoom: 4);
{ LFCub.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);


{ LFTri.ar(LFTri.kr(LFTri.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFTri.ar(LFTri.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFTri.ar(800,0,0.1) }.scope(1, zoom: 4);
{ LFTri.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);


{ LFSaw.ar(LFSaw.kr(LFSaw.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFSaw.ar(LFSaw.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ LFSaw.ar(100,0,0.1) }.scope(1, zoom: 4);
{ LFSaw.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);


{ Impulse.ar(LFTri.kr(LFTri.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ Impulse.ar(LFTri.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ Impulse.ar(100,0,0.1) }.scope(1, zoom: 4);
{ Impulse.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);

LFPulse, VarSaw
arguments: frequency, phase, width, mul, add

{ 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);
{ LFPulse.ar(LFPulse.kr(3, 0, 0.3, 200, 200), 0, 0.2, 0.1) }.scope(1, zoom: 4);
{ LFPulse.ar(XLine.kr(100,15000,6),0,0.5,0.1) }.scope(1, zoom: 4);

// pulse width modulation
{ LFPulse.ar(100,0,MouseY.kr(0,1),0.1) }.scope(1, zoom: 4);
{ LFPulse.ar(100,0,LFTri.kr(0.2,0,0.5,0.5),0.1) }.scope(1, zoom: 4);


{ 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);
{ VarSaw.ar(VarSaw.kr(0.2, 0, 0.2, 400,800),0,0.2,0.1) }.scope(1, zoom: 4);
{ VarSaw.ar(XLine.kr(100,15000,6),0,0.2,0.1) }.scope(1, zoom: 4);

// pulse width modulation
{ VarSaw.ar(100,0,MouseY.kr(0,1),0.1) }.scope(1, zoom: 4);
{ VarSaw.ar(100,0,LFTri.kr(0.2,0,0.5,0.5),0.1) }.scope(1, zoom: 4);

SyncSaw
arguments: syncFreq, sawFreq, mul, add

{ SyncSaw.ar(100, MouseX.kr(100, 1000), 0.1) }.scope(1, zoom: 4);
{ SyncSaw.ar(100, Line.kr(100, 800, 12), 0.1) }.scope(1, zoom: 4);


Band Limited Oscillators

SinOsc, FSinOsc, Blip, Saw, Pulse
will not alias. 

SinOsc, FSinOsc
arguments: frequency, phase, mul, add

{ SinOsc.ar(SinOsc.kr(SinOsc.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ SinOsc.ar(SinOsc.kr(0.2, 0, 400,800),0,0.1) }.scope(1, zoom: 4);
{ SinOsc.ar(800,0,0.1) }.scope(1, zoom: 4);
{ SinOsc.ar(XLine.kr(100,15000,6),0,0.1) }.scope(1, zoom: 4);

{ FSinOsc.ar(800,0,0.1) }.scope(1, zoom: 4);
// FSinOsc should not be frequency modulated. 
// Since it is based on a filter at the edge of stability, it will blow up:
{ FSinOsc.ar(FSinOsc.kr(FSinOsc.kr(0.2,0,8,10),0, 400,800),0,0.1) }.scope(1, zoom: 4);

Blip
arguments: frequency, numHarmonics, mul, add

{ Blip.ar(XLine.kr(20000,200,6),100,0.2) }.scope(1);
{ Blip.ar(XLine.kr(100,15000,6),100,0.2) }.scope(1); // no aliasing
// modulate number of harmonics
{ Blip.ar(200,Line.kr(1,100,20),0.2) }.scope(1);

Saw
arguments: frequency, mul, add

{ Saw.ar(XLine.kr(20000,200,6),0.2) }.scope(1);
{ Saw.ar(XLine.kr(100,15000,6),0.2) }.scope(1); // no aliasing

Pulse
arguments: frequency, width, mul, add

{ Pulse.ar(XLine.kr(20000,200,6),0.3,0.2) }.scope(1);
{ Pulse.ar(XLine.kr(100,15000,6),0.3,0.2) }.scope(1); // no aliasing

// modulate pulse width
{ Pulse.ar(200, Line.kr(0.01,0.99,8), 0.2) }.scope(1);

// two band limited square waves thru a resonant low pass filter
{ RLPF.ar(Pulse.ar([100,250],0.5,0.1), XLine.kr(8000,400,5), 0.05) }.scope(1);

Klang – sine oscillator bank
arguments: `[ frequencies, amplitudes, phases ], mul, add

{ Klang.ar(`[ [800, 1000, 1200],[0.3, 0.3, 0.3],[pi,pi,pi]], 1, 0) * 0.4}.scope(1);

{ Klang.ar(`[ {exprand(400, 2000)}.dup(16), nil, nil ], 1, 0) * 0.04 }.scope(1);


Table Oscillators

Osc, COsc, VOsc, VOsc3
Use a buffer allocated on the server.

Osc
arguments: buffer number, frequency, phase, mul, add.

(
b = Buffer.alloc(s, 2048, 1, bufnum: 80);
b.sine1(1.0/(1..6), true, true, true);
)

{ Osc.ar(80, 100, 0, 0.1) }.scope(1, zoom:4);

b.sine1(1.0/(1..12));
b.sine1(1.0/(1..24));
b.sine1(1.0/(1..32));
b.sine1([1.0/(1,3..12), 0].flop.flat.postln);
b.sine1([1.0/(1,3..32).squared, 0].flop.flat.postln);
b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
b.sine1((1.dup(4) ++ 0.dup(8)).scramble.postln);
b.sine1({1.0.rand2.cubed}.dup(8).round(1e-3).postln);
b.sine1({1.0.rand2.cubed}.dup(12).round(1e-3).postln);
b.sine1({1.0.rand2.cubed}.dup(16).round(1e-3).postln);
b.sine1({1.0.rand2.cubed}.dup(24).round(1e-3).postln);

COsc – two oscillators, detuned
arguments: buffer number, frequency, beat frequency, mul, add.

b.sine1(1.0/(1..6), true, true, true);

{ COsc.ar(80, 100, 1, 0.1) }.scope(1, zoom:4);
// change buffer as above.


VOsc – multiple wave table crossfade oscillators
arguments: buffer number, frequency, phase, mul, add.

(
// allocate tables 80 to 87
8.do {|i| s.sendMsg(b_alloc, 80+i, 1024); };
)

(
// fill tables 80 to 87
8.do({|i|
 var n, a;
 // generate array of harmonic amplitudes
 n = (i+1)**2; // num harmonics for each table: [1,4,9,16,25,36,49,64]
 a = {|j| ((n-j)/n).squared }.dup(n);
 // fill table
 s.listSendMsg([b_gen, 80+i, sine1, 7] ++ a);
});
)

{ VOsc.ar(MouseX.kr(80,87), 120, 0, 0.3) }.scope(1, zoom:4);

(
// allocate and fill tables 80 to 87
8.do({|i|
 // generate array of harmonic amplitudes
 a = {1.0.rand2.cubed }.dup((i+1)*4);
 // fill table
 s.listSendMsg([b_gen, 80+i, sine1, 7] ++ a);
});
)

VOsc3 – three VOscs summed.
arguments: buffer number, freq1, freq2, freq3, beat frequency, mul, add.

// chorusing
{ VOsc3.ar(MouseX.kr(80,87), 120, 121.04, 119.37, 0.2) }.scope(1, zoom:4);

// chords
{ VOsc3.ar(MouseX.kr(80,87), 120, 151.13, 179.42, 0.2) }.scope(1, zoom:4);

Aperiodic Sources: Noise.


LF “Low Frequency” Noise Generators.

LFNoise0, LFNoise1, LFNoise2, LFClipNoise
arguments: frequency, mul, add

{ LFClipNoise.ar(MouseX.kr(200, 10000, 1), 0.125) }.scope(1);
{ LFNoise0.ar(MouseX.kr(200, 10000, 1), 0.25) }.scope(1);
{ LFNoise1.ar(MouseX.kr(200, 10000, 1), 0.25) }.scope(1);
{ LFNoise2.ar(MouseX.kr(200, 10000, 1), 0.25) }.scope(1);

// used as controls
{ LFPar.ar(LFClipNoise.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
{ LFPar.ar(LFNoise0.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
{ LFPar.ar(LFNoise1.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);
{ LFPar.ar(LFNoise2.kr(MouseX.kr(0.5, 64, 1), 200, 400), 0, 0.2) }.scope(1, zoom:8);


Broad Spectrum Noise Generators

ClipNoise, WhiteNoise, PinkNoise, BrownNoise, GrayNoise
arguments: mul, add

{ ClipNoise.ar(0.2) }.scope(1);
{ WhiteNoise.ar(0.2) }.scope(1);
{ PinkNoise.ar(0.4) }.scope(1);
{ BrownNoise.ar(0.2) }.scope(1);
{ GrayNoise.ar(0.2) }.scope(1);

Impulse Noise Generators

Dust, Dust2
arguments: density, mul, add

{ Dust.ar(MouseX.kr(1,10000,1), 0.4) }.scope(1, zoom:4);
{ Dust2.ar(MouseX.kr(1,10000,1), 0.4) }.scope(1, zoom:4);


Chaotic Noise Generators

Crackle
arguments: chaosParam, mul, add

{ Crackle.ar(MouseX.kr(1,2), 0.5) }.scope(1);

Filters

Low Pass, High Pass

LPF, HPF – 12 dB / octave
arguments: in, freq, mul, add

{ LPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
{ HPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
{ LPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);
{ HPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2) }.scope(1);

Band Pass, Band Cut

BPF, BRF – 12 dB / octave
arguments: in, freq, rq, mul, add
rq is the reciprocal of the Q of the filter,
or in other words: the bandwidth in Hertz = rq * freq.

{ BPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.4, 0.4) }.scope(1);
{ BRF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.4, 0.2) }.scope(1);
{ BPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.4, 0.4) }.scope(1);
{ BRF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.4, 0.2) }.scope(1);

// modulating the bandwidth
{ BPF.ar(WhiteNoise.ar, 3000, MouseX.kr(0.01,0.7,1), 0.4) }.scope(1);

Resonant Low Pass, High Pass, Band Pass

RLPF, RHPF – 12 dB / octave
arguments: in, freq, rq, mul, add

{ RLPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
{ RHPF.ar(WhiteNoise.ar, MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
{ RLPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);
{ RHPF.ar(Saw.ar(100), MouseX.kr(1e2,2e4,1), 0.2, 0.2) }.scope(1);

Resonz – resonant band pass filter with uniform amplitude
arguments: in, freq, rq, mul, add

// modulate frequency
{ Resonz.ar(WhiteNoise.ar(0.5), XLine.kr(1000,8000,10), 0.05) }.scope(1);

// modulate bandwidth
{ Resonz.ar(WhiteNoise.ar(0.5), 2000, XLine.kr(1, 0.001, 8)) }.scope(1);

// modulate bandwidth opposite direction
{ Resonz.ar(WhiteNoise.ar(0.5), 2000, XLine.kr(0.001, 1, 8)) }.scope(1);

Ringz – ringing filter.
Internally it is the same as Resonz but the bandwidth is expressed as a ring time.
arguments: in, frequency, ring time, mul, add

{ Ringz.ar(Dust.ar(3, 0.3), 2000, 2) }.scope(1, zoom:4);

{ Ringz.ar(WhiteNoise.ar(0.005), 2000, 0.5) }.scope(1);

// modulate frequency
{ Ringz.ar(WhiteNoise.ar(0.005), XLine.kr(100,3000,10), 0.5) }.scope(1, zoom:4);

{ Ringz.ar(Impulse.ar(6, 0, 0.3), XLine.kr(100,3000,10), 0.5) }.scope(1, zoom:4);

// modulate ring time
{ Ringz.ar(Impulse.ar(6, 0, 0.3), 2000, XLine.kr(0.04, 4, 8)) }.scope(1, zoom:4);


Simpler Filters
6 dB / octave

{ OnePole.ar(WhiteNoise.ar(0.5), MouseX.kr(-0.99, 0.99)) }.scope(1);
{ OneZero.ar(WhiteNoise.ar(0.5), MouseX.kr(-0.49, 0.49)) }.scope(1);

NonLinear Filters
Median, Slew

// a signal with impulse noise.
{ Saw.ar(500, 0.1) + Dust2.ar(100, 0.9) }.scope(1);
// after applying median filter
{ Median.ar(3, Saw.ar(500, 0.1) + Dust2.ar(100, 0.9)) }.scope(1);

// a signal with impulse noise.
{ Saw.ar(500, 0.1) + Dust2.ar(100, 0.9) }.scope(1);
// after applying slew rate limiter
{ Slew.ar(Saw.ar(500, 0.1) + Dust2.ar(100, 0.9),1000,1000) }.scope(1);


Formant Filter 
Formlet – A filter whose impulse response is similar to a FOF grain.

{ Formlet.ar(Impulse.ar(MouseX.kr(2,300,1), 0, 0.4), 800, 0.01, 0.1) }.scope(1, zoom:4);

Klank – resonant filter bank
arguments: `[ frequencies, amplitudes, ring times ], mul, add

{ Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], Impulse.ar(2, 0, 0.1)) }.play;

{ Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], Dust.ar(8, 0.1)) }.play;

{ Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar(0.007)) }.play;

{ Klank.ar(`[ {exprand(200, 4000)}.dup(12), nil, nil ], PinkNoise.ar(0.007)) }.scope(1);

{ Klank.ar(`[ (1..13)*200, 1/(1..13), nil ], PinkNoise.ar(0.01)) }.scope(1);

{ Klank.ar(`[ (1,3..13)*200, 1/(1,3..13), nil ], PinkNoise.ar(0.01)) }.scope(1);


Distortion

abs, max, squared, cubed

{ SinOsc.ar(300, 0, 0.2) }.scope(1);
{ SinOsc.ar(300, 0, 0.2).abs }.scope(1);
{ SinOsc.ar(300, 0, 0.2).max(0) }.scope(1);
{ SinOsc.ar(300, 0).squared * 0.2 }.scope(1);
{ SinOsc.ar(300, 0).cubed * 0.2 }.scope(1);

distort, softclip, clip2, fold2, wrap2, 

{ SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).distort * 0.2 }.scope(1);
{ SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).softclip * 0.2 }.scope(1);
{ SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).clip2(1) * 0.2 }.scope(1);
{ SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).fold2(1) * 0.2 }.scope(1);
{ SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).wrap2(1) * 0.2 }.scope(1);
{ SinOsc.ar(300, 0, MouseX.kr(0.1,80,1)).wrap2(1) * 0.2 }.scope(1);

scaleneg

{ SinOsc.ar(200, 0, 0.2).scaleneg(MouseX.kr(-1,1)) }.scope(1);

waveshaping by phase modulating a 0 Hz sine oscillator
(currently there is a limit of 8pi)

(

 var in;
 in = SinOsc.ar(300, 0, MouseX.kr(0.1,8pi,1));
 SinOsc.ar(0, in, 0.2); // 0 Hz sine oscillator
}.scope(1);
)

Shaper 
input is used to look up a value in a table.
Chebyshev polynomials are typically used to fill the table.



s.sendMsg(b_alloc, 80, 1024); // allocate table
// fill with chebyshevs
s.listSendMsg([b_gen, 80, cheby, 7] ++ {1.0.rand2.squared}.dup(6));

{ Shaper.ar(80, SinOsc.ar(600, 0, MouseX.kr(0,1))) * 0.3; }.scope(1);

s.listSendMsg([b_gen, 80, cheby, 7] ++ {1.0.rand2.squared}.dup(6));
s.listSendMsg([b_gen, 80, cheby, 7] ++ {1.0.rand2.squared}.dup(6));

Panning

(
s = Server.internal;
Server.default = s;
s.quit;
s.options.numOutputBusChannels = 8;
s.options.numInputBusChannels = 8;
s.boot;
)

Pan2 – equal power stereo pan a mono source
arguments: in, pan position, level
pan controls typically range from -1 to +1

{ Pan2.ar(BrownNoise.ar, MouseX.kr(-1,1), 0.3) }.scope(2);
{ Pan2.ar(BrownNoise.ar, SinOsc.kr(0.2), 0.3) }.scope(2);

LinPan2 – linear pan a mono source (not equal power)
arguments: in, pan position, level

{ LinPan2.ar(BrownNoise.ar, MouseX.kr(-1,1), 0.3) }.scope(2);
{ LinPan2.ar(BrownNoise.ar, SinOsc.kr(0.2), 0.3) }.scope(2);

Balance2 – balance a stereo source
arguments: left in, right in, pan position, level

{ Balance2.ar(BrownNoise.ar, BrownNoise.ar, MouseX.kr(-1,1), 0.3) }.scope(2);

Pan4 – equal power quad panner

{ Pan4.ar(BrownNoise.ar, MouseX.kr(-1,1), MouseY.kr(1,-1), 0.3) }.scope(4);

PanAz – azimuth panner to any number of channels
arguments: num channels, in, pan position, level, width

{ PanAz.ar(5, BrownNoise.ar, MouseX.kr(-1,1), 0.3, 2) }.scope(5);

// change width to 3
{ PanAz.ar(5, BrownNoise.ar, MouseX.kr(-1,1), 0.3, 3) }.scope(5);


XFade2 – equal power cross fade between two inputs
arguments: in1, in2, crossfade, level

{ XFade2.ar(BrownNoise.ar, SinOsc.ar(500), MouseX.kr(-1,1), 0.3) }.scope(1);


PanB2 and DecodeB2 – 2D ambisonics panner and decoder

(
{
 var w, x, y, p, lf, rf, rr, lr;
 
 p = BrownNoise.ar; // source
 
 // B-format encode
 #w, x, y = PanB2.ar(p, MouseX.kr(-1,1), 0.3); 
 
 // B-format decode to quad. outputs in clockwise order
 #lf, rf, rr, lr = DecodeB2.ar(4, w, x, y);
 
 [lf, rf, lr, rr] // reorder to my speaker arrangement: Lf Rf Lr Rr
}.scope(4);
)

Rotate2 – rotate a sound field of ambisonic or even stereo sound.

(
{
 // rotation of stereo sound via mouse 
 var x, y;
 x = Mix.fill(4, { LFSaw.ar(200 + 2.0.rand2, 0, 0.1) }); // left in
 y = WhiteNoise.ar * LFPulse.kr(3,0,0.7,0.2); // right in
 #x, y = Rotate2.ar(x, y, MouseX.kr(0,2));
 [x,y]
}.scope(2);
)

Delays and Buffer UGens

DelayN, DelayL, DelayC
simple delays
N – no interpolation
L – linear interpolation
C – cubic interpolation
arguments: in, maximum delay time, current delay time, mul, add

(
// Dust randomly triggers Decay to create an exponential 
// decay envelope for the WhiteNoise input source
{
z = Decay.ar(Dust.ar(1,0.5), 0.3, WhiteNoise.ar);
DelayN.ar(z, 0.1, 0.1, 1, z); // input is mixed with delay via the add input
}.scope(1, zoom: 4)
)

(
{
z = Decay.ar(Impulse.ar(2,0,0.4), 0.3, WhiteNoise.ar);
DelayL.ar(z, 0.3, MouseX.kr(0,0.3), 1, z); // input is mixed with delay via the add input
}.scope(1, zoom: 4)
)

CombN, CombL, CombC
feedback delays
arguments: in, maximum delay time, current delay time, echo decay time, mul, add


// used as an echo. 
{ CombN.ar(Decay.ar(Dust.ar(1,0.5), 0.2, WhiteNoise.ar), 0.2, 0.2, 3) }.scope(1, zoom:4);

// Comb used as a resonator. The resonant fundamental is equal to 
// reciprocal of the delay time.
{ CombN.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), 0.2) }.scope(1);

{ CombL.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), 0.2) }.scope(1);

{ CombC.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), 0.2) }.scope(1);

// with negative feedback:
{ CombN.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), -0.2) }.scope(1);

{ CombL.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), -0.2) }.scope(1);

{ CombC.ar(WhiteNoise.ar(0.02), 0.01, XLine.kr(0.0001, 0.01, 20), -0.2) }.scope(1);

{ CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/100, 1/100, 3) }.play;
{ CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/200, 1/200, 3) }.play;
{ CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/300, 1/300, 3) }.play;
{ CombC.ar(Decay.ar(Dust.ar(1,0.1), 0.2, WhiteNoise.ar), 1/400, 1/400, 3) }.scope(1, zoom:4);


AllpassN, AllpassL, AllpassC
allpass delay
arguments: in, maximum delay time, current delay time, echo decay time, mul, add

(
{
 var z;
 z = Decay.ar(Dust.ar(1,0.5), 0.1, WhiteNoise.ar);
 8.do { z = AllpassL.ar(z, 0.04, 0.04.rand, 2) };
 z
}.scope(1);
)
 
PlayBuf
buffer playback
arguments: numChannels, buffer number, rate, trigger, start pos, loop

// read sound
b = Buffer.read(s, “sounds/a11wlk01.wav”);

{ SinOsc.ar(800 + (700 * PlayBuf.ar(1,b.bufnum, BufRateScale.kr(b.bufnum), loop:1)),0,0.3) }.scope(1);

// loop is true
{ PlayBuf.ar(1,b.bufnum, BufRateScale.kr(b.bufnum), loop:1) }.scope(1);


// trigger one shot on each pulse
(
{
 var trig;
 trig = Impulse.kr(2.0);
 PlayBuf.ar(1,b.bufnum,BufRateScale.kr(b.bufnum),trig,0,0);
}.scope(1);
)

// trigger one shot on each pulse
(
{
 var trig;
 trig = Impulse.kr(XLine.kr(0.1,100,30));
 PlayBuf.ar(1,b.bufnum,BufRateScale.kr(b.bufnum),trig,5000,0);
}.scope(1);
)

// mouse control of trigger rate and startpos
(
{
 var trig;
 trig = Impulse.kr(MouseY.kr(0.5,200,1));
 PlayBuf.ar(1,b.bufnum,BufRateScale.kr(b.bufnum),trig,MouseX.kr(0,BufFrames.kr(b.bufnum)),1)
}.scope(1);
)

// accelerating pitch
(
{
 var rate;
 rate = XLine.kr(0.1,100,60);
 PlayBuf.ar(1, b.bufnum, rate, 1.0,0.0, 1.0)
}.scope(1);
)

// sine wave control of playback rate. negative rate plays backwards
(
{
 var rate;
 rate = FSinOsc.kr(XLine.kr(0.2,8,30), 0, 3, 0.6);
 PlayBuf.ar(1,b.bufnum,BufRateScale.kr(b.bufnum)*rate,1,0,1)
}.scope(1);
)

// zig zag around sound 
(
{
 var rate;
 rate = LFNoise2.kr(XLine.kr(1,20,60), 2);
 PlayBuf.ar(1,b.bufnum,BufRateScale.kr(b.bufnum) * rate,1,0,1)
}.scope(1);
)


// free sound
b.free;


TGrains
granulation of a buffer
arguments: numChannels, trigger, buffer number, rate, center pos, dur, pan, amp, interpolation

// read sound
b = Buffer.read(s, “sounds/a11wlk01.wav”);

(
{
 var trate, dur;
 trate = MouseY.kr(2,200,1);
 dur = 4 / trate;
 TGrains.ar(2, Impulse.ar(trate), b.bufnum, 1, MouseX.kr(0,BufDur.kr(b.bufnum)), dur, 0, 0.1, 2);
}.scope(2, zoom: 4);
)

(
{
 var trate, dur, clk, pos, pan;
 trate = MouseY.kr(8,120,1);
 dur = 12 / trate;
 clk = Impulse.kr(trate);
 pos = MouseX.kr(0,BufDur.kr(b.bufnum)) + TRand.kr(0, 0.01, clk);
 pan = WhiteNoise.kr(0.6);
 TGrains.ar(2, clk, b.bufnum, 1, pos, dur, pan, 0.1);
}.scope(2, zoom: 4);
)

// 4 channels
(
{
 var trate, dur, clk, pos, pan;
 trate = MouseY.kr(8,120,1);
 dur = 12 / trate;
 clk = Impulse.kr(trate);
 pos = MouseX.kr(0,BufDur.kr(b.bufnum)) + TRand.kr(0, 0.01, clk);
 pan = WhiteNoise.kr(0.6);
 TGrains.ar(4, clk, b.bufnum, 1, pos, dur, pan, 0.1);
}.scope(4, zoom: 4);
)

(
{
 var trate, dur, clk, pos, pan;
 trate = MouseY.kr(8,120,1);
 dur = 4 / trate;
 clk = Dust.kr(trate);
 pos = MouseX.kr(0,BufDur.kr(b.bufnum)) + TRand.kr(0, 0.01, clk);
 pan = WhiteNoise.kr(0.6);
 TGrains.ar(2, clk, b.bufnum, 1, pos, dur, pan, 0.1);
}.scope(2, zoom: 4);
)



(
{
 var trate, dur, clk, pos, pan;
 trate = LinExp.kr(LFTri.kr(MouseY.kr(0.1,2,1)),-1,1,8,120);
 dur = 12 / trate;
 clk = Impulse.ar(trate);
 pos = MouseX.kr(0,BufDur.kr(b.bufnum));
 pan = WhiteNoise.kr(0.6);
 TGrains.ar(2, clk, b.bufnum, 1, pos, dur, pan, 0.1);
}.scope(2, zoom: 4);
)


(
{
 var trate, dur, clk, pos, pan;
 trate = 12;
 dur = MouseY.kr(0.2,24,1) / trate;
 clk = Impulse.kr(trate);
 pos = MouseX.kr(0,BufDur.kr(b.bufnum)) + TRand.kr(0, 0.01, clk);
 pan = WhiteNoise.kr(0.6);
 TGrains.ar(2, clk, b.bufnum, 1, pos, dur, pan, 0.1);
}.scope(2, zoom: 4);
)

(
{
 var trate, dur, clk, pos, pan;
 trate = 100;
 dur = 8 / trate;
 clk = Impulse.kr(trate);
 pos = Integrator.kr(BrownNoise.kr(0.001));
 pan = WhiteNoise.kr(0.6);
 TGrains.ar(2, clk, b.bufnum, 1, pos, dur, pan, 0.1);
}.scope(2, zoom: 4);
)

(
{
 var trate, dur, clk, pos, pan;
 trate = MouseY.kr(1,400,1);
 dur = 8 / trate;
 clk = Impulse.kr(trate);
 pos = MouseX.kr(0,BufDur.kr(b.bufnum));
 pan = WhiteNoise.kr(0.8);
 TGrains.ar(2, clk, b.bufnum, 2 ** WhiteNoise.kr(2), pos, dur, pan, 0.1);
}.scope(2, zoom: 4);
)




(
{
 var trate, dur;
 trate = MouseY.kr(2,120,1);
 dur = 1.2 / trate;
 TGrains.ar(2, Impulse.ar(trate), b.bufnum, (1.2 ** WhiteNoise.kr(3).round(1)), MouseX.kr(0,BufDur.kr(b.bufnum)), dur, WhiteNoise.kr(0.6), 0.1);
}.scope(2, zoom: 4);
)

// free sound
b.free;


 
Control

Filters for Controls

Decay
triggered exponential decay
arguments: in, decay time, mul, add

{ WhiteNoise.ar * Decay.ar(Impulse.ar(1), 0.9, 0.2) }.scope(1, zoom:4);
{ WhiteNoise.ar * Decay.ar(Dust.ar(3), 0.9, 0.2) }.scope(1, zoom:4);
{ SinOsc.ar(Decay.ar(Dust.ar(4), 0.5, 1000, 400), 0, 0.2) }.scope(1, zoom:4);

Decay2
triggered exponential attack and exponential decay 
arguments: trigger, attack time, decay time, mul, add

{ WhiteNoise.ar * Decay2.ar(Impulse.ar(1), 0.2, 0.9, 0.2) }.scope(1, zoom:4);
{ WhiteNoise.ar * Decay2.ar(Dust.ar(3), 0.2, 0.9, 0.2) }.scope(1, zoom:4);

Lag
arguments: trigger, duration

{ SinOsc.ar(Lag.ar(LFPulse.ar(2,0,0.5,800,400), MouseX.kr(0,0.5)), 0, 0.2) }.scope(1, zoom:4);

Integrator
leaky integrator

{ SinOsc.ar(Integrator.ar(Dust2.ar(8), 0.99999, 200, 800), 0, 0.2) }.scope(1)


Triggers

Trig, Trig1
timed duration gate
arguments: trigger, duration

// amplitude determined by amplitude of trigger
{ Trig.ar(Dust.ar(2), 0.2) * FSinOsc.ar(800, 0, 0.4) }.scope(1, zoom:4);
// amplitude always the same.
{ Trig1.ar(Dust.ar(2), 0.2) * FSinOsc.ar(800, 0, 0.4) }.scope(1, zoom:4)

TDelay
delays a trigger. only delays one pending trigger at a time.
arguments: trigger, delay time

(

 var trig;
 trig = Dust.ar(2);
 [(Trig1.ar(trig, 0.05) * FSinOsc.ar(600, 0, 0.2)),
 (Trig1.ar(TDelay.ar(trig, 0.1), 0.05) * FSinOsc.ar(800, 0, 0.2))]
}.scope(2, zoom:4);
)

Latch
sample and hold
arguments: in, trigger

{ Blip.ar(Latch.ar(WhiteNoise.ar, Impulse.ar(9)) * 400 + 500, 4, 0.2) }.play;
{ Blip.ar(Latch.ar(SinOsc.ar(0.3), Impulse.ar(9)) * 400 + 500, 4, 0.2) }.play;

Gate
pass or hold
arguments: in, trigger

{ Blip.ar(Gate.ar(LFNoise2.ar(40), LFPulse.ar(1)) * 400 + 500, 4, 0.2) }.scope(1, zoom:4);


PulseCount
count triggers
arguments: trigger, reset

(
{
SinOsc.ar(
  PulseCount.ar(Impulse.ar(10), Impulse.ar(0.4)) * 200, 
  0, 0.05
  )
}.scope(2, zoom:4);
)

PulseDivider
arguments: trigger, div, start

(

 var p, a, b;
 p = Impulse.ar(8);
 a = SinOsc.ar(1200, 0, Decay2.ar(p, 0.005, 0.1));
 b = SinOsc.ar(600, 0, Decay2.ar(PulseDivider.ar(p, MouseX.kr(1,8).round(1)), 0.005, 0.5));
 
 [a, b] * 0.4
}.scope(2, zoom:4);
)


EnvGen
envelope generator
envelope is specified using an instance of the Env class.

{ EnvGen.kr(Env.perc, doneAction:2) * SinOsc.ar(880,0,0.2) }.play;
{ EnvGen.kr(Env.perc(1,0.005,1,4), doneAction:2) * SinOsc.ar(880,0,0.2) }.play;

{ EnvGen.kr(Env.perc, Impulse.kr(2)) * SinOsc.ar(880,0,0.2) }.play;
{ EnvGen.kr(Env.perc, Dust.kr(3)) * SinOsc.ar(880,0,0.2) }.play;

// for sustain envelopes a gate is required
z = { arg gate=1; EnvGen.kr(Env.adsr, gate, doneAction:2) * SinOsc.ar(880,0,0.2) }.play;
z.release;

(
// randomly generated envelope
z = { arg gate=1; 
 var env, n=32;
 env = Env(
  [0]++{1.0.rand.squared}.dup(n-1) ++ [0], 
  {rrand(0.005,0.2)}.dup(n),
  lin, n-8, 8 );
 EnvGen.kr(env, gate, doneAction: 2) * LFTri.ar(220,0,0.4) 
}.scope(1, zoom:4);
)
z.release;

Spectral

FFT, IFFT and the phase vocoder ugens.

FFT calculates the spectrum of a sound, puts it into a buffer, and outputs a trigger each time the
buffer is ready to process. The PV UGens process the spectrum when they receive the trigger.
IFFT converts the spectrum back into sound.


// alloc a buffer for the FFT
b = Buffer.alloc(s,2048,1);
// read a sound
c = Buffer.read(s, “sounds/a11wlk01.wav”);


(
// do nothing
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 0.5 * IFFT(chain);
}.scope(1);
)

(
// pass only magnitudes above a threshold
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 chain = PV_MagAbove(chain, MouseX.kr(0.1,512,1)); 
 0.5 * IFFT(chain);
}.scope(1);
)

(
// pass only magnitudes below a threshold
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 chain = PV_MagBelow(chain, MouseX.kr(0.1,512,1)); 
 0.5 * IFFT(chain);
}.scope(1);
)

(
// brick wall filter.
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 chain = PV_BrickWall(chain, MouseX.kr(-1,1)); 
 0.5 * IFFT(chain);
}.scope(1);
)

(
// pass random frequencies. Mouse controls how many to pass.
// trigger changes the frequencies periodically
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 chain = PV_RandComb(chain, MouseX.kr(0,1), Impulse.kr(0.4));
 0.5 * IFFT(chain);
}.scope(1);
)

(
// rectangular comb filter
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 chain = PV_RectComb(chain, 8, MouseY.kr(0,1), MouseX.kr(0,1));
 0.5 * IFFT(chain);
}.scope(1);
)

(
// freeze magnitudes
{
 var in, chain;
 in = PlayBuf.ar(1,c.bufnum, BufRateScale.kr(c.bufnum), loop:1);
 chain = FFT(b.bufnum, in);
 chain = PV_MagFreeze(chain, LFPulse.kr(1, 0.75));
 0.5 * IFFT(chain);
}.scope(1);
)


2. Techniques

Artificial Space
Building a sense of space into a sound by setting up phase differences between the speakers.


{ var x; x = BrownNoise.ar(0.2); [x,x] }.scope(2); // correlated
{ {BrownNoise.ar(0.2)}.dup }.scope(2); // not correlated

// correlated
{ var x; x = LPF.ar(BrownNoise.ar(0.2), MouseX.kr(100,10000)); [x,x] }.scope(2);
// not correlated
{ LPF.ar({BrownNoise.ar(0.2)}.dup, MouseX.kr(100,10000)) }.scope(2);


// correlated
(
{ var x; 
 x = Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar(7e-3)); 
 [x,x] 
}.scope(2))
// not correlated
{ Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar([7e-3,7e-3])) }.scope(2);

// two waves mixed together coming out both speakers
{ var x; x = Mix.ar(VarSaw.ar([100,101], 0, 0.1, 0.2)); [x,x] }.scope(2);
// two waves coming out each speaker independantly
{ VarSaw.ar([100,101], 0, 0.1, 0.2 * 1.414) }.scope(2); // * 1.414 to compensate for power

// delays as cues to direction
// mono
{ var x; x = LFTri.ar(1000,0,Decay2.ar(Impulse.ar(4,0,0.2),0.004,0.2)); [x,x]}.scope(2);

(
// inter-speaker delays
{ var x; x = LFTri.ar(1000,0,Decay2.ar(Impulse.ar(4,0,0.2),0.004,0.2)); 
 [DelayC.ar(x,0.01,0.01),DelayC.ar(x,0.02,MouseX.kr(0.02, 0))]
}.scope(2);
)

(
// mixing two delays together
// you hear a phasing sound but the sound is still flat.
{ var x; x = BrownNoise.ar(0.2); 
 x = Mix.ar([DelayC.ar(x,0.01,0.01),DelayC.ar(x,0.02,MouseX.kr(0,0.02))]);
 [x,x]
}.scope(2);
)

(
// more spatial sounding. phasing causes you to perceive directionality
{ var x; x = BrownNoise.ar(0.2); 
 [DelayC.ar(x,0.01,0.01),DelayC.ar(x,0.02,MouseX.kr(0.02, 0))]
}.scope(2);
)


Parallel Structures

(
{
 // mixing sine oscillators in parallel
 var n = 16; // number of structures to make
 // mix together parallel structures
 Mix.fill(n,  
  // this function creates an oscillator at a random frequency
  { FSinOsc.ar(200 + 1000.0.rand) }
 ) / (2*n) // scale amplitude
}.scope(1);
)

(
{
 // mixing sine oscillators in parallel
 var n = 16; // number of structures to make
 // mix together parallel structures
 Mix.fill(n,  
  // this function creates an oscillator at a random frequency
  { FSinOsc.ar(200 + 1000.0.rand + [0, 0.5]) }
 ) / (2*n) // scale amplitude
}.scope(2);
)

(
{
 // mixing sine oscillators in parallel
 var n = 16; // number of structures to make
 // mix together parallel structures
 Mix.fill(n,  
  { 
  var amp;
  amp = FSinOsc.kr(exprand(0.1,1),2pi.rand).max(0);
  Pan2.ar(
  FSinOsc.ar(exprand(100,1000.0), 0, amp),
  1.0.rand2)
  }
 ) / (2*n) // scale amplitude
}.scope(2);
)


(
{
 var n;
 n = 8; // number of ‘voices’
 Mix.ar( // mix all stereo pairs down.
  Pan2.ar( // pan the voice to a stereo position
  CombL.ar( // a comb filter used as a string resonator
  Dust.ar( // random impulses as an excitation function
  // an array to cause expansion of Dust to n channels
  // 1 means one impulse per second on average
  1.dup(n), 
  0.3 // amplitude
  ), 
  0.01, // max delay time in seconds
  // array of different random lengths for each ‘string’
  {0.004.rand+0.0003}.dup(n), 
  4 // decay time in seconds
  ),
  {1.0.rand2}.dup(n) // give each voice a different pan position
  )
 )
}.scope(2, zoom:4);
)


20. 5synthdef using filters controlled with Ugens

//5synthdef using filters controlled with Ugens
//1
(
SynthDef(“filt1”,
        {|freq,mul0,mul,out|
        var in1;
        in1 = RHPF.ar(LFNoise2.ar(SinOsc.kr([10,50],0,mul0,(mul0+mul0)),0.5),freq.rand+100,XLine.kr(0.01,2,10,doneAction:2),mul);
        Out.ar(out,Pan2.ar(in1))
        }
        ).send(s)
)
a=Synth(“filt1”,[freq,5000,mul0,300,mul,0.8,out,0])
.a.free

//2
AbstractFunction
(
SynthDef(“filt2”,
        {|mul,out|
                var in1;
                in1 = BRF.ar(WhiteNoise.ar(0.5),LFTri.kr(2,0,1000,2500),LFTri.kr(2,0,0.9,1),mul);
                Out.ar(out,Pan2.ar(in1))
        }
                  ).send(s)
)
a=Synth(“filt2”,[mul,0.9,out,0])
a.free
//3
(
SynthDef(“filt3”,
                {|freq,mul,rq,out |
                var in1;
                in1 = Resonz.ar(Mix.fill(5,
                                                        {Dust.ar(freq+freq.rand,mul)}*1/5),LFTri.kr(1.0.rand,0,300,650),rq,mul);
//*** rrand(0.1,1.0).round(0.01)
                //in2 = Ringz.ar(Impulse.ar(Dust.kr(freq+freq.rand,mul),0,0.5),LFTri.kr(1.0.rand,0,300,650),rq,mul);
                Out.ar(out,Pan2.ar(in1))
                }
                ).send(s)
)

a=Synth(“filt3”,[freq,1000,mul,0.9,rq,2.0.rand,out,0])
a.free

//4
(
SynthDef(“filt4”,
                {|den,freq,mul,add,min,max|
                var in1,in2;
                in1=Mix.fill(8,
                                {RLPF.ar(Saw.ar(200+2000.rand,0.2),XLine.kr(mul,add,8),0.5)}*(0.4)/8);
                in2=Array.fill(8,
                                {Resonz.ar(Dust.ar(500,den),SinOsc.kr(freq.rand,0,mul,add),exprand(min,max),0.5)}*(0.4)/8);
                Out.ar(0,Pan2.ar(in1+in2))
                }
                ).send(s)
)
//****RLPF.ar(Mix)
a=Synth(“filt4”,[den,0.4.rand,freq,exprand(0.1,1.0),mul,1000,add,2500,min,1.0,max,2.0])
a.free

//5
(
SynthDef(“filt5”,
        {|freq,mul,freq2,q|
                var in1, in2;
                in1=Array.fill(8,
                                {RHPF.ar(Crackle.ar(XLine.kr(1,2,5),mul),freq2.rand,q,0.5)}*0.5/8);
                in2=RHPF.ar(Mix.fill(8,{Saw.ar(freq+freq.rand,0.8)}*0.5/8),SinOsc.kr(2.0.rand,0,freq2,((freq2*2)+100)),LFTri.kr(0.1,0,0.3,0.6,1.3),0.9) ;
                Out.ar(0,Pan2.ar(in1,in2))
                }
                ).send(s)
)
a=Synth(“filt5”,[freq, 1500, mul, 1, freq2,exprand(1500,4000),q,exprand(0.1,2.0)])
a.free

//6

(
SynthDef(“filt6”,
        { |freq1,freq2,q,den,start,end,dur |
        var in1, in2;
        in1=Array.fill(10,
                                                {RLPF.ar(Saw.ar(Dust.kr(50,freq1,freq2),0.5),XLine.kr(start,end,dur,doneAction:2),q,0.8)}*0.5/10) ;
        in2=Array.fill(10,
                                                {Resonz.ar(WhiteNoise.ar(den),XLine.kr(start,end,dur,doneAction:2),q,0.9)}*0.8/10) ;
        Out.ar(0,Pan2.ar(in1,in2))
        }
        ).send(s)
)

a=Synth(“filt6”,[freq1,300.rand+100,freq2,500.rand+600,q,exprand(0.01,2),den,exprand(0.1,0.8),start,500,end,1000,dur,5])
a.free

//7

(
SynthDef(“filt7”,
        { |freq1,freq2,q,den,start,end,dur |
        var in1, in2;
        in1=Array.fill(10,
                        {RLPF.ar(Saw.ar(Dust.kr(50,freq1,freq2),0.5),XLine.kr(start,end,dur,doneAction:2),q,0.8)}*0.1/10) ;
        in2=Mix.fill(10,
                        {Resonz.ar(SinOsc.ar(LFNoise0.kr([20,35],400,800),0,0.5),XLine.kr(start,end,dur,doneAction:2),q,0.9)}*0.1/10) ;
        Out.ar(0,Pan2.ar(in1,in2))
        }
                 ).send(s)
)

a=Synth(“filt7”,[freq1,300.rand+100,freq2,500.rand+600,q,exprand(0.01,2),den,exprand(0.1,0.8),start,500,end,1000,dur,8])

//——————————————
http://csound.x-y.net
Ji Youn Kang,
Csound Max Community