//--spektrografi, workshop@skaneskonst, oct2011

//--generating sounds that look good





/////////////////////////////////////////////


//day1



//--[mac osx only] boot internal server for scope to work


s= Server.internal;

Server.default= s;

s.boot;


//(same as clicking the default and boot buttons)



//--basic sounds


a= {SinOsc.ar([400, 404], 0, 0.1)}.scope

a.free


a= {Saw.ar([400, 404], 0.1)}.scope

a.free


a= {WhiteNoise.ar([0.1, 0.1])}.scope

a.free


//scope keyboard shortcuts: s, S, +, -, *, _, j, l, k, i, o, <space>, .

//cmd+. to stop

//alt+. on windows

//cmd+d for mac help

//f1 for windows help


a= {SinOsc.ar(500)*0.2}.scope

a.free


a= {SinOsc.ar( MouseX.kr(50, 600) )*0.2}.scope

a.free


a= {SinOsc.ar(MouseX.kr(200, 4000))*MouseY.kr(0, 0.2)}.scope

a.free


a= {SinOsc.ar(MouseX.kr(200, 4000))*SinOsc.kr(0.4)*0.2}.scope

a.free


a= {SinOsc.ar(MouseX.kr(200, 4000))*SinOsc.kr(MouseY.kr(0, 5))*0.2}.scope

a.free



//--argument positions

//SinOsc.ar(freq, phase, mul, add)

{SinOsc.ar(500)}.scope //freq only

{SinOsc.ar(500, 0, 0.2)}.scope //freq and amp



//this

{SinOsc.ar(500)*SinOsc.kr(1)}.plot(1)

{SinOsc.ar(500)*SinOsc.kr(1)}.play


//same as...

{SinOsc.ar(500, 0, SinOsc.kr(1))}.plot(1)

{SinOsc.ar(500, 0, SinOsc.kr(1))}.play



//and this...

{SinOsc.ar(500, 0, 0.2)+SinOsc.kr(1)}.scope

{SinOsc.ar(500, 0, 0.2)+SinOsc.kr(1)}.plot(1)


//same as...

{SinOsc.ar(500, 0, 0.2, SinOsc.kr(1))}.scope

{SinOsc.ar(500, 0, 0.2, SinOsc.kr(1))}.plot(1)




//--combining in different ways

{SinOsc.ar(500, 0, 0.2)+SinOsc.kr(1)+SinOsc.kr(4.6)*SinOsc.ar(100)*0.2}.plot(1)

{SinOsc.ar(500, 0, 0.2)+SinOsc.kr(1)+SinOsc.kr(4.6)*SinOsc.ar(100)*0.2}.play


{SinOsc.ar(500, 0, 0.2)*SinOsc.kr(1)+SinOsc.kr(4.6)+SinOsc.ar(100)*0.2}.plot(1)

{SinOsc.ar(500, 0, 0.2)*SinOsc.kr(1)+SinOsc.kr(4.6)+SinOsc.ar(100)*0.2}.play


//division can also give fun results

{SinOsc.ar(500, 0, 0.2)/SinOsc.kr(1)+SinOsc.kr(4.6)+SinOsc.ar(100)*0.2}.plot(1)


//--manual mixing

(

{

SinOsc.ar(100, 0, 0.1)

+SinOsc.ar(200, 0, 0.1)

+SinOsc.ar(300, 0, 0.1)

+SinOsc.ar(400, 0, 0.1)

+SinOsc.ar(500, 0, 0.1)

+SinOsc.ar(600, 0, 0.1)

+SinOsc.ar(700, 0, 0.1)

+SinOsc.ar(800, 0, 0.1)

}.plot(1)

)


//slight detune -> more complex shapes

(

{

SinOsc.ar(100, 0, 0.1)

+SinOsc.ar(202, 0, 0.1)

+SinOsc.ar(300, 0, 0.1)

+SinOsc.ar(406, 0, 0.1)

+SinOsc.ar(500.5, 0, 0.1)

+SinOsc.ar(600, 0, 0.1)

+SinOsc.ar(699, 0, 0.1)

+SinOsc.ar(810, 0, 0.1)

}.plot(1)

)


