//-- Switch from PureData! (or MAX/MSP for that matter)

//-- workshop 110513, organized by l'ull cec [ http://lullcec.org ] @hangar

//-- beginner-intermediate level



//--running code...


//fn+return - for osx

//ctrl+return - for win

//c-c, c-c - for emacs


1+10


1/40


3+4+5


( //select all inbetween () and evaluate

var a= 5;

a+100;

)




//--making sound...

s.boot


//panic stop all sound keyboard shortcuts

//cmd+. - for osx

//alt+. - for win

//c-c, c-s - for emacs


Ndef(\mysine).play

Ndef(\mysine, {SinOsc.ar(500)})

Ndef(\mysine).stop


//multi channel expansion

Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar([400, 404])}) //two sawtooth oscillators

Ndef(\mysaw).stop


Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar([400, 404, 500])})

Ndef(\mysaw).stop


//mysaw ndef is stereo by default so channels will wrap left, right, left, right etc


Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar([400, 404, 500, 505, 600, 606], 0.5)})

Ndef(\mysaw).stop


//0.5 is amplitude.  we need to scale down the signal to not distort


{100.rand+500}.dup(10) //generate array with 10 random integers between 500 and 599 


Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar({500.rand+600}.dup(20), 0.1)})

Ndef(\mysaw, {Saw.ar({500.rand+600}.dup(20), 0.1)})

Ndef(\mysaw, {Saw.ar({500.rand+600}.dup(20), 0.1)})

Ndef(\mysaw).stop


//the clicks are phase alignment due to integer numbers.

//try same but with floats...

Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(20), 0.1)})

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(20), 0.1)})

Ndef(\mysaw).stop


//and with different number of sawtooth oscillators...

Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(4), 0.2)})

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(30), 0.1)})

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(60), 0.07)})

Ndef(\mysaw).stop

//note how we compensate for amplitude due to the shifting number of oscillators


//and amplitude (mul) argument can also be an array...

Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(10), [0.1, 0.2, 0.05])})

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(10), {0.2.rand}.dup(10))})

Ndef(\mysaw).stop


//set a cross fade time

Ndef(\mysaw).fadeTime= 2 //2 seconds

Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(20), 0.1)})

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(10), 0.12)})

Ndef(\mysaw, {Saw.ar({500.0.rand+600}.dup(30), 0.08)})

Ndef(\mysaw).stop


//last with different range (run each line multiple times)


0.5.rrand(1.0) //range random between 0.5 and 1.0


Ndef(\mysaw).play

Ndef(\mysaw, {Saw.ar({50.0.rand+1000}.dup(40), {0.2.rand}.dup(40))})

Ndef(\mysaw, {Saw.ar({50.0.rrand(1000)}.dup(40), {0.2.rand}.dup(40))})

Ndef(\mysaw, {Saw.ar({150.0.rrand(5000)}.dup(50), 0.1)})

Ndef(\mysaw, {Saw.ar({350.0.rrand(400)}.dup(30), 0.15)})

Ndef(\mysaw).stop




//--draw the synthesis network

Ndef(\mysaw).source.draw  //needs graphviz and rd_dot quark


//install the rd_dot quark with this command

Quarks.install("rd_dot")


//download and install graphviz separately from

http://www.pixelglow.com/graphviz/


//(version 2.26 works well on my mac osx 10.5.8)




//--more static sounds


Ndef(\pad).play

Ndef(\pad, {SinOsc.ar({300.rrand(1600)}.dup(10), 0, 0.1)})

Ndef(\pad).fadeTime= 5


//now modulate with another sinosc instead of static 0.1 amplitude (run multiple times)

Ndef(\pad, {SinOsc.ar({300.rrand(1600)}.dup(10), 0, 0.1+SinOsc.ar({0.01.rrand(0.2)}.dup(10), 0, 0.1))})

Ndef(\pad, {SinOsc.ar({400.rrand(700)}.dup(15), 0, 0.1+SinOsc.ar({0.01.rrand(1.0)}.dup(15), 0, 0.1))})

Ndef(\pad).source.draw

Ndef(\pad).stop




//--recording soundfiles


//just click the record button in the server gui window


thisProcess.platform.recordingsDir //where files are stored by default


//optional: set a different path if you prefer

thisProcess.platform.recordingsDir = "/Users/ifields/Desktop/"


//and set different file header, sampleformat if you prefer

s.recHeaderFormat= "WAV"

s.recSampleFormat= "int16"


//but it's recommended to use the default 32bit floatingpoint aiff




//--level meters display


s.meter


//handy gui to see in and outgoing levels

//can also be activated by bringing the server gui window to the front and typing the letter 'l'




//--recommended patch setup


//save the following in a seperate document and use as template for you own patches.  includes some handy gui for playing back your sounds


s.boot

s.meter

NdefMixer(s)


Ndef(\pad).play

Ndef(\pad, {SinOsc.ar({300.rrand(1600)}.dup(10), 0, 0.1+SinOsc.ar({0.1.rrand(0.5)}.dup(10), 0, 0.1))})

