MotionTrackOSC

Hiho,

I made another little app in the vein of WiiOSC.
This time for Motion Tracking using video, or rather computer vision.
The program uses the OpenCV libraries, and of course the liblo libraries.
And it is distributed with a SuperCollider class and help file, so you can 
start and use the program from and with that program right away.

For more info, download and a short demo video see my website at:
http://www.nescivi.nl/?p=92


Happy new year!

sincerely,
Marije

26. Patterns

Patterns이란 여러개의 stream들을 하나로 묶어주어 출력하고 콘트롤 하게 해주는 방법이다.
따라서 stream에서 쓰이는 방법들과 많이 일치한다. 

앞에 Stream에서 사용됬던 FuncStream처럼 쓰이는것이 Pfunc으로 거의 같은 역할을 한다. 앞에 FuncStream에서는 stream자체가 정의되고 next라는 메세지를 통해서 값을 출력해주었지만 pattern에서는 Pfunc이 값을 만들고, 그것을 Stream으로 만들어 주는 asStream이라는 메세지가 필요하다. 

(
var a, b;
a = Pfunc.new({ #[1, 2, 3, 4].choose });
b = a.asStream; // make a stream from the pattern
5.do({ b.next.postln; }); // print 5 values from the stream

)


또한 앞에서 Routine이 Stream을 만드는데 쓰였지만, 여기서는 Prout가 사용되어 이것이 Routine 을 보낸다.
(
var a, b, c;
a = Prout.new({ 
  3.do({ arg i; 3.rand.yield; }) 
 });
// make two streams from the pattern
b = a.asStream;
c = a.asStream;
4.do({ b.next.postln; }); // print 4 values from first stream
4.do({ c.next.postln; }); // print 4 values from second stream
)
물론 위의 예제만 보면 더욱 복잡해 보인다. 그러나 일정한 값을 지정해준 후, 그것으로 여러개의 다른 stream을 만들어 낼 수 있다는 점을 상기하면 pattern을 복잡한 data를 생성하고, 여러개의 parameter를 동시에 control할 수 있는 방법 중 하나가 된다.


Math on Patterns
Stream의 경우와 거의 비슷하다. Pattern Object가 Stream(Routine이 했던 일)의 자리를 대신한다는 것만 제외하고..
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
b = a.squared; // pattern b is a square of the pattern a
c = b.asStream;
12.do({ c.next.postln; });
)
//Stream에선 아래와 같았다. 
(
var a, b;
// a is a stream that counts from 0 to 9
a = Routine.new({ 
  10.do({ arg i; i.yield; }) 
 });
b = a.squared; // stream b is a square of the stream a
12.do({ b.next.postln; });
)
비교해보면, variables는 3개가 들어가지만, Pattern의 경우 그 구조가 훨신 간단하다.


Filtering on Patterns
Stream과 같이 .collect, .select, .reject의 메세지를 사용하여 값을 추출해낼 수 있다. 
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
// b is a pattern whose stream adds 100 to even values
b = a.collect({ arg item; if (item.even, { item + 100 },{ item }); });
c = b.asStream;
6.do({ c.next.postln; });
)
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
// b is a pattern whose stream only returns the odd values
b = a.select({ arg item; item.odd; });
c = b.asStream;
6.do({ c.next.postln; });
)
(
var a, b, c;
// a is a pattern whose stream counts from 0 to 9
a = Pseries.new(0,1,10);
// b is a pattern whose stream that only returns the non-odd values
b = a.reject({ arg item; item.odd; });
c = b.asStream;
6.do({ c.next.postln; });
)

Reference : SC3 메뉴얼


24. TaskProxy

TaskProxy event stream reference

superclass: PatternProxy

TaskProxy는 task(time pattern)의 reference를 저장하는 공간이며, play되는 동안 다른 값으로 대체가 가능합니다.
하나의 stream이 끝나고 새로운 schedule의 beat이 변경될때(즉 count의 변화등) 유용하게 사용됩니다.



 *new(source)
  새로운 function을 가진 instance를 만듭니다. 그 소스는 routine function(Tdef참고) 또는 시간값을 가진 pattern이어야 합니다.
 
 
 *default
  아무것도 주어지지 않으면 default는 아무것도 하지않고 0.1의 wait time을 가진 loop입니다.
   
 source_(obj)
  source를 설정합니다. 만약 quantization이 주어지면 이 변화를 다음 beat으로 schedule합니다.
  object 는 routine function으로 안전한 방법으로 계산하는데 그렇기 때문에 만약 proxy가 멈출 경우 그것을 알려줍니다. object 는 time 값을 가진 pattern 이 주어져야 합니다.

 clear source를 nil로 설정.
 
 quant_(beats)
  quantization value로 설정. [quant, offset]의 pair로 설정 가능.
 
 quant
  quantization value를 받음
 
 *defaultQuant_(beats)
  default quantization value는 1.0, [quant, offset]의 pair로 설정 가능.
 
 condition_(func)
  새로운 pattern이 켜지면 새로운 condition을 제공합니다. stream 값과 count 가 그function에 적용됩니다. .
  methods count_(n)은 단순하게 n까지 count하고 그다음 pattern을 켜줍니다.
 
 reset  
  pattern을 reset시켜줍니다.
   
 envir_(event)
  proxy를 위해 default environment 를 제공합니다.
  주어진 다음 routine function을 위한 environment 로 사용됩니다. 
  맨 처음 주어졌을때는 routine pattern이 재 생성 됩니다.
 
 set(key, val, key2, val2, …)
  environment에 arguments를 설정.
  아무값이 주어지지 않으면 이것이 생성되고 routine pattern이 재 생성 됩니다.
 
 endless
  Proutine를 출력하고 그것이 이 proxy를 지속적으로 실행하도록 합니다. 이는 nil을 default(1 s. wait time)로 전환하기 때문입니다. 
  이것은 또한 stream을 만들어 새로운 pattern이 삽입될때까지 기다리도록 해 줍니다.
  

   

