vertex

clean-up #25:

attached is a little class that draws polygons in supercollider. with inspiration from processing.
if you want to use the \point type of shape it will look better with smoothing set to false and Vertex.pointSize= 0;

update 101211: attached a simple BezierVertez class. it works like this one.
update 101215: improved the \triangleFan type in vertex.sc.
update 141012: minor update to BezierVertez.sc - added close argument

(
        var win= Window("vertex test", Rect(100, 100, 430, 320), false);
        win.drawHook= {
                Pen.fillColor= Color.white;
                Pen.strokeColor= Color.black;
               
                Pen.use{
                        Pen.translate(10, 10);
                        Vertex.beginShape();
                        Vertex(Point(30, 20));
                        Vertex(Point(85, 20));
                        Vertex(Point(85, 75));
                        Vertex(Point(30, 75));
                        Vertex.endShape(1);             //1 means close
                        Pen.fillStroke;                 //also try fill and stroke
                };
                Pen.use{
                        Pen.translate(110, 10);
                        Vertex.beginShape(\points);
                        Vertex(Point(30, 20));
                        Vertex(Point(85, 20));
                        Vertex(Point(85, 75));
                        Vertex(Point(30, 75));
                        Vertex.endShape();
                        Pen.stroke;
                };
                Pen.use{
                        Pen.translate(210, 10);
                        Vertex.beginShape(\lines);
                        Vertex(Point(30, 20));
                        Vertex(Point(85, 20));
                        Vertex(Point(85, 75));
                        Vertex(Point(30, 75));
                        Vertex.endShape();
                        Pen.stroke;
                };
                Pen.use{
                        Pen.translate(310, 10);
                        Vertex.beginShape();
                        Vertex(Point(30, 20));
                        Vertex(Point(85, 20));
                        Vertex(Point(85, 75));
                        Vertex(Point(30, 75));
                        Vertex.endShape(0);             //0 means not close (default)
                        Pen.stroke;
                };
               
                Pen.use{
                        Pen.translate(10, 110);
                        Vertex.beginShape();
                        Vertex(Point(30, 20));
                        Vertex(Point(85, 20));
                        Vertex(Point(85, 75));
                        Vertex(Point(30, 75));
                        Vertex.endShape(1);             //1 means close
                        Pen.stroke;
                };
                Pen.use{
                        Pen.translate(110, 110);
                        Vertex.beginShape(\triangles);
                        Vertex(Point(30, 75));
                        Vertex(Point(40, 20));
                        Vertex(Point(50, 75));
                        Vertex(Point(60, 20));
                        Vertex(Point(70, 75));
                        Vertex(Point(80, 20));
                        Vertex.endShape();
                        Pen.fillStroke;                 //also try fill and stroke
                };
                Pen.use{
                        Pen.translate(210, 110);
                        Vertex.beginShape(\triangleStrip);
                        Vertex(Point(30, 75));
                        Vertex(Point(40, 20));
                        Vertex(Point(50, 75));
                        Vertex(Point(60, 20));
                        Vertex(Point(70, 75));
                        Vertex(Point(80, 20));
                        Vertex(Point(90, 75));
                        Vertex.endShape();
                        Pen.fillStroke;                 //also try fill and stroke
                };
                Pen.use{
                        Pen.translate(310, 110);
                        Vertex.beginShape(\triangleFan);
                        Vertex(Point(57.5, 50));
                        Vertex(Point(57.5, 15));
                        Vertex(Point(92, 50));
                        Vertex(Point(57.5, 85));
                        Vertex(Point(22, 50));
                        Vertex(Point(57.5, 15));
                        Vertex.endShape();
                        Pen.fillStroke;                 //also try fill and stroke
                };
               
                Pen.use{
                        Pen.translate(10, 210);
                        Vertex.beginShape(\quads);
                        Vertex(Point(30, 20));
                        Vertex(Point(30, 75));
                        Vertex(Point(50, 75));
                        Vertex(Point(50, 20));
                        Vertex(Point(65, 20));
                        Vertex(Point(65, 75));
                        Vertex(Point(85, 75));
                        Vertex(Point(85, 20));
                        Vertex.endShape();
                        Pen.fillStroke;                 //also try fill and stroke
                };
                Pen.use{
                        Pen.translate(110, 210);
                        Vertex.beginShape(\quadStrip);
                        Vertex(Point(30, 20));
                        Vertex(Point(30, 75));
                        Vertex(Point(50, 20));
                        Vertex(Point(50, 75));
                        Vertex(Point(65, 20));
                        Vertex(Point(65, 75));
                        Vertex(Point(85, 20));
                        Vertex(Point(85, 75));
                        Vertex.endShape();
                        Pen.fillStroke;                 //also try fill and stroke
                };
                Pen.use{
                        Pen.translate(210, 210);
                        Vertex.beginShape();
                        Vertex(Point(20, 20));
                        Vertex(Point(40, 20));
                        Vertex(Point(40, 40));
                        Vertex(Point(60, 40));
                        Vertex(Point(60, 60));
                        Vertex(Point(20, 60));
                        Vertex.endShape(1);             //also try 0 here
                        Pen.fillStroke;                 //also try fill and stroke
                };
                Pen.use{
                        Pen.translate(310, 210);
                        Vertex.beginShape();
                        14.do{
                                Vertex(Point(85.rand, 85.rand));
                        };
                        Vertex.endShape(1);             //also try 0 here
                        Pen.fillStroke;                 //also try fill and stroke
                };
        };
        win.front;
)
//http://processing.org/reference/bezierVertex_.html
(
        var win= Window("beziervertex test1", Rect(100, 100, 300, 300), false);
        win.drawHook= {
                Pen.fillColor= Color.white;
                Pen.strokeColor= Color.black;
                BezierVertex.beginShape(Point(30, 20));
                BezierVertex(Point(80, 0), Point(80, 75), Point(30, 75));
                BezierVertex.endShape;
                Pen.stroke;                             //also try fillStroke and fill
        };
        win.front;
)

