백년만의 글쓰기

이병무 선생님 특강때의 두서없는 필기를 공유합니다.

제대로 알고있지 못했던 것 등, 개인적으로 필요했던 부분만 적어두었습니다.

특강은 개인적으로 너무 좋았구요.

그러나, 전혀 정리되어 있지 않으니 섣불리 스크롤하지 마세요!

 

================================================

20120421

<이병무 선생님 특강>

 

<array와 list의 차이> : 둘 모두 순서가 중요한 collection

~ar = Array.new(3);

~ar.add(1); //넣을 수 있는 요소의 수에 제한이 있다

 

~ls = List.new;

~ls.add(1); //List는 원래 요소의 수에 제한이 없다.

 

*array를 list처럼 쓰는 방법

~ar = ~ar.add(1);

 

처음부터 갯수를 정해놓을 때에는 .newClear; 를 쓰는 것이 좋다.

 

 

<반복과 관련된 메소드>

그 중에 .do

3.do({“hi”.postln}); //postln은 postln의 ‘receiver를 post 창에 줄바꿔 찍어라’는 명령

3.do{| idx | idx.postln;}; //0, 1, 2까지 찍어주고, 마지막으로 receiver인 3을 찍는다.

 

 

<반복을 이용한 소리만들기>

Server.local.boot;

 

{SinOsc.ar(440, mul: 0.3)}.play(s);

{SinOsc.ar(440, mul: 0.3)}.play(Server.local);

10.do{| idx | {SinOsc.ar(400*(idx+1), mul: 0.03)}.play;};

[0, 1, 4, 7].do{| i, j | i.postln; j.postln;}; // i는 0, 1, 4, 7. j는 0, 1, 2, 3

 

FreqScope.new(400, 300);

s.scope;

 

<Dictionary>: 순서가 없는 collection

 

d = {“hi dic”.postln}

a = Dictionary[\a -> d, \b -> 20];

a.at(\a).value;

\a가 숫자일 수도 있지만 거대한 펑션일 수도 있다.

 

 

IdentityDictionary

: Environment는 IdentityDictionary의 subclass다.

 

Event

: Environment의 subclass다. 소리를 내기 위한 속성들을 지니고 있는 일종의 IdentityDictionary.

(freq: 1000, amp: 0.5).play; //고로 이것도 dictionary의 속성을 물려받았다.

 

 

<Server 만들기>

 

a = Server.new(“jongro”, NetAddr(“127.0.0.1”, 10000)) //port number는 아무거나 써도 좋지만 두 가지는 예약되어 있다.

server port : 57110

Server.internal.addr.port; //0

Server.local.addr.port; //local host 는 주소가 있으나, internal 은 주소가 없다. 외부에서 명령을 주어 소리를 만드는 등의 일은 모두 localhost 서버에서 이루어 져야 한다.

lang port : 57120

NetAddr.langPort; //57120. 이것은 재부팅시마다 달라질 수 있다.

 

Other applications sending messages to SuperCollider should distinguish between sending messages to the server or the language. Server messages are documented in the Server Command Reference and should be sent to the server’s port – s.addr.port – which is 57110 by default. Messages sent to the server will not be processed by any OSCresponder in the language.

Messages from external clients that should be processed by OSCresponders must be sent to the language port, 57120 by default. Use NetAddr.langPort to confirm which port the SuperCollider language is listening on.

 

외부에서 sc로 오는 메시지는 그것이 server(scsynth)로 가는 것인지, client(sclang)로 가는 것인지 구분되어야 한다. server로 직접 보내지는 메시지는 57110포트를 통해서, internal 이 아닌 localhost 서버로 보내지며, 이는 Server command 형태가 되어야 한다. 반면 client(sclang)으로 보내지는 메시지는 57120포트를 통해서 보내지며 이 둘(scsynth와 sclang)은 메시지를 주고받는 객체로서는 서로 영향받지 않는다.

 

OSCresponder

a.makeWindow; //서버 창을 만든다.

 

 

*internal 서버에서 p를 누르면 노드의 상태를 보여주는 창이 뜬다.(3.5버전에서 추가된 훌륭한 기능)

s.queryAllNodes; //같은 역할

 

<Node>

g = Group(s); //group 만들기

r = Group(g); //group 안에 group 만들기

{SinOsc.ar(mul: 0.5)}.play(target: g); //group g에 synth만들기

{SinOsc.ar(mul: 0.5)}.play(target: r); //group r에 synth만들기

nodeId로 synth를 제거하려면, s.sendMsg(\n_free, nodeId);

 

<Bus>

{In.ar(8, 1)}.play; // feedback!!!

하드웨어에 연결된 버스(8 + 8) 이후 번호는 private bus라고 한다.

 

{SinOsc.ar(mul: 0.5)}.play(s, 100);

s.scope(2, 100); //number of channes, index

