13 Synthdefs/Routines

13 Synthdefs Routines

1. Frequency Modulation

envelope 없는 간단한 FM의 예제
(
var carrierFreq = 400, modFreq = 50, deviation = 100;
{        SinOsc.ar(carrierFreq + SinOsc.ar(modFreq, mul: deviation),
                        mul: 0.3);
}.scope
)

같은것을 다음과 같이 간단화 시킬수 있다.
(
var carrierFreq = 400, modFreq = 50, deviation = 100;
{        SinOsc.ar(SinOsc.ar(modFreq, mul:deviation, add: carrierFreq),
                        mul:0.3);
}.scope
)

2. Phase Modulation

PM은 FM과 비슷하지만, frequency 대신 Phase가 modulate된다.

PMOsc가 사용된다;
PMOsc.ar(carfreq, modfreq, index, modphase, mul, add)
        index는 radian에서의  modulation index
        modphase는 radians에서 modulator를 위한 modulation input.

{ PMOsc.ar(Line.kr(600, 900, 5), 600, 3, 0, 0.1)}.play// modulation carfreq
{ PMOsc.ar(300, Line.kr(600, 900, 5),3,0,0.1)}.play// modulate modfreq
{ PMOsc.ar(300, 550, Line.ar(0,20,8), 0, 0.1)}.scope// modulate index

(
var carrierFreq = 400, modFreq = 50, index = 3, decayTime = 5;
{ EnvGen.kr(Env.perc(0.001, decayTime, 0.2), 1, doneAction:2) * PMOsc.ar(carrierFreq, modFreq, index,0);
}.scope
)

calculate modFreq from cmRatio:
(
var carrierFreq = 400, modFreq, cmRatio = 1.5, index = 3, decayTime = 5;
modFreq = (carrierFreq * cmRatio.reciprocal).postln;
{        EnvGen.kr(Env.perc(0.001, decayTime, 0.2), 1, doneAction: 2) *
        PMOsc.ar(carrierFreq, modFreq, index, 0);
}.scope
)

– as SynthDef

SynthDef(name, {function})
load, send, writeDef, play

SynthDef는 반드시 Output bus 에 무엇인가를 보내야 한다;
Out.ar(bus, value)

(
SynthDef(pmgrain, {
        |carrierFreq = 400, cmRatio = 1.5, index = 3, decayTime = 0.01, amp = 1|
        
        var signal, modFreq;
        
        modFreq = (carrierFreq * cmRatio.reciprocal);
        signal =
                EnvGen.kr(Env.perc(0.001, decayTime, 0.2),1,amp, doneAction: 2) *
                PMOsc.ar(carrierFreq, modFreq, index, 0);
        
        Out.ar(0, signal)
}).load(s)
)

//위의 구문을 실행햐여 정의를 내린다.
//아래와 같은 방법으로 불러낸다.
//definition내의 arguments들의 값을 다음과 같이 변경시킬수 있다.

Synth(pmgrain, [decayTime, 5])
Synth(pmgrain, [decayTime, 1, carrierFreq, 200])

-with Routines

Routine({function})
//random carrierFreqs and random offset between events
//loops indefinitely

(
Routine({
        {Synth(pmgrain, [carrierFreq, rrand(1000.0,5100)]);
                rrand(0.001,0.1).wait;
        }.loop
        }).play(SystemClock)
)
        
//with more layers
(
a= {Routine({
        {Synth(pmgrain, [carrierFreq, rrand(1000.0,5100)]);
                rrand(0.5,0.8).wait;
        }.loop
        })
        } ! 10// be careful how many layers are used
)

play the array of routines
a.do({|i| i.play(SystemClock)})
stop the array of routines:
a.do({|i| i.stop})
reset and play the array of routines
   a.do({|i| i.reset.play(SystemClock)})

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

12. Routine/.do

12. Routine

Routine은 function으로 실행을 멈추고 (중간으로 돌아가) 다시 계속할수 있게 해준다.