//http://processing.org/reference/bezierVertex_.html
(
        var win= Window("beziervertex test2", Rect(100, 100, 300, 300), false);
        win.drawHook= {
                Pen.fillColor= Color.white;
                Pen.strokeColor= Color.black;
                BezierVertex.beginShape(Point(30, 20));
                BezierVertex(Point(80, 0), Point(80, 75), Point(30, 75));
                BezierVertex(Point(50, 80), Point(60, 25), Point(30, 20));
                BezierVertex.endShape;
                Pen.fillStroke;                 //also try stroke and fill
        };
        win.front;
)

AttachmentSize
Binary Data Vertex.sc1.6 KB
Binary Data BezierVertex.sc342 bytes

k-means

clean-up #24:

i took some code i had for performing k-means clustering and made it into a proper class. i also found Dan Stowell's KMeans quark and borrowed some concepts from that one. my version works slightly different and uses RedVectors of any dimension.
the class is part of my redUniverse quark and the best way to install it is as always... download it with Quarks.checkoutAll; and then install via Quarks.gui; a helpfile and simple examples are included but i hope to write more elaborate demonstrations of this later on.

this is a screenshot from the example in the helpfile. 1000 random points are categorised into 5 groups/clusters. the bigger circles are the 5 mean points/centroids.

also see 190-kmeans.scd for an example running in realtime.

anneVideotracking

clean-up #23:

the screenshot below is of a simple little mac application i made in max/msp/jitter. it takes realtime input from a web or dv-camera, chops it into six regions and tracks activity in each of those regions separately. the result is sent over to supercollider via osc.

the analysis/tracking is just a simple average luminescence per frame. i.e. it takes the mean of all the red, green and blue values in one frame and then calculate the luma with (0.299*red)+(0.587*green)+(0.114*blue). the luma will be close to 0 for dark frames and close to 1 for very bright video frames.

to tune this system to produce maximal output, one should first make sure the camera sits still and has sufficient and stable light. then in the software there are colour, brightness and contrast controls to help get even better readings. (completely inverting all the colours might help in really dark places.)
the luma values (float 0.0-1.0) can be rounded off to nearest number and also smoothed out. this is often necessary to avoid flutter and noise. and most important - there is manual calibration of the luma values - either per region or globally.
to calibrate one should first empty the camera's view of any objects and then press the 'calibrate min' button in the lower left corner. then move some objects around to see what is the maximum reading. last put that number into the 'set max' numberbox. one can also calibrate each region separately with the min and max buttons next to the preview windows.

download the mac osx standalone from here.

and here is supercollider code to read the data and make some simple sounds out of it.

//to start: select all + enter
//to stop: cmd + .
(
n= 6;
s.latency= 0.05;
s.waitForBoot{
        var osc, dlast= 0.dup(n);
        d= {Bus.control(s, 1)}.dup(n);
        e= {Bus.control(s, 1)}.dup(n);
        osc= OSCresponder(nil, \anneVideoTracking, {|t, r, m|
                var index= m[1], val= m[2], diff= (val-dlast[index]).abs;
                //m.postln;
                d[index].set(val);
                e[index].set(diff);
                dlast.put(index, val);
        }).add;
        CmdPeriod.doOnce({osc.remove; d.do{|x| x.free}; e.do{|x| x.free}});
        SynthDef(\annetest, {
                var src= Mix({|i| SinOsc.ar(i*100+400, 0, LagUD.kr(In.kr(e[i].index), 0.01, 0.1))}.dup(n));
                Out.ar(0, Pan2.ar(src));
        }).send(s);
        s.sync;
        Synth(\annetest);
};
)