{In.ar(100, 1) * SinOsc.ar(440, mul: 0.5)}.play(addAction: \addToTail);

시그널은 head 에서 tail로 흐른다. 따라서 소스가 되는것이 위에, 그것을 받는것이 아래에 깔려야 한다.

 

이 순서를 맞추기 위해서는,

1) 실행 순서를 조절하거나,

2) addAction의 속성을 주거나,

3) head쪽, tail 쪽 그룹을 만들어 두고 소스는 head쪽 그룹에, 받는 쪽은 tail쪽 그룹에 넣어 생성하는 방법

등이 있다.

 

 

(크게보아서)<소리를 내는 두 가지 방법>

1) 오실레이터 이용

2) 버퍼에 녹음된 소리를 이용

*오실레이터 역시 버퍼안에 특정 시그널 주기를 넣어두고 재생하는 것

 

Buffer.freeAll; //존재하는 모든 버퍼를 free시킨다.

b = Buffer.alloc(s, s.sampleRate * 4, 1);

b.read(Platform.resourceDir +/+ “sounds/a11wlk01-44_1.aiff”, action:{|buf| {buf.plot}.defer; buf.play});

b.plot;

 

BufRateScale – samplerate converting의 역할

 

<멀티 채널 셋팅>

{[SinOsc.ar(300, mul: 0.4), SinOsc.ar(1000, mul: 0.2)]}.play;

{SinOsc.ar([300, 1000], mul: 0.4)}.play;

배열의 형태로 간단히 멀티 채널의 셋팅을 달리 할 수 있다.

({

var sig;

sig = PlayBuf.ar(1, b, BufRateScale.kr(b)*[0.5, -1], loop:1);

LPF.ar(sig, 500);

}.play;)

 

<action, completionMsg>

action은 function형식으로 써도 되지만, completionMsg는 Msg 형태로 주어야 한다.

*function형태로 적되, .read 를 .readMsg 로 쓰면, function을 msg 타입으로 알아서 바꾸어 적용해 준다.

 

a = Buffer.alloc(s, s.sampleRate * 2.0, 1, {| buf | buf.read(Platform.resourceDir +/+ “sounds/a11wlk01-44_1.aiff”)}); //안된다. function

a = Buffer.alloc(s, s.sampleRate * 2.0, 1, {| buf | buf.readMsg(Platform.resourceDir +/+ “sounds/a11wlk01-44_1.aiff”)}); //된다. msg

a = Buffer.alloc(s, s.sampleRate * 2.0, 1, [\b_read, a.bufnum, Platform.resourceDir +/+ “sounds/a11wlk01-44_1.aiff”]); //된다. msg

a.free;

a.plot;

Buffer.freeAll

 

 

<루틴>

기본적으로 stream을 만들어 준다.

(

r = Routine{

 

“first”.postln;

1.yield;

 

“second”.postln;

2.yield;

 

“third”.postln;

3.yield;

 

}

)

 

(

q = Routine{

 

“1st”.postln;

1.yield;

 

“2nd”.postln;

2.yield;

 

“3rd”.postln;

3.yield;

 

}

)

 

 

r.reset;

r.next;  //Routine은, .next를 받으면 처음 .yield까지만, 다음 .next를 받으면 다음 yield까지만 일하는 스트림.

r.play; //.play를 받으면 자동으로 처음부터 끝까지 진행한다. 그러나 .yield, .wait 의 receiver 만큼의 시간동안 중간에서 기다린다.

*스트림(Stream) : .next를 받았을 때 값을 내보내는 연속적인 오브젝트. 아주 특별한 형태의 배열

 

r.postln;

r.asArray.at(1);

 

 

<클럭(Clock)>

sc에는 세 가지의 시계가 있다.

SystemClock, AppClock, TempoClock

 

SystemClock가 가장 정확하다.

그러나 GUI에서는 AppClock이 시계로 쓰여야만 한다.

 

*SystemClock, AppClock은 인스턴스를 만들 수 없다. 따라서 클래스 메소드를 이용해 사용한다.

 

SystemClock.sched(0.0, {“hi”.postln}); //바로

SystemClock.sched(2.0, {“hi”.postln}); //2초 후에

 

(

SystemClock.sched(0.0, {

r.play;

“first routine start”.postln;

});

 

SystemClock.sched(2.0, {

q.play;

“second routine start”.postln;

});

)

 

r.reset; q.reset; //루틴 reset

 

TempoClock은 인스턴스를 만들 수 있다.

->인스턴스를 만들어야 한다.

t = TempoClock(2); //2는 1의 두 배 속도

 

(

t.sched(0.0, {

r.play;

“first routine start”.postln;

});

 

t.sched(5.0, {

q.play;

“second routine start”.postln;

});

)

r.reset; q.reset;

*GUI interface는 PD에서, 소리합성은 SC에서 하는 것을 연습해보자.

Advertisements