Ndef(\pad).fadeTime= 5


Ndef(\pad).vol= 0.4

Ndef(\pad).stop(6) //fade out over 6 sec




//--envelopes...

Env.perc(0.1, 0.5).plot

Env.perc(0.1, 0.5, 0.6).plot  //goes from 0 to 0.6 (plot will look similar due to normalisation)

Env.perc(0.1, 0.5, 0.6, 0).plot //fourth arg is curve

Env.perc(0.1, 0.5, 0.6, 3).plot

Env.perc(0.1, 0.5, 0.6, -4).plot //-4 is the default


Env.sine(0.2).plot


Env.adsr(0.01, 0.2, 0.75, 0.1, 0.6, -4).plot


//see Env helpfile for more


//manually set levels, times, curves

Env([0, 1, 0], [0.2, 0.6], [0, -4]).plot

Env([0, 1, 0.3, 0.8, 0.1, 0], [0.2, 0.6, 0.1, 0.6, 2], [0, -4, 2.5, 3, 5]).plot


//always one more value in the levels array.  this is the init starting value.


//there is also .test for quickly listening to the envelope

Env([0, 1, 0.2, 0.3, 0], [0.2, 0.1, 0.1, 0.6], -3).plot.test




//--playing sounds that start and stop

Ndef(\myping).play

Ndef(\myping, {EnvGen.ar(Env.perc(0.05, 2.5), doneAction:2)*SinOsc.ar([400, 404])})


Ndef(\myping).spawn //will re-trigger




//--arguments


//arguments are sort of the equivalent of inlets in puredata

Ndef(\myping, {|freq= 400| EnvGen.ar(Env.perc(0.05, 2.5), doneAction:2)*SinOsc.ar([freq, freq+4])})

//compare with ndef above.  the only thing we added was freq.  should sound the same


//but now we re-trigger with different values for the freq argument

Ndef(\myping).spawn([\freq, 600.rrand(800)])

Ndef(\myping).spawn([\freq, 600.rrand(800)])

Ndef(\myping).spawn([\freq, 600.rrand(800)])


//add 2 more arguments: amp, pan

Ndef(\myping, {|freq= 400, amp= 0.5, pan= 0| EnvGen.ar(Env.perc(0.05, 2.5, amp), doneAction:2)*Pan2.ar(Mix(SinOsc.ar([freq, freq+4])), pan)})


Ndef(\myping).source.draw


Ndef(\myping).spawn([\freq, 600.rrand(800), \amp, 0.6.rand, \pan, -1.0.rrand(1.0)])

Ndef(\myping).spawn([\freq, 600.rrand(800), \amp, 0.6.rand, \pan, -1.0.rrand(1.0)])

Ndef(\myping).spawn([\freq, 600.rrand(800), \amp, 0.6.rand, \pan, -1.0.rrand(1.0)])


//add even 2 more arguments (atk and rel)

Ndef(\myping, {|freq= 400, amp= 0.5, pan= 0, atk= 0.05, rel= 2.5| EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2)*Pan2.ar(Mix(SinOsc.ar([freq, freq+4])), pan)})


Ndef(\myping).spawn([\freq, 600.rrand(800), \amp, 0.6.rand, \pan, -1.0.rrand(1.0), \atk, 0.05.rand, \rel, 0.8.rand])


//or same but using midi notes as frequencies

60.rrand(80).midicps


Ndef(\myping).spawn([\freq, 60.rrand(80).midicps, \amp, 0.6.rand, \pan, -1.0.rrand(1.0), \atk, 0.05.rand, \rel, 0.8.rand])



//--sequencing...

(

Tdef(\metro, {loop{

Ndef(\myping).spawn([\freq, 60.rrand(80).midicps, \amp, 0.4.rand, \pan, -1.0.rrand(1.0), \atk, 0.05.rand, \rel, 0.4.rand]);

0.1.wait;

}}).play;

)

Tdef(\metro).stop


//using arrays with counter i indexing

(

Tdef(\metro, {var i= 0; loop{

Ndef(\myping).spawn([\freq, [50, 60, 55, 53, 80, 82].wrapAt(i).midicps, \amp, [0, 0.2, 0.1, 0.2, 0.3].wrapAt(i), \pan, -1.0.rrand(1.0), \atk, 0.05.rand, \rel, 0.4.rand]);

0.1.wait;

i= i+1;

}}).play;

)


//it's possible to change the sound while sequencer is running

Ndef(\myping, {|freq= 400, amp= 0.5, pan= 0, atk= 0.05, rel= 2.5| EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2)*Pan2.ar(Mix(SinOsc.ar([freq, freq+4])+WhiteNoise.ar(0.3)), pan)})


//also one can change the sequencer without stopping