tweets

clean-up #22:

here are my best-of twitter tweets so far. see twitter.com/redFrik for the rest. with the hard limitation of 140 characters, it is really challenging to write a piece of supercollider code that fits and sounds good _and is interesting to listen to for more than a few seconds.

 

//--tweet0001

r{99.do{|i|x={Pan2.ar(SinOsc.ar(i+1,SinOsc.ar((i%9).div(3)*100+(i%9)+500),0.03),1.0.rand2)}.play;2.wait;x.release(25)}}.play//#SuperCollider

99 sine oscillators played one after the other with a two seconds interval. each oscillator lasts for 27 seconds. so the total duration is 99*2+27= 225 seconds. the oscillators are phase modulated with other sine oscillators with frequencies repeating in the number series: 500, 501, 502, 603, 604, 605, 706, 707, 708. the base frequencies of the 99 carrier oscillators slowly raise by one hertz from 1 to 99. the only random thing is the stereo panning position for each oscillator.

 

//--tweet0006

r{loop{x={GVerb.ar(MoogFF.ar(ClipNoise.ar*0.4,LFPar.kr({0.3.rand}!2,0,600,990)),9,9,1)}.play(s,0,19);3.wait;x.release}}.play//#SuperCollider

a clip noise generator runs through a moog filter and then a reverb. every third second there is a new noise added and each noise lasts for 22 seconds. each moog filter has two unique parabolic lfos that runs at a random rate between 0 and 0.3 hertz - each in one channel. at the most there are 8 number of overlapping noises playing at the same time. as there are so many reverbs playing here at once one needs to allocate more memory to sc server. something like this... Server.local.options.memSize= 32768; and then reboot the localhost server.

 

//--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

this one is completely deterministic although it is hard to believe when hearing it. a lot of nested feedbacking sine oscillators. nine parallel oscillators are mixed down to 1 and duplicated in left and right channels. each of the nine oscillators is frequency and feedback modulated but have a static amplitude of 1/9. the frequency modulator consist of yet more modulated feedbacking sine oscillators, while the feedback of the outer is only modulated with a single feedbacking sine oscillator running at 0.1 hertz. all in all there are 109 unit generators in total running in this tweet and it peaks at about 9.3% of my computer's cpu.

 

//--tweet0016 - tweet0019
these four all work the same way. they only differ in buffer size and what kind of oscillator is used for reading back samples from the buffer. there is not much progress over longer time but they do have characted and subtle though deterministic variation in the details.

 

play{b=LocalBuf(9e4,2).clear;i=Sweep.ar(BufRd.ar(2,b,Saw.ar(12,3e4,4e4)),9e4);BufWr.ar(Saw.ar([8,9]),b,i);BufRd.ar(2,b,i)/2}//#SuperCollider


 

play{b=LocalBuf(8e4,2).clear;i=Sweep.ar(BufRd.ar(2,b,Saw.ar(3.1,4e4,4e4)),8e4);BufWr.ar(Blip.ar([2,3]),b,i);BufRd.ar(2,b,i)}//#SuperCollider


 

play{b=LocalBuf(5e3,2).clear;i=Sweep.ar(BufRd.ar(2,b,Saw.ar(50,2e3,5e3)),6e4);BufWr.ar(Saw.ar([4,3]),b,i);BufRd.ar(2,b,i)/6}//#SuperCollider


 

play{b=LocalBuf(1e4,2).clear;i=Sweep.ar(BufRd.ar(2,b,Saw.ar(1,2e3,5e3)),5e5);BufWr.ar(Saw.ar([8,50]),b,i);BufRd.ar(2,b,i)/3}//#SuperCollider


 

//--tweet0020

play{a=LFPulse;b=(1..4);Mix(a.ar(a.ar(a.ar(a.ar(b/32)+1/8)+1*b)+(Mix(a.ar(b/64))+a.ar(4/b)*(a.ar(a.ar(b/8))*2+b))*100))/8!2}//#SuperCollider

this tweet is also totally deterministic and without any randomness. here a lot of nested square wave oscillators creates the complexity. basically there are 4 channels/voices mixed down to one and then duplicated in left and right channel. there are three levels deep nesting of frequency modulation with another set of square waves mixed and added.

 

