23. Tdef

Tdef task reference definition

superclass: TaskProxy


Tdef는 reference를 task(time pattern)으로 유지시켜서 play되는 동안에 값이 전환될 수 있도록 해줍니다.
이는 old stream이 끝났을때 플래이 되고, 새로운 stream이 결정되고 beat의 단위로 schedule을 주게 됩니다.

Tdef(key)는 instance를 보내며, Tdef(key,pat)은 pattern을 결정하여 instance를 보냅니다. 이는 Pdef와 Ndef와 유사하며 TaskProxy와 비슷합니다. 

-instance message 
 *new(key, obj)
  task 를 key에 따라 global dictionary 에 저장합니다. 
  만약 이미 다른 Tdef가 있다면 이것은 새로운것으로 대체가 됩니다.
  obj 는 function 또는 시간값을 가진 pattern 입니다.
   
 *new(key)
  key에 있는 task로 접근합니다. (만약 아무것도 없으면 default task 가 생성됩니다.)
   
 *default
  a default source, 만약 아무것도 주어지지 았으면 default는 loop 으로 1.0 beat wait time을 무시합니다.
  
 *removeAll 모든 proxies를 제거
 *clear 모든 proxies 를 clear
 
 *all
  모든 저장된 Tdef들을 불러냅니다.
 
 *all_(envir)
  global environment를 set합니다. 
   
 quant_(beats)
  quantisation time 을 beat 의 단위를 가진 정확한 scheduling을 위해 쓰게 해줍니다. 
  [timingOffset, quant] 와 같이 pair로 사용가능합니다.
   
 clear 그 source 를 nil로 set
 
 *defaultQuant_(beats)
  default quantisation 을 new instances (default: 1.0)로 set
  [timingOffset, quant] 와 같이 pair로 사용가능합니다.

 condition_(func)
  새로운것이 삽입되었을때에 pattern이 적용되는곳에 어떤 condition 을 제공 합니다.
  stream value 와 count 가 그 function으로 적용됩니다.
  methods count_(n) 은 count를 n 까지 사용하게 해주며 그때 pattern을 켜줍니다.
 
 reset  
  pattern을 곧바로 켜줍니다. (stuck conditions 이 이로 인해 파괴될 수 있습니다.)


 envir_(event)
  default environment 가 proxy를 위해 제공됩니다. 
  주어진 후에 이것은 routine function의 environment 로 적용됩니다. 
  이것이 처음으로 주어졌을때는 routine pattern 이 재생성됩니다.
 
 set(key, val, key2, val2, …)
  arguments 를 environment에 set해줍니다.
  environment에 아무것도 없으면 주어진 값이 생성되고 routine pattern은 재생성 됩니다.

 endless
  a proxy를 지속적으로 play해주는 Proutine을 보냅니다. 
  이는 nil값을 default값으로 전환시켜 줍니다.(1 s. wait time)
  이는streams을 만들어 새로운 pattern이 삽입될때 까지 기다립니다.


a) stream reference로 사용할 때.
 
 
 embed 는 embedInStream의 축소형
 
 embedInStream(inval)
  stream처럼 stream위에 놓게 합니다.
 
 

 
b) Task로 사용될 때

 play(clock, doReset, quant)
  Pdef를 시작하여 player를 만듭니다.
  여러개의 instances를 재생하기 원하면 .playOnce(clock, doReset, quant)를 사용합니다. 여기서 quant는 [quant, phase]로 pair로 사용가능합니다.
   
 stop
  task를 멈춥니다.
 
 player 
  현재의 task (만약 Tdef이 단순히 다른 stream에서 사용되면 이것은 nil)

 pause / resume / reset / mute / unmute
  등이 적용될 수 있습니다. 
   
 isPlaying 
  Tdef가 현재 사용되고 있으면 true를 보냅니다.
  Tdef 가 play되고 있으면 그것의 stream 을 끝내고, 새로운 function이 적용될 때에 바로 task가 play될 수 있도록 schedule 해줍니다.




a) task player로의 사용.


Tdef(x).play; // 빈 Tdef를 만들고 play합니다. (즉 환경을 먼저 만듭니다.)