//play the above examples and listen to the differences



//also change amplitude of the individual oscillators and way of combining (+, -, *, /)

(

{

SinOsc.ar(100, 0, 0.11)

+SinOsc.ar(200, 0, 0.1)

/SinOsc.ar(300, 0, 0.1)

-SinOsc.ar(400, 0, 0.1)

+SinOsc.ar(500, 0, 0.1)

*SinOsc.ar(600, 0, 0.1)

+SinOsc.ar(700, 0, 0.06)

+SinOsc.ar(800, 0, 0.1)

+SinOsc.ar(801, 0, 0.1)

}.plot(1)

)


//kr vs ar.  kr= control rate, ar= audio rate

//rule of thumb >20 ar, <20 kr



//--multichannel expansion

{SinOsc.ar([400, 500], 0, [0.1, 0.5])}.scope //stereo sound



//--mixing n number of channels to mono

{Mix(SinOsc.ar([400, 404], 0, [0.5, 0.5]))}.play

{Mix(SinOsc.ar([400, 404], 0, [0.5, 0.5]))}.plot(1)


{Mix(SinOsc.ar([400, 404, 600, 700, 505, 2000, 5], 0, 0.1))}.play

{Mix(SinOsc.ar([400, 404, 600, 700, 505, 2000, 5], 0, 0.1))}.plot(1)



//--loops

(

r= Routine({

inf.do{

0.1.wait;

a= {SinOsc.ar(500.rand+500)}.play;

0.2.wait;

a.release(0.1);

};

});

)

r.play

r.stop

a.free



//--different waveforms

{Saw.ar(400)}.plot

{LFSaw.ar(400)}.plot


{LFTri.ar(400)}.plot


{Pulse.ar(400)}.plot

{LFPulse.ar(400)}.plot


{WhiteNoise.ar(0.1)}.plot

{PinkNoise.ar(1)}.plot

{GrayNoise.ar(0.5)}.plot

{BrownNoise.ar(0.5)}.plot

{ClipNoise.ar(0.5)}.plot



//see Tour_of_UGens helpfile




//run the following examples in phase mode: shift+s


{SinOsc.ar([400, 404], 0, 0.7)}.scope


s.scope


//'s' to toggle combined channel mode

//'shift+s' to switch to phase mode

//for phase mode must use stereo


{SinOsc.ar([400, 404], 0, [MouseX.kr(0, 1), MouseY.kr(0, 1)])}.scope


{SinOsc.ar([MouseX.kr(4, 400), MouseY.kr(2, 200)], 0, 0.9)}.scope


{SinOsc.ar([MouseX.kr(4, 400), MouseY.kr(2, 200)], 0, 0.9)*LFSaw.ar(1)}.scope(bufsize:256)


//try different buffersize: 64, 128, 256, 512, 1024, 2048, 4096, 8192


//0.25 is circle width, 1 is height

{SinOsc.ar([500, 500.7], [0, pi*0.5], [0.25, 1])}.scope(bufsize:128)


{Saw.ar([500, 500.7], [0.25, 1])}.scope(bufsize:128)


{LFTri.ar([MouseX.kr(1, 100), MouseY.kr(1, 100)])}.scope(bufsize:2048)


{LFTri.ar([MouseX.kr(1, 100), MouseY.kr(1, 100)]+SinOsc.ar([4, 4.4]))}.scope(bufsize:2048)




//--recording sound

//click record button to start and stop.  the resulting file will be in this directory:

thisProcess.platform.recordingsDir  //run this line to post filepath




//--screenshots

//mac osx: press cmd+shift+4 and the <space>, click in the window you want to grab


//windows: click window and press Alt+Print Screen (psc) to take a screenshot under win xp

// open Accessories/Paint and Paste




//--inspiration:


//cymatics - "the study of visible sound and vibration"

http://en.wikipedia.org/wiki/Cymatics

http://www.youtube.com/watch?v=sY6z2hLgYuY

http://www.youtube.com/watch?v=3csi-2Hrzhg

http://www.youtube.com/watch?v=3zoTKXXNQIU

http://www.youtube.com/watch?v=uQWBA8q8JEs

http://www.youtube.com/watch?v=NIoFJibzww8


//using oscilloscopes

http://robinfox.net/projects/oscilloscope/

http://www.youtube.com/watch?v=GFBHVDMUgXM


//spectrograms

aphex twin http://www.youtube.com/watch?v=M9xMuPWAZW8

metasynth http://www.uisoftware.com/MetaSynth/index.php

xenakis upic http://www.youtube.com/watch?v=yztoaNakKok






/////////////////////////////////////////////


//day2



//--Stethoscope

(

w= Window.new("Stethoscope test", Rect(20, 20, 400, 500));

c= Stethoscope(s, view:w.view, bufsize: 1024);

w.front;

CmdPeriod.doOnce({c.free; if(w.isClosed.not, {w.close})});

//i, o //busses

//s, S //styles

//k //audio/control rate

//j, l //inc/dec offset

//+, - //inc/dec x zoom

//*, _ //inc/dec y zoom

//<space>, . //start/stop

)


//now make some sounds.  e.g.

a= {SinOsc.ar([4, 5]*MouseX.kr(1, 100), MouseY.kr(0, 2pi), 0.9)}.play

a.free


a= {Splay.ar(SinOsc.ar([1, 2, 3, 4, 5]*MouseX.kr(1, 100), MouseY.kr(0, 2pi), 0.7))}.play

a.free


//press cmd+. / alt+. to close window and free buffer




//--ScopeView

(

b= Buffer.alloc(s, 2048, 2); //buffersize

w= Window("ScopeView test", Rect(20, 20, 640, 480), false).front;

c= ScopeView(w.view, w.view.bounds);

c.bufnum= b.bufnum;

SynthDef(\scope, {|buf|

var z= In.ar(0, 2);

ScopeOut.ar(z, buf);

}).play(RootNode(s), [\buf, b], \addToTail);

CmdPeriod.doOnce({b.free; if(w.isClosed.not, {w.close})});

)


a= {SinOsc.ar([400, 500]*SinOsc.ar(MouseX.kr(1, 100)), MouseY.kr(0, 8pi), 0.5)}.play


c.style= 0

c.style= 1

c.style= 2

c.xZoom= 2

c.yZoom= 0.5

c.waveColors= [Color.red, Color.green]

c.style= 0

a.free


//press cmd+. / alt+. to close window and free buffer




//--Spectrogram (NOTE: this example is mac osx only - also need to install the quark 'Spectrogram')

(

w= Window("Spectrogram test", Rect(10, 10, 1200, 900), false).front;

v= Spectrogram(w, Rect(0, 0, 1200, 900), 4096, Color.red, Color.black, 25, 5000); //buffersize, colours, min and max frequencies

v.start;

v.intensity= 2; //colour

v.rate= 50; //speed

CmdPeriod.doOnce({v.free; if(w.isClosed.not, {w.close})});

)


a= {SinOsc.ar([400, 500]+SinOsc.ar(MouseY.kr(0, 100), 0, MouseX.kr(1, 100)), 0, 0.5)}.play

a.free


a= {Saw.ar(100*SinOsc.ar(SinOsc.ar(SinOsc.ar(0.1)*0.2)).abs+50, 0.5)}.play

a.free


v.stop

v.free

w.close





/////////////////////////////////////////////


//amptrack