a) stream reference로 사용하기 
 
 source_ 
  routine function / pattern을 설정 (내부적으로 *new(key, obj)에 의해 만들어짐)
   
 
 embedInStream(inval)
  어느stream과 마찬가지로 그 자신을 stream상에 놓이도록 합니다. 
 
 
 
b) EventStreamPlayer로 사용하기

 play(clock, protoEvent, quant)
  TaskProxy를 만들어서 player를 생성합니다.
  만약 여러개의 instances를 play하고 싶다면 .playOnce(clock, protoEvent, quant)를 사용합니다.
  quant 는 array로 설정가능합니다.-> [quant, phase]
   
 stop
  stop
 
 player 
  현재 player (만약 TaskProxy가 단순히 다른 stream들에서 사용되면 이 값은 nil)

 pause / resume / reset / mute / unmute
  perform player method 
   
 isPlaying 
  만약 TaskProxy 가 진행되고 있으면 true값을 줍니다. 
  만약 TaskProxy 는 진행되고 그 stream이 끝나면 새로운 stream이 주어졌을때 바로 시작될 수 있도록 stream을 schedule해줍니다.
  
 




a) TaskProxy를 player로 사용하기


// 자. 앞에서 배운 Tdef와 비교하여 보세요.
x = TaskProxy.new;//이것은 없었던것이죠? x 에 새로운 TaskProxy설정해줍니다.
x.play; 


x.source = { loop { “ggggggggggggggggg9999ggg999ggg999gg”.scramble.postln; 0.5.wait; } };


x.source = { loop { “———////———————-“.scramble.postln; 0.25.wait; } };
x.source = { loop { thisThread.seconds.postln; 1.wait; } };
x.source = { loop { thisThread.seconds.postln; 1.01.wait; } };

TempoClock.default.tempo = 2;

x.source = { “the end”.postln };
x.source = { “one more”.postln };
x.source = { loop { “some more”.scramble.postln; 0.25.wait; } };

TempoClock.default.tempo = 1;

x.stop;
x.play;
x.stop;

//Tdef와 별반 다를것이 없죠. Tdef는 사실 이 TaskProxy의 편리한 사용을 위함이기 때문입니다. 


// 소리의 예제

(
// 앞장에서 쓰인 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;
)
x.play;//앞에서 쓰인 x값이 나오죠

(
x.source = { 
 loop {
  s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, rrand(600, 640));
  0.1.wait;
 }
}
)
//자 여기서 x 가 변경되어 쓰입니다. freq가 변하고 있어요.source가 쓰였습니다. 

(
x.source = { 
 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;
 }
}
)
//앞장에서 Tdef(x, — 가 사용되었는데 여기서 다른점은 맨 앞에 x를 TaskProxy로 설정한 이후로 그저 x.source만 사용됩니다. 

(
x.source = { 
 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;
 }
}
)

// metronome
(
y = TaskProxy { 
 loop { s.sendMsg(“/s_new”, “pdef_grainlet”, -1,0,0, freq, 1500); 1.wait; } 
};
y.play;
)

// play ending stream once
(
x.source = { 
 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);
  dt.wait;
 }
}
)

… and so on …

x.stop;
y.stop;
//앞장과 같아요~



b)다른 task나 Routine으로 TaskProxy를 embedding하기 

//이것은 앞에 것을 하나로 묶어준 것입니다.
(
#a, c = { TaskProxy.new } ! 2;//a 와 c 를 TaskProxy로 동시에 넣어줍니다. 그러기 위해 쓰인 #를 보세요. 이것을 지운후 실행해보면 에러가 나옵니다. !2도 잊지말아야겠죠.
a.source = { “one”.postln; 1.wait; “two”.postln };
c.source = { var z; z = Synth(default); 0.5.wait; z.release };
r = Task {
 “counting…”.postln;
 2.wait;
 a.embedInStream;
 1.wait;
 c.embedInStream;
 “done.”.postln;
};
)

r.play; // play 

c.source = { var z; z = Synth(default, [freq, 300]); 1.5.wait; z.release }; // change the def

r.reset;
r.play;

//TaskProxies는 또한 다른 Tdef에서도 사용할수 있습니다. 
(
b = TaskProxy.new;
b.source = {
 “counting…”.postln;
 2.wait;
 a.embedInStream;//다시 a를 부르고
 1.wait;
 c.embedInStream;//c 도 부르고
 “done.”.postln;
};
)
b.playOnce;

// 만약에 stream을 다른 분리된 곳으로 넣고 싶다면 asStream을 사용합니다.
(
Routine {
 c.asStream.play;
 0.1.wait;
 c.asStream.play;
 0.1.wait;
 a.asStream.play;

}.play;
)

Reference : SC3 메뉴얼