Tdef(x, { loop({ “ggggggggggggggggg9999ggg999ggg999gg”.scramble.postln; 0.5.wait; }) });// loop가 0.5초마다 적용되거 ” ” 내에 있는것을 scramble 시켜서 보내는 새로운 instance가 생성되었습니다.


Tdef(x, { loop({ “———////———————-“.scramble.postln; 0.25.wait; }) });//이제 새로운것으로 대체 되었습니다. 
Tdef(x, { loop({ thisThread.seconds.postln; 1.wait; }) });//이제 Thread가 초단위로 나가게 됩니다.
Tdef(x, { loop({ thisThread.seconds.postln; 1.01.wait; }) });//schedule시간을 변경해줍니다.

TempoClock.default.tempo = 2;//비트단위로 변경

Tdef(x, { “the end”.postln });//시간값이 없으니 instance만 보내고 멉춥니다.
Tdef(x, { “one more”.postln });//하나 더 보내봅니다.
Tdef(x, { loop({ “some more”.scramble.postln; 0.25.wait; }) });//다시 시간값을 주니 변합니다. 

TempoClock.default.tempo = 1;//시간단위 변경

Tdef(x).stop; //멈춥니다.
Tdef(x).play;//다시 실행

Tdef(x).clear;//instance를 지워줍니다.




// 소리의 예제

(
//간단한 synthdef를 하나 만들어봅니다.
s.boot;
SynthDef(“pdef_grainlet”, 
 { arg out=0, freq=440, sustain=0.05;
  var env;
  env = EnvGen.kr(Env.perc(0.01, sustain, 0.3), doneAction:2);
  Out.ar(out, SinOsc.ar(freq, 0, env))
 }).store;
)
Tdef(x).play;//Tdef를 x라는 이름으로 했음을 살펴보아주세요~
Server
(
Tdef(x, { 
 loop({
  s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, rrand(600, 640));
  0.1.wait;
 })
})
)//이제 x에 instance를 만들어 줍니다. 서버에 메세지를 보내야겠지요. Synthdef는 늘 서버에 저장되니까요. 그다음 새로운 instance를 만들어 주고(“/s_new”), synth이름을 불러주고 (“pdef_grainlet”), nextNodeID는 nil이니 -1, group 0(RootNode), targetID 0, 그다음 argument값을 random값으로 바꾸어 주었습니다. 

(
Tdef(x, { 
 var x;
 x = Pseries(300, 20, 100).loop.asStream;
 loop({
  s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, x.next);
  0.05.wait;
 })
})
)
//위에는 새로운 패턴을 적용시킨 예제입니다. Pseries로만든 stream을 freq에 적용

(
Tdef(x, { 
 var x;
 x = Plazy({ Pseries(300 + 300.rand, 10 + 30.rand, 10 + 30.rand) }).loop.asStream;
 loop({
  s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, x.next);
  0.05.wait;
 })
})
)
//다음은 Plazy를 사용하여 stream들을 만들어 주었습니다. 
// metronome
Tdef(y, { loop({ s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, 1500); 1.wait; }) }).play;
//여기에 새로운 y란 이름으로 메트로놈을 만들어 주었어요.

// play ending stream once
(
Tdef(x, { 
 var x, dt;
 dt = [0.1, 0.125, 0.05].choose;
 x = Plazy({ Pseries(1300 + 300.rand, 110 + 130.rand, 16) }).asStream;
 x.do({ arg item;
  s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, item.postln);
  dt.wait;
 })
})
)

//다시 x 를 바꾸어 줍니다. dt값은 schedule을 컨트롤 하는데 쓰입니다. 자 여기서 이전의 Plazy는 freq를 컨트롤 하는데 사용되었는데, 여기서는 instance를 여러개 만들어 주기 위해서 사용되었습니다. loop가 없어서 한번의 stream이 사용되고 마쳐집니다. 여기서 item은 Plazy로 생성된 item을 받는것이죠. 값을 확인하고 싶다면 freq, item.postln해보세요.


Tdef(x).stop;
Tdef.removeAll;



b) embed 와 fork: 다른 Tasks / Routines내에 쓰이는 Tdef