구문 : (Routine({function})

메세지 yielf, wait이 있는데 초단위의 숫자(SystemClock사용시)나 비트단위(TempoClock사용시)의 숫자를 요구한다.
//——————————————
//ex1)
(
        r = Routine({
                        var counter = 0;
                        { counter = counter + 1;
                          counter.postln;
                          1.yield;//1.wait
                          }.loop;//looo의 사용은 loop가 계속적으로 지속되도록 하기 위함
                          })
)//이렇게 루틴을 만든후 아래와 같이 실행

r.play(SystemClock)
r.stop
r.reset.play(SystemClock)

//ex2)Karplus routine(11장에서 사용한 Karplus사용)
(
SynthDef(“Karplus”,
{
        arg midiPitch = 69, decayTime = 2.0;
        var burstEnv, att = 0, dec = 0.001, signalOut, delayTime;
        delayTime = midiPitch.midicps.reciprocal;
        burstEnv = EnvGen.kr(Env.perc(att, dec));
        signalOut = CombL.ar(WhiteNoise.ar(burstEnv), delayTime, delayTime, decayTime);
        DetectSilence.ar(signalOut, doneAction: 2);
        Out.ar(0,signalOut);
}).load(s)
)

(
r = Routine({
        {        Synth(“Karplus”,[midiPitch, rrand(50,90), delayTime,rrand(2.0,3)]);
        [0.5,0.75,1].choose.wait;
        }.loop;
}).play(SysyemClock)
)

//ex3) Sine Grain
(
SynthDef(“SineGrain”, {
                |out = 0, freq, amp = 1, decay = 0.01|
                var signal;
        
                signal = SinOsc.ar(freq, mul:amp) *
                                EnvGen.kr(Env.perc(0.001,decay,0.2),1,doneAction:2);
                signal = Pan2.ar(signal, Rand(-1.0,1.0));//Rand geberates 1 randon value when SunthDef starts playing
                Out.ar(out,signal)
                }).send(s)
)        
//2가지 방법으로 SineGrain에 메세지를 보내보자.
//1.s_new, synthname, ID, add Action(0 is add to head). Target ( Group)ID
//if ID in s_new message is -1, the server generates an ID and you cannot access it by number
//This is convenient if SynthDef turns off and deallocates the synth.

(
r = Routine({
        { s.sendMsg(s_new, SineGrain, -1,0,0,freq,rrand(5000.0,5100));
                rrand(0.001,0.1).wait;
        }.loop
        }).play(SystemClock)
)
//using Synth
(
r = Routine({
                {Synth(SineGrain,[freq,rrand(1000.0,5100),decay,rrand(0.1,1),amp,rrand(0.05,0.1)]);
                rrand(0.001,0.1).wait;
                }.loop
        }).play(SystemClock)
)

//——————————————
number.do({function});
10.do({|i = 0| i.postln;})

위 구문은 0~10까지를 프린트.
do는 루틴을 여러개 만들때 유용하게 사용된다. 아래는 SineGrain의 레이어를 여러개 만든다.

(
20.do({Routine({
        { Synth(SineGrain,[freq,rrand(1000.0,5100),decay,rrand(0.1,1),amp,rrand(0.05,0.1)]);
                rrand(0.001,0.1).wait;
        }.loop
        }).play(SystemClock)
        })
)

array.do({function});
array의 값은 argument에 할당된다.
[1,3,5].do ({|i| i.postln})
//다음은 루틴의 array를 만든다.
(
a = { Routine({
        { Synth(SineGrain,[freq, rrand(1000.0,5100), decay, rrand(0.1,1), amp, rrand(0.05,0.1)]);
        rrand(0.001,0.1).wait}.loop
        })
        } ! 5;
)
do를 사용하여 play and stop
a.do({|i| i.play(SystemClock)})
a.do({|i| i.stop})
a.do({|i| i.reset.play(SystemClock)})
//——————————————
http://csound.x-y.net
Ji Youn Kang,
Csound Max Community

11. SynthDef

11. Synth Def

SynthDef는 patch에 이름을 만들어 다른곳에서 불릴수 있도록 한다. 서버로 불려지면 SynthDef 는 메세지를 받아 값을 변경시킬수 있다.

-Basic Format:
SynthDef(“name”, {Out.ar(busNumber,Ugen});

“name”은 /name이렇게 쓰여질수도 있다.

(
SynthDef(“onesine”,{|freq = 440, bus = 0|
                Out.ar(bus, SinOsc.ar(freq,0,0.1));
                }).load(s);//file을 저장하고 서버로 보낸다.
)

-SynthDef은 또한 파일로 저장되어 다음에 다시 사용될 수 있다.
Default directory는 synthdefs/이다.

다음은 명령메세지들이다.

writeDefFile (dir) :  file로 쓰기
load(server) : defFile을 쓰고 서버로 보내기 위한 메세지를 보낸다.
send(server) : def를 compile 하고 파일로 쓰지않고 서버로 보낸다.
play(server) : def를 compile 하고 서버로 보내고 하나의 synth를 만든다.

Raw messages는 SynthDef의 새로운 instance를 만들거나 이미 존재하는것의argment값을 바꾸기 위해서 서버로 보내질수 있다.

메세지 정의는 다름을 참고:
[Server-Command-Reference]        

// To create a new instance of a synth
s.sendMsg(“/s_new”, “onesine”, 1000,1,0);

//1000이 ID
//1은 action (0: head로 더해지고 1은 꼬리에 더해지고)
//0은 target  ID (group)

To free node 1000:
s.sendMsg(“/n_free”, 1000);

To change the frequency in node 1000 (which must be active):
s.sendMsg(“/n_set”, 1000,freq,200);
s.sendMsg(“/n_set”, 1000,”freq”,500);

//*Note : freq와 “freq” 둘다 위 메세지에 사용되었다.

여러개의 nodes만들기
        s.sendMsg(“/s_new”, “onesine”, 1000,1,0,freq,100);
        s.sendMsg(“/s_new”, “onesine”, 1001,1,0,freq,230);
        s.sendMsg(“/s_new”, “onesine”, 1002,1,0,freq,470);
        s.sendMsg(“/s_new”, “onesine”, 1003,1,0,freq,1000);

To free these nodes:

s.sendMsg(“/n_free”, 1000);
s.sendMsg(“/n_free”, 1001);
s.sendMsg(“/n_free”, 1002);
s.sendMsg(“/n_free”, 1003);

-또다른 SynthDef:

(
SynthDef(“filteredNoise”, {|center = 2000|
        Out.ar(0,Resonz.ar(WhiteNoise.ar(0.5), center, 0.1));
        }).load(s);
)

a = Synth(“filteredNoise”,[center,500]);
b = Synth(“filteredNoise”,[center,1000]);
a.free;
b.free;

To browse available SynthDefs:
(
SynthDescLib.global.read;
SynthDescLib.global.browse;
)

-Karplus-Strong as SynthDef

(
SynthDef(“Karplus”,
{
        arg midiPitch = 69, decayTime = 2.0;
        var burstEnv, att = 0, dec = 0.001, signalOut, delayTime;
        delayTime = midiPitch.midicps.reciprocal;
        burstEnv = EnvGen.kr(Env.perc(att, dec));
        signalOut = CombL.ar(WhiteNoise.ar(burstEnv), delayTime, delayTime, decayTime);
        DetectSilence.ar(signalOut, doneAction: 2);
        Out.ar(0,signalOut);
}).load(s)
)

// note :arg syntax (arg ..  ;   instead of |arg, arg|
// note :the way that Out is used
// DetectSilence – evaluates doneAction when input falls below a certain threshold

Synth(“Karplus”)
Synth(“Karplus”, [midiPitch, 60])   // uses a new node each time

a = Synth(“Karplus”);
a.set(midiPitch, 60);   // synth is turned off before this happens

Synth(“Karplus”, [midiPitch, rrand(50,80), decayTime, 3.0]);
//——————————————
http://csound.x-y.net
Ji Youn Kang,
Csound Max Community