(

Tdef(\metro, {var i= 0; loop{

Ndef(\myping).spawn([\freq, [60, 80].wrapAt(i).midicps, \amp, [0, 0.1, 0.2, 0.05, 0.1].wrapAt(i), \pan, -1.0.rrand(1.0), \atk, 0.02.rand, \rel, [0.3, 0.1].wrapAt(i)]);

[0.125, 0.125, 0.125, 0.125, 0.125, 1/16, 1/16].wrapAt(i).wait;

i= i+1;

}}).play;

)

Tdef(\metro).stop




//--new example

Ndef(\snare).play

Ndef(\snare,{|amp= 0.1, atk= 0.01, rel= 0.1, pan= 0| Pan2.ar(WhiteNoise.ar*EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2), pan)})


Ndef(\drum).play

Ndef(\drum, {|amp= 0.5, atk= 0.03, rel= 0.5, pan= 0, freq= 100| Pan2.ar(Mix(SinOsc.ar([freq, freq+4]))*EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2), pan)})


Ndef(\hat).play

Ndef(\hat, {|amp= 0.1, atk= 0.02, rel= 0.1, pan= 0, freq= 4000| Pan2.ar(BPF.ar(GrayNoise.ar, freq, 0.2, 10)*EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2), pan)})


Tdef(\seq).play(quant:1)

Tdef(\seq, {loop{Ndef(\drum).spawn; 1.wait}})

Tdef(\seq2).play(quant:1)

Tdef(\seq2, {loop{Ndef(\hat).spawn; 2.wait}})

Tdef(\seq3).play(quant:1)

Tdef(\seq3, {loop{Ndef(\snare).spawn([\rel, 0.5.rand]); 4.wait}})


Tdef(\seq, {var i= 0; loop{Ndef(\drum).spawn([\freq, [60, 60, 160, 180, 180, 190].wrapAt(i)]); [0.5, 0.5, 0.5, 0.125, 0.125].wrapAt(i).wait; i= i+1}})


Tdef(\seq, {var i= 0; loop{Ndef(\drum).spawn([\freq, [60, 60, 160, 180, 180, 190].wrapAt(i), \pan, [-1, 1].wrapAt(i)]); [0.5, 0.5, 0.5, 0.125, 0.125].wrapAt(i).wait; i= i+1}})


Tdef(\seq2, {loop{Ndef(\hat).spawn([\freq, 3000.rrand(8000), \amp, 0.15.rand]); 0.125.wait; }})


TempoClock.default.tempo= 114/60 //114 bpm

TempoClock.default.tempo= 80/60 //80 bpm


Tdef(\seq3, {var i= 0; loop{Ndef(\snare).spawn([\amp, [0.2, 0.1, 0.05, 0].wrapAt(i), \pan, -0.3.rrand(0.3)]); 0.25.wait; i= i+1}})


Tdef(\seq, {var i= 0; loop{Ndef(\drum).spawn([\freq, [100, 200, 300, 400, 500, 500.rrand(1500)].wrapAt(i), \pan, [-0.8, 0, 0.8].wrapAt(i), \atk, 0.005, \rel, 0.1]); [0.5, 0.5, 0.5, 0.125, 0.125].wrapAt(i).wait; i= i+1}})


Tdef(\seq4).play(quant:1) //different tdef using same ndef (drum)

Tdef(\seq4, {var i= 0; loop{Ndef(\drum).spawn([\freq, 50, \atk, 0, \rel, 0.1, \amp, 0.7]); 0.5.wait; i= i+1}})


Tdef(\seq2).stop

Tdef(\seq3).stop

Tdef(\seq4).stop

Tdef(\seq).stop


Tdef(\seq).play(quant:1)

Tdef(\seq2).play(quant:1)

Tdef(\seq4).play(quant:1)

Tdef(\seq3).play(quant:1)


Tdef(\seq).stop

Tdef(\seq4).stop

Tdef(\seq3).stop

Tdef(\seq2).stop




//--additional tips and tricks


OSCresponder //receive osc data over network

NetAddr //send osc data



//some granulators that comes with sc

TGrains, GrainBuf, GrainFM, GrainIn, GrainSin



//package manager gui to install more extras

Quarks.gui


SynthDefPool //quark with premade instruments

sc3-plugins //separate download plugins (recommeded - lots of extras here)



//different speaker setups, ambisonics etc

VBAP, PanAz, BiPanB2



//using your own soundcard you will need to set your own ServerOptions

Server.default.options.dump //list current server options

//see helpfile: using the startup file



//there is built in simple gui control for ndefs

//just do .edit on an existing ndef.  click play button to start and send to retrigger in case the ndef uses an envelope

Ndef(\myping).edit

Ndef(\snare).edit



//some sc tweets (little pieces that fit in 140 characters)

http://supercollider.sourceforge.net/sc140/


http://fredrikolofsson.com/f0blog/?q=node/478



//openobject quark to easily connect puredata or maxmsp with supercollider

http://fredrikolofsson.com/f0blog/?q=node/401




//--learning more...


//sample chapter from the scbook

http://supercolliderbook.net/wilsondescrivanch3.pdf


//and the sc book itself is of course recommended reading


//last check this page for a collection of links

http://supercollider.sourceforge.net/learning/