(
Tdef(a, { “one”.postln; 1.wait; “two”.postln });
Tdef(c, { var z; z = Synth(default); 0.5.wait; z.release });
r = Task({
 “counting…”.postln;
 2.wait;
 Tdef(a).embed;
 1.wait;
 Tdef(c).embed;
 “done.”.postln;
});
)
//Tdef a는 one출력후 1초 기다리고, 다시 two를 출력하라이고
//Tdef c는 z란 default synth를 만든다음에, 0.5초 기다리고 출력하라고 되어있습니다.
//r은 task를 만들어서 위의 값에 stream을 주었는데요, counting한다음, 2초 기다리고, a를 보내고, 1초 기다리고, c를 보낸다음 done을 보냅니다.
//여기서 중요한 점은 Task안에 Tdef를 불러낼때에 play가 아닌 embed를 사용한다는 것.
r.play; // r 을 출력합니다.

Tdef(c, { var z; z = Synth(default, [freq, 300]); 1.5.wait; z.release }); // change the def
//c를 변경했네요.
r.reset;//reset하고
r.play;//다시 play

// 물론 Tdefs은 다른 Tdef들과도 사용가능합니다.
(
Tdef(b, {
 “counting…”.postln;
 2.wait;
 Tdef(a).embed;
 1.wait;
 Tdef(c).embed;
 “done.”.postln;
});
)
Tdef(b).fork;//fork를 사용한 출력입니다. 

// 만약에 stream하나를 분리해서 thread에 넣고 싶다면 asStream을 사용하면 됩니다.
// .playOnce 도 사용가능합니다. 
(
Routine({
 Tdef(c).fork;
 0.1.wait;
 Tdef(c).fork;
 0.1.wait;
 Tdef(a).fork;

}).play;
)

//Routine과 사용될때 fork가 사용됬다는 접을 기억하세요. 




Tdef as a time pattern

Pdefn을 time값으로 사용하지 않고 Tdef를 사용하는것도 유용합니다.
source를 변경할때에 stream의 값들을 clock으로 synchronized 되도록 유지시켜 줍니다.


(
// synthdef정의해줍니다. 
s.boot;
SynthDef(“pdef_grainlet”, 
 { arg out=0, freq=440, sustain=0.05;
  var env;
  env = EnvGen.kr(Env.perc(0.01, sustain, 0.3), doneAction:2);
  Out.ar(out, SinOsc.ar(freq, 0, env))
 }).store;//저장하고
)




Tdef(z, Pseq([1, 1, 1, 0.5, 0.5], inf));
하나의 Tdef를 먼저 정의해줍니다. 

(
 Pset(instrument, pdef_grainlet, //instrument로 위에 주어진 synthdef를 사용하고
  Ppar([
  Pbind(
  dur, Tdef(z),//duration값을 Tdef에서 불러줍니다.
  note, Pseq([1, 3, 2, 1, 0], inf),//note값을 Pseq으로 새롭게 정의
  x, Pfunc { TempoClock.default.elapsedBeats.postln } // onset times 을 출력해줍니다. 
  ),
  Pbind(
  dur, 4, //이것은 reference beat으로 사용될 값입니다.
  sustain, 0.1,
  note, 8
  )
  ])
 ).play(quant:1);
)


Tdef(z, Prand([1, 1, 0.23, 0.5, 0.5], inf)); //time pattern을 변경하기가 이리 쉽습니다.
Tdef(z, Pseq([1, 1, 1, 1], inf)); // pattern을 synch하도록
Tdef(z, Pseq([1, 1, 1, 0.5, 0.5], inf)); // 다른 순서로 정렬될 가능성이 있습니다. (

  // 이를 피하기 위해서 quant의 값을 설정해 주면 됩니다.

reference : SC3 메뉴얼





24. Polymorphism

Polymorphism

Polymorphism은 여러가지 다른 방법으로 하나의 메세지에 응답하는 다른 클라스들의 능력을 이야기한다. 어떤 메세지는 일반적으로 그 내면의 의미를 담고있고, 그것이 각각 클래스의 책임으로서 그 의미에 적절한 방법으로 대응하기 위한것이다.

예를들어 value라는 메세지는 “이 오브젝트의 적절한 값을 주세요’라는 의미를 가진다.

그 value의 방법은 다음의 클라스에 정해져 있다.
Function : this.value(args)
Object : this.value()
Ref : this.value