(

s.latency= 0.05;

s.waitForBoot{

//--window setup

var width= 500, height= 500;

var w= Window("amptrack", Rect(99, 99, width, height), false, false);

var u= UserView(w, Rect(0, 0, width, height));

//--variables

var fps= 60;

var num= 100; //number of tuned filter synths

var cnt= 0; //vertical drawing position

var amps= 0.dup(num); //array of current amplitudes

var o= OSCresponder(s.addr, '/tr', {|t, r, m| amps= amps.put(m[2], m[3])}).add;

var syns;

var wn= width/num;

var w2= width*0.5;

var h2= height*0.5;

//--interface

~freqMin= 200;

~freqMax= 6000;

~width= 120;

~speed= 1;

~extra= 1;

~version= 1;

//--synths

SynthDef(\avTrk, {|in, t_trig, time= 0.01, cutoff= 400, index= 0|

var z= In.ar(in, 1);

var val= Amplitude.kr(BPF.ar(BPF.ar(z, cutoff, 0.1, 5), cutoff, 0.1, 5), time, time);

SendTrig.kr(t_trig, index, val);

}).send(s);

s.sync;

syns= {|i| //each tracker with an unique peakfilter

Synth(\avTrk, [\in, 0, \index, i, \cutoff, i.linexp(0, num-1, ~freqMin, ~freqMax)]).play;

}.dup(num);

s.sync;

//--main loop

u.drawFunc= {

//--first frame clear to black

if(cnt==0, {

Pen.fillColor= Color.black;

Pen.fillRect(Rect(0, 0, width, height));

});

//--optional oval mask

/*

Pen.moveTo(Point(w2, 0));

Pen.arcTo(Point(width, 0), Point(width, h2), w2);

Pen.arcTo(Point(width, height), Point(w2, height), w2);

Pen.arcTo(Point(0, height), Point(0, h2), w2);

Pen.arcTo(Point(0, 0), Point(w2, 0), w2);

Pen.clip;

*/

switch(~version,

0, {

Pen.translate(wn*0.5, cnt%height);

amps.do{|amp, i|

Pen.fillColor= Color.grey((amp*~extra).clip(0, 1));

Pen.fillRect(Rect.aboutPoint(Point(wn*i, 0), wn*0.5, ~width));

};

cnt= cnt+~speed;

},

1, {

amps.do{|amp, i|

Pen.rotate(cnt, w2, h2);

Pen.strokeColor= Color.grey((amp*~extra).clip(0, 1));

Pen.strokeRect(Rect.aboutPoint(Point(wn*i, 0), ~width*0.1, ~width));

cnt= cnt+(~speed*0.000001);

};

},

2, {

Pen.rotate(cnt, w2, h2);

Pen.translate(w2, h2);

amps.do{|amp, i|

Pen.strokeColor= Color.grey((amp*~extra).clip(0, 1));

Pen.strokeOval(Rect.aboutPoint(Point(i*~speed, 0), ~width*0.5, ~width*0.5));

};

cnt= cnt+(~speed*0.01);

}

);

syns.do{|x| x.set(\t_trig, 1)}; //request amp data

};

//--window management

u.clearOnRefresh= false; //do not erase - just draw on top of

w.onClose= {

syns.do{|x| x.free};

o.remove;

};

w.front;

CmdPeriod.doOnce({if(w.isClosed.not, {w.close})});

//Routine({while({w.isClosed.not}, {u.refresh; (1/fps).wait})}).play(AppClock);

u.animate= true;

};

)


//change these while the program is running

~width= 50;

~speed= 2;

~speed= -0.1;

~speed= pi;

~version= 0;

~width= 20;

~speed= 1;

~width= 10;

~speed= 10;

~width= 250;

~width= 500;

~version= 2;

~width= 100;

~speed= 1;

~speed= -1.5;

~width= 20;

~extra= 7;



//--tweet0014

play{a=SinOscFB;sum({|i|a.ar(a.ar(a.ar(a.ar(i+1,1/9,999),1/9,a.ar(1/9,1,1/9)),a.ar(0.1,3),i+2*999),a.ar(1/9,1/9),1/9)}!9)!2}//#SuperCollider








/////////////////////////////////////////////


//fft