//--tweet0021

r{{|j|a=play{sin(Decay.ar(Duty.ar(1/50,0,Dseq(flat({|i|asBinaryDigits(j+1*i)}!8),4),2),j+1*0.008))/2!2};5.12.wait}!256}.play//#SuperCollider

binary numbers from 0 to 255 form the rhythmic patterns in this tweet. each number first repeats 8 times - each time all the bits are shifted one position to the left. that creates an array of 64 ones and zeros. this array is then repeated four times. this is what makes it sound like a 4 x 4/4 bar theme (i.e. 4 bars per number). the total 64*4*256 binary digits are played in sequence and each digit lasts for 1/50th of a second. the total duration becomes 64*4*256/50= 1310.72 seconds. the sound is generated by the ones and the zeros directly. there is an exponential decay for these flipflop pulses that slowly increases throughout the 256 numbers. it starts with a decay time of 0.008 seconds and ends with 2.04 seconds. in the mp3 below only the numbers 0-31 are played.

 

//--tweet0024

{|j|r{{|i|x=sin(i/5+(j*5));Ndef(i%5+(j*5),{Pan2.ar(LFCub.ar(j*2+x*40+400+i)/15,i%5/2-1)}).play;wait(x.abs+0.5)}!500}.play}!5//#SuperCollider

another tweet without any randomness. there are five paralles routines and all do something 500 times. what they do is to define or redefine a node proxy. there are 25 proxies in total and each one contains a sine shaped oscillator panned to one out of four positions in the stereo field. the frequencies are climbing upwards in a slightly jaggered curve. the exact length is a bit complicated to calculate but it is around 575 seconds. in the end the proxies do not stop to play but just keeps the last assigned frequency and the whole soundscape becomes static.

klee

clean-up #21:

attached is a klee step-sequencer as a supercollider list-pattern class. the included helpfile should explain how it works.

there are a couple of ways to make a klee sequencer on the server side as well. in the below examples i used argument lists, but one can also do it using buffers together with the index ugen.