그렇다면 클래스가 정의된 방법을 보자.
 여기 클라스 Object에 있는 value방법이 있다.
value { ^this }
위는 단순히 그것을 return 하라는 명령이다. 모든 클래스들은 클라스 Object에 의해 전해져 내려오므로, 이 뜻을 클라스가 value를 무시하지 않는 한 그 오브젝트는 그 자신을 return시킴으로서 value 에 응답한다. 

5.postln; // posts itself
5.value.postln; // value returns itself
‘a symbol’.postln;
‘a symbol’.value.postln;
[1,2,3].value.postln;
//etc..

클라스 Function에서 value방법은 기본으로 들어간다.
 value { arg … args; 
  _FunctionValue 
  // evaluate a function with args
  ^this.primitiveFailed 
 }

_FunctionValue 는 C code기본으로 이것이 무엇을 하는지는 이것만 보아서는 알수 없다. 그러나 그것이 하는일은 그 function을 처리하고 그 결과를 보내는 일이다.
{ 5.squared }.postln; // posts Instance of Function
{ 5.squared }.value.postln; // posts 25

Ref 클라스는 오브젝트의 간접적인 reference을 만드는 방법을 제공한다. 이는 reference 에 의해 value 를 통과하도록 쓰일 수 있다. Ref Obkect들은 하나의 instance variable ‘value’를 갖는다. 그 ‘value’방법은 그 instance variable의 ‘value’의 값을 보낸다. 다음 예제를 보자.
Ref : AbstractFunction 
{
 var <>value;
 *new { arg thing; ^super.new.value_(thing) }
 set { arg thing; value = thing }
 get { ^value }
 dereference { ^value }
 asRef { ^this }

 //behave like a stream
 next { ^value }
 embedInStream { arg inval;
  ^this.value.embedInStream(inval)
 }

 printOn { arg stream;
  stream << “`(” << value << “)”;
 }
 storeOn { arg stream;
  stream << “`(” <<< value << “)”;
 }
}
****^의 의미는 return. class에서 ^가 없으면 instance를 return한다. 
****this의 의미는 instance(서두에 instance method가 있는 경우)또는 class (서두에 classMethod가 있는 경우)
Ref.new(123).postln;//ref를 내보낸다.
Ref.new(123).value.postln;//ref의 값을 내보낸다.

Ref는 또한 dereference라는 메세지를 만든다. dereference는 value method가 하는 일과 다르지 않은 instance variable로 value를 보낸다. 그럼 이것은 왜 필요할까? 그것은 어떻게 다른 class들이 dereference에 응답하는가에 의해 설명된다. dereference메세지는 “당신을 포함하고 있는 어떤 Ref든 없애라” 라는 메세지를 의미한다. class Object에서 dereference는 그 object자체를 보낸다. 이는 value 메세지와 같은 양상이다. 차이점은 다른 class들이 이 방법을 취하하지 않는다는 것이다. 따라서 어떤 Function의 dereference는 여전히 Function이다.

Object : this.dereference()
Ref : this.dereference()

5.value.postln;  
{ 5.squared }.value.postln;  
Ref.new(123).value.postln;

5.dereference.postln;  
{ 5.squared }.dereference.postln;//여기를 주목. 위에서는 25를 출력했다.  
Ref.new(123).dereference.postln;//dereference의 값을 내보낸다. ref를 보내는것이 아니다.


또 다른 예제로는 play가 있다. 
{ PinkNoise.ar(0.1) }.play; // Function

( // AppClock
var w, r;
w = GUI.window.new(“trem”, Rect(512, 256, 360, 130));
w.front;
r = Routine({ arg appClockTime;
  [“AppClock has been playing for secs:”,appClockTime].postln;
  60.do({ arg i;
  0.05.yield;
  w.bounds = w.bounds.moveBy(10.rand2, 10.rand2);
  w.alpha = cos(i*0.1pi)*0.5+0.5;
  });
  1.yield;
  w.close;
});
AppClock.play(r);
)

( // SynthDef
x = SynthDef(“Help-SynthDef”, 
 { arg out=0;
  Out.ar(out, PinkNoise.ar(0.1))
 }).play;
)

Pbind(degree, Pseq([0, 1, 2, 3],inf)).play; // Pattern

reference: SC3메뉴얼



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.