(

s.latency= 0.05;

s.waitForBoot{

//--variables

var l= 512; //try with 512 if you have a fast machine

var scale= if(l<=256, {2}, {1}); //scale can be 1 or 2

var cnt= 0; //horizontal drawing position

var fftArray= Array.fill(l, 0);

var o= OSCresponder(s.addr, '/tr', {|t, r, m|

var v= m[3].min(1); //brutal clip of mags here

var i= l.div(2);

fftArray= fftArray.put([i-m[2], i+m[2]], v); //mirror middle of array

}).add;

var trk;

//--window setup

var width= 512+10, height= 512+10;

var w= Window("fft", Rect(99, 99, width, height), false);

var u= UserView(w, Rect(0, 0, width, height));

//--interface

~speed= 1;

~version= 0;

~radius= 2/scale;

~depth= 0.01;

~trails= 0.5;

~fps= 60;

//--synths

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

SynthDef(\avTrk, {|in= 0, t_trig= 0|

var z= In.ar(in, 1);

var chain= FFT(b, z);

Array.fill(l.div(2), {|i|

var a= Unpack1FFT(chain, l, i, 0);

var b= Demand.kr(chain>=0, 0, a);

SendTrig.kr(t_trig, i, b);

});

}).send(s);

s.sync;

trk= Synth(\avTrk, [\in, 0], RootNode(s), \addToTail);

s.sync;

//--main loop

u.drawFunc= {

switch(~version,

0, { //rectangles

Pen.translate(5, 5);

fftArray.do{|a, y|

var p= Point(cnt*scale, height-10-(y*scale));

Pen.fillColor= Color.grey((1-a).clip(0, 1));

Pen.fillRect(Rect.aboutPoint(p, scale*~radius, scale*~radius));

};

cnt= cnt+~speed%fftArray.size;

Pen.strokeColor= Color.red;

Pen.line(Point(cnt*scale, 0), Point(cnt*scale, l*scale));

Pen.stroke;

},

1, { //ovals with a little transparency

Pen.translate(5, 5);

fftArray.do{|a, y|

var p= Point(cnt*scale, height-10-(y*scale));

Pen.fillColor= Color.grey((1-a).clip(0, 1), 0.5);

Pen.fillOval(Rect.aboutPoint(p, scale*~radius, scale*~radius));

};

cnt= cnt+~speed%fftArray.size;

},

2, { //rotation

Pen.fillColor= Color.grey(1, ~trails);//clear color with some alpha

Pen.fillRect(Rect(0, 0, width, height));//manually clear with rect

fftArray.do{|a, y|

var p= Point(cnt*scale, height-(y*scale));

Pen.rotate(y/l*0.25*scale*2pi*~depth, width*0.5, height*0.5);

Pen.fillColor= Color.grey((1-a).clip(0, 1));

Pen.fillOval(Rect.aboutPoint(p, scale*~radius, scale*~radius));

};

cnt= cnt+~speed%fftArray.size;

},

3, { //lines

Pen.fillColor= Color.grey(1, ~trails);

Pen.fillRect(Rect(0, 0, width, height));

fftArray.do{|a, y|

var p= Point(cnt.fold(0, l*scale), height-y);

Pen.strokeColor= Color.grey(1-(a+0.5).clip(0, 1), 0.5);

Pen.moveTo(p*a); //move to before rotation special here

Pen.rotate(y/l*pi*0.5*scale*~depth, width*0.5, height*0.5);

Pen.lineTo(p);

Pen.stroke;

};

cnt= cnt+~speed;

}

);

trk.set(\t_trig, 1); //to all send trigs

};

//--window management

u.clearOnRefresh= false; //do not erase - just draw on top of

w.onClose= {

trk.free;

o.remove;

b.free;

};

w.front;

//Routine({while({w.isClosed.not}, {u.refresh; (1/~fps).wait})}).play(AppClock);

u.animate= true;

CmdPeriod.doOnce({if(w.isClosed.not, {w.close})});

};

)


//change these while the program is running

~version= 1;

~radius= 4;

