//Some effects examples


//use the internal server with the scope

(

Server.default= s=Server.internal; 

s.boot;

)



//make some source sound recipe


(

SynthDef(\impulse, {

Out.ar(0,Pan2.ar(Saw.ar(440,Decay2.ar(Impulse.ar(1),0.001,0.1,0.5)),0.0));

}).add;  


SynthDef(\continuous, {

Out.ar(0,Pan2.ar(WhiteNoise.ar(0.1),0.0));

}).add;  

)



//we'll need to be careful with execution order here, since the effects unit SynthDefs will be separate to the sound sources. See the previous Nodes file. 


a = Group.basicNew(s,1); //get Group 1


x = Synth.head(a, \impulse);


s.scope











//Delay


(

SynthDef(\fxexampledelay, {arg delaytime=0.1;

var input, effect; 


input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0


effect= DelayN.ar(input, 1,delaytime); //max delay of one second


Out.ar(0,effect); //adds to bus 0 

}).add;  

)



x.free;

x = Synth.head(a, \impulse);

y= Synth.tail(a, \fxexampledelay);


y.free;


y= Synth.tail(a, \fxexampledelay, [\delaytime, 0.4]);


y.free;








//other UGens to explore:

DelayN, DelayL, DelayC, Delay1, Tap, MultiTap








//vibrato

(


{

var source; 

var fx; 



source= Saw.ar(440,0.1);


fx= DelayC.ar(source, 0.01, SinOsc.ar(Rand(5,10),0,0.0025,0.0075));


fx

}.play


)





//chorusing

(


{

var source; 

var fx; 

var n=10;


source= EnvGen.ar(Env([0,1,0],[0.1,0.5]),Impulse.kr(2))*Saw.ar(440,0.5);


fx= Mix.fill(n, {

var maxdelaytime= rrand(0.01,0.03);

var half= maxdelaytime*0.5;

var quarter= maxdelaytime*0.25; 


//%half+(quarter*LPF.ar(WhiteNoise.ar,rrand(1.0,10)))

DelayC.ar(source, maxdelaytime, LFNoise1.kr(Rand(5,10),0.01,0.02) )


});


fx

}.play


)












//Reverb


(

SynthDef(\fxexamplereverb, {arg delaytime=0.01, decaytime=1;

var input; 

var numc,numa,temp;


input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0


numc = 4; // number of comb delays

numa = 6; // number of allpass delays


// reverb predelay time :

temp = DelayN.ar(input, 0.048,0.048);


temp=Mix.fill(numc,{CombL.ar(temp,0.1,rrand(0.01, 0.1),5)});

// chain of 4 allpass delays on each of two channels (8 total) :

numa.do({ temp = AllpassN.ar(temp, 0.051, [rrand(0.01, 0.05),rrand(0.01, 0.05)], 1) });

// add original sound to reverb and play it :

Out.ar(0,(0.2*temp));

}).add;  

)


y= Synth.tail(a, \fxexamplereverb);


y.free;



//readymade Reverbs in SC3.2 and later

FreeVerb

FreeVerb2

GVerb


//If you build your own reverbs, useful UGens are: 

CombN, CombL, CombC

AllpassN, AllpassL, AllpassC

//and the delay reverbs above for early reflections










//simple feedback example, using the LocalIn and LocalOut UGens


(

{

var source = Impulse.ar(MouseX.kr(1,10));

var sound, feedback;

feedback = LocalIn.ar(1); //one channel of feedback

sound = source + feedback; 

LocalOut.ar(sound* MouseY.kr(0,0.9));  //feedback sound with some gain (<1 to stop feedback building up and overloading!). 

sound;

}.play

)


//can take on pitch at reciprocal of control period, which is the default delay time for feedback. You can add further delay via Delay UGens for the feedback signal. 

{SinOsc.ar(ControlDur.ir.reciprocal)*0.1}.play








//Phasing and Flanging



//phasing = play a signal back in combination with a phase shifted copy of itself (using an allpass filter); vary the delaytime under 20 msec



(

SynthDef(\fxexamplephasing, {arg freq=0.2;

var input, effect; 


input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0


effect= AllpassN.ar(input,0.02,SinOsc.kr(freq,0,0.01,0.01)); //max delay of 20msec


Out.ar(0,effect); //adds to bus 0 where original signal is already playing

}).add;  

)


x.free


x= Synth.head(a, \continuous);


y= Synth.tail(a, \fxexamplephasing);


y.set(\freq, 0.1)


y.set(\freq, 1)


y.free












//flanging= play a signal back in combination with a delayed copy of itself; vary the delaytime around 10 msec