(
SynthDef(\klee8, {|freq= 400, rate= 0.5,
                list= #[0, 0, 0, 0, 0, 0, 0, 0],
                mul= #[0, 0, 0, 0, 0, 0, 0, 0]|
        var i= LFSaw.kr(rate, 1, 0.5, 0.5)*list.size;
        var sum= (mul*Select.kr(i+(0..list.size-1)%list.size, list)).sum;
        var src= SinOsc.ar(freq+sum, 0, Decay2.kr(Impulse.kr(list.size*rate), 0.01, 0.1, 0.5));
        Out.ar(0, Pan2.ar(Mix(src)));
}).add;
)
a= Synth(\klee8)
a.set(\list, #[4, 0, 0, 2, 0, 0, 0, 0]*100)     //set the values
a.set(\mul, #[1, 0, 0, 0, 0, 0, 0, 0])          //activate 1 read head
a.set(\mul, #[1, 1, 0, 0, 0, 0, 0, 0])          //activate 2 read heads
a.set(\mul, #[1, 1, 1, 0, 0, 0, 0, 0])
a.set(\mul, #[1, 1, 1, 1, 0, 0, 0, 0])

a.set(\mul, #[1, 0.5, 0.25, 0, 0, 0, 0, 0])
a.set(\list, #[4, 0, -4, 2, 0, 0, 0, 0]*100)
a.set(\freq, 500)
a.set(\rate, 1.5)
a.free

and similar but with 16 steps. it is only to change the number of zeros in list and mul arguments.

(
SynthDef(\klee16, {|freq= 400, rate= 0.5,
                list= #[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                mul= #[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
        var i= LFSaw.kr(rate, 1, 0.5, 0.5)*list.size;
        var sum= (mul*Select.kr(i+(0..list.size-1)%list.size, list)).sum;
        var src= SinOsc.ar(freq+sum, 0, Decay2.kr(Impulse.kr(list.size*rate), 0.01, 0.1, 0.5));
        Out.ar(0, Pan2.ar(Mix(src)));
}).add;
)
a= Synth(\klee16)
a.set(\list, #[4, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 2, 0, 0, 0, 0]*100)     //set the values
a.set(\mul, #[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])          //activate 1 read head
a.set(\mul, #[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])          //activate 2 read heads
a.set(\mul, #[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0.25, 0, 0, 0, 0, 0])
a.set(\list, #[4, 0, -4, 2, 0, 0, 0, 0, 3, 0, -3, 2, 0, 0, 0, 0]*100)
a.set(\freq, 500)
a.set(\rate, 1.5)
a.free
AttachmentSize
Package icon Pklee.zip3 KB

2 max ports

clean-up #20:

here are two supercollider documents made years ago to resemble two max/msp patches by katsuhiro chiba. his patches are really wonderfully constructed with playful and nice gui design plus they sounded good to me. so i was curious how he made them and to learn more i ported parts of his code to sc. the max4 patches are still available here along with some screenshots.
all credit for the attached code should go to mr chiba.

 


 


AttachmentSize
File autumn.rtf8.93 KB
File sev.rtf4.27 KB

alarm

clean-up #19:

there was a sleeping-bag concert as part of the sound of stockholm festival this year. music for sleeping - what a great concept!
first i was assigned to play last and would thereby have had the honour/responsibility of waking everybody up for breakfast at 7:00 in the morning. both fun and daunting. how to let your audience sleep in as long as possible and then wake them up gently but firmly?
i assumed most people would be asleep when it was my turn and that i myself also would be very tired. so i prepared my solo set (using redThermoKontroll) to be extremely simple and static in nature. hardly no variation - only a couple of sounds sources (4 sc patches i think it was) with looong transitions between settings that i could control manually.
then there was the waking up part and for that i wrote the very simple sounding code below. it starts slowly with one little alarm going off. then a second alarm, then more and more until complete chaos. i made it so that this patch could be mixed in with my drones and with separate control over volume.
unfortunately when i got to stockholm they had changed the playing order and i did do my performance around midnight instead. and i never set the alarms off.

//--set alarms
(
~num= 25;                       //number of alarms
~fadeTime= 10;          //fade in time in seconds
~num.do{|i|
        Ndef(("alarm"++i).asSymbol, {|amp= 0, lag= 5|
                var src= Pulse.ar(
                        ExpRand(300, 3000)+LFPulse.kr(ExpRand(3, 30), 0, Rand(0.4, 0.6), Rand(-100, 100)),
                        Rand(0.4, 0.6),
                        LFPulse.kr(LinRand(0.05, 2), 0, LinRand(0.1, 0.5), 0.5)
                );
                Pan2.ar(src, Rand(-0.95, 0.95), amp.lag(lag));
        });
};
Ndef.all;               //list them
)

//--start alarms
(
~task.stop;
~task= Task({
        ~num.do{|i|
                Ndef(("alarm"++i).asSymbol).play(fadeTime: ~fadeTime).set(\amp, 7/~num).postln;
                i.linlin(0, ~num-1, ~fadeTime*2, ~fadeTime/2).wait;
        };
}).play;
)

//--stop alarms
(
~task.stop;
~task= Task({
        ~num.do{|i|
                Ndef(("alarm"++i).asSymbol).stop(fadeTime: 1/~fadeTime);
                i.linlin(0, ~num-1, 1/~fadeTime, 10/~fadeTime).wait;
        };
}).play;
)

 


growing more sounds

clean-up #18:

i found more code i never published. again it is about generating synthdefs using genetic algorithms. see here and here for previous stories.
and to run the attached files you will need to install my RedGA library from this page.

first is a little exploration tool called growing_sounds10. it makes a single synthdef from the settings of a multi slider. draw something and press space to generate and play the synthdef. if you like what you hear you can copy the code from the post window and refine it manually.
also try the preset functions. they will either generate, modify or set a fixed setting/drawing in the multislider.

the synthdef generated in the screenshot above was this one...

{LFPar.ar(LFTri.kr(LFDNoise3.kr(0.836588, 0.257632, 0.772292).exprange(3.7376802825928, 15.120258769989)).exprange(11935.654205322, 5408.6393985748)).range(0.31427707672119, -0.23100700378418)}.play

another file is called growing_soundsBreed and it gives you control over 6 parent genomes that can be transformed into synthdefs and listened to by clicking the play buttons. mark good sounding parents and breed a new generation. the genomes should now have been mixed and mutated and there are 6 new children as a result of the operation. it is likely that they sound similar to their parents and the longer you repeat the process, the more similar the genomes and in turn the synthdefs (phenomes) will be.

yet another piece of code is growing_soundsBreedFitness and it works the same way as the previous except that you here give a rating i.e. a fitness to each parent. (blue sliders = fitness amount). so instead of marking which parents you give ratings. the system will use these ratings as a guideline of importance when choosing which parents' genes to use for the new generation.

and last is a file called growing_soundsBreedPattern in which you can not only breed synthdefs but also the amplitude pattern they play in a simple sequencer.

as always, all code published under gnu gpl v2 license.

Pages

Subscribe to f0blog RSS