~speed= 8;

~speed= 256/6;

~radius= 256/25;

~speed= -1;

~version= 2;

~trails= 0.01;

~radius= 5;

~speed= 2;

~radius= 0.5;

~depth= -0.002;

~depth= 3;

~radius= 1;

~trails= 0.5;

~version= 3;

~depth= 0.5;

~speed= 5;

~depth= -0.1;

~depth= -0.01

~trails= 0.01;



//waveform


(

s.latency= 0.05;

s.waitForBoot{

//--variables

var l= 750; //global window size

var theta= 0;

var fps= 60;

var arr= Array.fill(l, 0); //same as half windowsize above

var o= OSCresponder(s.addr, '/tr', {|t, r, m|

if(m[2]==0, { //redraw once for each cycle of amps

b.getn(0, l-1, {|data| {arr= data; u.refresh}.defer});

});

}).add;

var trk, cnt= 0;

//--window setup

var width= l, height= l;

var w= Window("waveform", Rect(99, 99, width, height), false);

var u= UserView(w, Rect(0, 0, width, height));

var w2= width*0.5;

var h2= height*0.5;

//--interface

~trails= 1;

~speed= 0;

~sample= 1;

~amp= 0.5;

~version= 0;

//--synths

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

SynthDef(\avTrk, {|in= 0, bufnum, rate= 40, sample= 1|

var z= In.ar(in, 1);

var trig= Impulse.kr(rate);

var index= Phasor.ar(trig, sample, 0, BufFrames.ir(bufnum)-1);

BufWr.ar(z, bufnum, index, 0);

SendTrig.kr(trig, 0, bufnum);

}).send(s);

s.sync;

trk= Synth(\avTrk, [\in, 0, \bufnum, b, \rate, fps], RootNode(s), \addToTail);

s.sync;

//--main loop

u.drawFunc= {

if(cnt==0, {

Pen.fillColor= Color.black; //erase first time

Pen.fillRect(Rect(0, 0, width, height));

});

trk.set(\sample, ~sample);

Pen.fillColor= Color.grey(0, ~trails);

Pen.fillRect(u.bounds); //manually clear

Pen.strokeColor= Color.green;

switch(~version,

0, { //line

Pen.rotate(theta, w2, h2);

Pen.translate(0, h2);

arr.do{|y, x|

var p= Point(x, y*(height*~amp));

if(x==0, {Pen.moveTo(p)}, {Pen.lineTo(p)});

};

Pen.stroke;

},

1, { //warp

Pen.rotate(theta, w2, h2);

Pen.translate(w2, h2);

arr.do{|y, x|

var p= Point(x*~amp, y*~amp).rotate(y*2pi);

if(x==0, {Pen.moveTo(p)}, {Pen.lineTo(p)});

};

Pen.stroke;

},

2, { //flower

Pen.translate(w2, h2);

Pen.moveTo(Point(arr[0], 0)*arr[0]);

arr.do{|y, x|

var p= Point(y, x)*y;

var a= x%width/width*2pi+theta;

Pen.lineTo(p.rotate(a));

};

Pen.stroke;

}

);

theta= theta+~speed;

cnt= cnt+1;

};

//--window management

u.clearOnRefresh= false; //do not erase - just draw on top of

w.onClose= {

trk.free;

o.remove;

b.free;

};

w.front;

CmdPeriod.doOnce({if(w.isClosed.not, {w.close})});

//note no routine here. the responder is driving the animation

};

)


//change these while the program is running

~sample= 2;

~sample= 10;

~sample= 1;

~trails= 0.2;

~speed= 0.1;

~speed= -0.05;

~trails= 0.01;

~amp= 0.02;

~speed= pi*0.25;

~amp= 0.2;

~sample= 2;

~version= 1;

~trails= 0.2;

~version= 2;

~sample= 1;

~version= 1;

~speed= 2pi*1.001;

~amp= 0.5;




/////////////////////////////////////////////


//day3+4



//own project and exhibition