//flanging usually also involves some feedback, achieved here using LocalIn and LocalOut


(

SynthDef(\fxexampleflanging, {arg flangefreq=0.1, fdback=0.1;

var input, effect; 


input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0


input= input+ LocalIn.ar(2); //add some feedback


effect= DelayN.ar(input,0.02,SinOsc.kr(flangefreq,0,0.005,0.005)); //max delay of 20msec


LocalOut.ar(fdback*effect);

//LocalOut.ar(fdback*BPF.ar(effect,MouseX.kr(1000,10000),0.1)); //alternative with filter in the feedback loop



Out.ar(0,effect); //adds to bus 0 where original signal is already playing

}).add;  

)


x.free


x= Synth.head(a, \continuous);


y= Synth.tail(a, \fxexampleflanging);


y.set(\flangefreq,0.4);


y.set(\fdback, 0.95);


y.free;

















//Dynamics Processing


s.scope


//compress or expand the dynamic range (amplitude variation) of a signal


(

SynthDef(\fxexamplecompression, {arg gain=1.5, threshold=0.5;

var input, effect; 


input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0


effect= CompanderD.ar(gain*input,threshold,1,0.5); 


ReplaceOut.ar(0,effect); //replaces bus 0 where original signal is already playing

}).add;  

)




x.free


x= Synth.head(a, \impulse);


y= Synth.tail(a, \fxexamplecompression);


y.free;


y= Synth.tail(a, \fxexamplecompression,[\gain,2, \threshold,0.1]);


y.free;













//a limiter forces an absolute limit, and is very useful as a final stage in a patch to avoid overloading 


(

SynthDef(\fxexamplelimiter, {arg gain=1;

var input, effect; 


input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0


effect= Limiter.ar(gain*input,0.99, 0.01); 


ReplaceOut.ar(0,effect); //replaces bus 0 where original signal is already playing

}).add;  

)




x.free


x= Synth.head(a, \impulse);


y= Synth.tail(a, \fxexamplelimiter);


y.set(\gain, 10) //careful with your ears! 


y.free;





Compander, Normalizer, Limiter





//Distortion


Adding new components into a signal to make it richer; modulation side effects are examples of these. 


//use a unary or binary operation (see the top of the AbstractFunctions or bottom of the Signal help files for some more)


{SinOsc.ar(440,0,0.5)}.play


{SinOsc.ar(440,0,0.5).distort}.play


{SinOsc.ar(440,0,0.5).cubed}.play //squared would put it an octave up; recall ring modulation and C+M, C-M


{SinOsc.ar(440,0,0.1).pow(MouseX.kr(0.1,1.0))}.scope


{SinOsc.ar(440,0,0.5).clip(-0.2,0.3)}.scope


{SinOsc.ar(440,0,0.1).round(2**(-7))}.scope //bit reduction to 7 bit signal


{Latch.ar(SinOsc.ar(440,0,0.1),Impulse.ar(MouseX.kr(100,20000)))}.scope //sr change; Latch allows crude resampling with aliasing (sample and hold signal values at assigned rate)





//pass through Shaper for waveshaping; each input value has an assigned output value in a lookup table


b = Buffer.alloc(s, 1024, 1);


// arbitrary transfer function, create the data at 1/2 buffer size + 1

t = Signal.fill(513, { |i| i.linlin(0.0, 512.0, -1.0, 1.0) });


// linear function

t.plot


// t.asWavetable will convert it to the official Wavetable format at twice the size

b.sendCollection(t.asWavetableNoWrap);  // may also use loadCollection here


// shaper has no effect because of the linear transfer function

(

{ var sig = Shaper.ar(b, SinOsc.ar(440, 0, 0.4));

sig ! 2

}.scope;

)



// now for a twist

(

a = Signal.fill(256, { |i| 

var t = i/255.0;  

t + (0.1 * (max(t, 0.1) - 0.1) * sin(2pi * t * 80 + sin(2pi * 25.6 * t)))

})

);


a.plot


d = (a.copy.reverse.neg) ++(Signal[0])++ a;


d.plot


d.size //must be buffer size/2 + 1, so 513 is fine


b.sendCollection(d.asWavetableNoWrap);  // may also use loadCollection here


b.plot // wavetable format! 


// test shaper

(

{ 

Shaper.ar(

b, 

SinOsc.ar(440, 0.5, Line.kr(0,0.9,6))

) 

}.scope

)





Shaper can also be used to deliberately distort a sine in a controlled manner, as a synthesis method. 


[Shaper]



Further examples of various effects, from distortion to delay effects, are in 


[Tour_of_UGens]