RedBMP
Submitted by f0 on Mon, 2010-11-22 03:36clean-up #7:
today i cleaned up and finished a class belonging to my redSys quark. the class can read and write bitmap images (.bmp files). to get it run the following command in supercollider...
and then install redSys via the gui...
it's a fairly slow and useless class but well, it can generate images relatively fast. and saving to disk is also quite quick. but avoid drawing the images to screen. the built in makeWindow method is very slow as it goes through width*height number of pixels and draws a rectangle for each using Pen.
b= RedBMP(640, 480, 32);
b.data= {|i|
var x= i%b.width;
Color.red(sin(x/b.width*2pi+sin(x*0.11)), sin(i*0.01+sin(x*0.1)).abs);
}.dup(b.width*b.height);
b.write("~/Desktop/redbmp.bmp");
)
this code outputs the following file (notice the alpha channel)...
1.2mb windows v3 bmp, 640x480, 72dpi

a script that rules the world
Submitted by f0 on Sun, 2010-11-21 01:26clean-up #6:
this is a hack from 2007. it was done in cocoacollider, but now i updated it using the standard SCNSObject in supercollider. it works by talking to google earth via applescript.
//req. mac osx, google earth
//--init
(
s.waitForBoot{
SynthDef(\redGoogleKick, {|out= 0, t_trig= 1, freq= 50, dur= 0.5, envFreq= 500, envAtk= 0.005, envRel= 0.1, amp= 1|
var z, env, fenv, click;
env= EnvGen.ar(Env.linen(0, 0, dur, amp), t_trig);
fenv= EnvGen.kr(Env([envFreq, envFreq-freq*0.275+freq, freq], [envAtk, envRel]), t_trig);
click= EnvGen.ar(Env.linen(0, 0, 0), t_trig);
z= SinOsc.ar(fenv, 0, env, click);
Out.ar(out, z);
}).add;
SynthDef(\redGoogleSynth, {|out= 0, t_trig= 1, freq= 200, atk= 0.005, dec= 0.5, pm= 0.5, amp= 1|
var z, env, pmod;
env= EnvGen.kr(Env.perc(atk, dec, 1, -3), t_trig);
pmod= LFSaw.ar(freq*2.pow(TIRand.kr(1, 3, t_trig)), 0, env*pm);
z= SinOsc.ar(freq, pmod, env);
Out.ar(out, z*amp);
}).add;
SynthDef(\redGoogleDelay, {|in= 0, out= 0, depth= 3, time= 0.45, amp= 1, dist= 2, pan= 0|
var src, z;
src= In.ar(in, 1);
z= CombL.ar(src, 1.5, time.min(1.5), depth, amp, src);
Out.ar(out, Pan2.ar(Clip.ar(z*dist, -1, 1), pan));
}, #[\ir, \ir, 0, 0.5, 0, 0, 0]).add;
};
f= {|cmd|
{
var o;
o= SCNSObject("NSAppleScript", "initWithSource:", ["tell application \"Google Earth\"\n"++cmd++"\nend tell"]);
o.invoke("executeAndReturnError:", [nil], true);
o.release;
}.defer;
};
f.value("open");
)
//--run (wait until localhost and googlearth started, also disable all overlays in googleearth)
(
f.value("SetViewInfo{latitude:0, longitude:0, distance:10000000, tilt:0, azimuth:0} speed 5");
d= Synth(\redGoogleDelay, [\out, 0, \in, 32]);
k= Synth(\redGoogleKick, [\t_trig, 0]);
e= Synth(\redGoogleSynth, [\out, 32, \t_trig, 0]);
Tdef(\redGoogle).play;
Tdef(\redGoogle, {
var dist, xxx= 0, yyy= 0;
300.do{|i|
if(i%25==0, {
if(i%100==0, {
k.set(\t_trig, 1, \amp, 0.1, \out, 32, \freq, 2000, \dur, 1.5, \envAtk, 0.005, \envRel, 0.2);
});
e.set(\t_trig, 1, \freq, [500, 600, 700].wrapAt(i), \amp, 0.5, \dec, 0.5, \pm, 0.2);
if(i%4==0, {
xxx= xxx+1.0.rand2;
yyy= yyy+20.rand2;
f.value("SetViewInfo{latitude:"++1.0.rand2++", longitude:"++yyy++", distance:10000000, tilt:0, azimuth:0} speed 0.4");
});
});
(1/25).wait;
};
f.value("SetViewInfo{latitude:0, longitude:0, distance:10000000, tilt:0, azimuth:0} speed 0.5");
300.do{|i|
if(i%25==0, {
dist= [400, 600, 700, 800].wrapAt(i);
k.set(\t_trig, 1, \amp, 1, \out, 32, \freq, 50, \dur, 0.5, \envAtk, 0.005, \envRel, 0.1);
e.set(\t_trig, 1, \freq, dist, \amp, 0.5, \dec, 0.5, \pm, 1-(i/300));
f.value("SetViewInfo{latitude:0, longitude:0, distance:"++8000000++", tilt:"++45.rand++", azimuth:0} speed 5");
}, {
if(i%25==1, {
f.value("SetViewInfo{latitude:0, longitude:"++([100, -100].choose)++", distance:"++5000000++", tilt:0, azimuth:10} speed 0.5");
});
});
(1/25).wait;
};
d.set(\dist, 4);
f.value("SetViewInfo{latitude:52.45, longitude:-1.93, distance:300, tilt:0, azimuth:0} speed 0.5");
50.do{|i|
if(i%25==0, {
k.set(\t_trig, 1, \amp, 1, \out, 32, \freq, 50, \dur, 0.5, \envAtk, 0.005, \envRel, 0.1);
e.set(\t_trig, 1, \freq, [100, 500, 600, 700].wrapAt(i), \amp, 0.5, \dec, 1.1, \pm, 2);
});
(1/25).wait;
};
d.set(\dist, 5);
500.do{|i|
if(i%25==0, {
k.set(\t_trig, 1, \amp, 1, \out, 32, \freq, 50, \dur, 0.5, \envAtk, 0.005, \envRel, 0.1);
e.set(\t_trig, 1, \freq, [200, 500, 600, 700].wrapAt(i), \amp, 0.5, \dec, 1.1, \pm, 2);
f.value("SetViewInfo{latitude:52.45, longitude:-1.93, distance:"++200.rrand(300)++", tilt:"++(i%45)++", azimuth:"++(i%180)++"} speed 1");
}, {
if(i%20==18, {
k.set(\t_trig, 1, \amp, 0.3, \out, [0, 1].choose, \freq, [2100, 100].wrapAt(i), \dur, 0.9, \envAtk, 0.1.linrand, \envRel, i%3);
})
});
(1/25).wait;
};
})
)
f.value("quit");
/*
SCNSObject.dumpPool;
SCNSObject.freePool;
*/
//--some notes:
there are two ways to run applescripts from within supercollider. one is to construct a string with osascript -e and a unixCmd, the other is creating a cocoa NSAppleScript object with the SCNSObject cocoa binding class. the later method is slightly more involved but runs way faster.
the following two examples do the same thing - switches to Finder.
"osascript -e 'tell application \"Finder\" to activate'".unixCmd
a= SCNSObject("NSAppleScript", "initWithSource:", ["tell application \"Finder\" to activate"]);
a.invoke("executeAndReturnError:", [nil], true);
a.release;
SCNSObject.dumpPool; //should be 0
SCNSObject.freePool; //free stray objects if any left
also i've attached a simple class that wraps the functionality. it's called RedEarth.
eco
Submitted by f0 on Fri, 2010-11-19 23:15clean-up #5:
an ecosystem as described in Gary William Flake's book - "The Computational Beauty of Nature" (page 191). i started coding it 1,5 years ago but never finished it until today.
white = empty space
green = plant
red = herbivore
blue = carnivore.
* For every time step:
* For every empty cell, e:
* If e has three or more neighbors that are plants, then e will become a plant at the next time step (assuming it isn't trampled by a herbivore or carnivore).
* For every herbivore, h (in random order):
* Decrease energy reserves of h by a fixed amount.
* If h has no more energy, then h dies and becomes an empty space.
* Else, if there is a plant next to h, then h moves on top of the plant, eats it, and gains the plant's energy.
* If h has sufficient energy reserves, then it will spawn a baby herbivore on the space that it just exited.
* Else, h will move into a randomly selected empty space, if one exists, that is next to h's current location.
* For every carnivore, c (in random order):
* Decrease energy reserves of c by a fixed amount.
* If c has no more energy, then c dies and becomes an empty space.
* Else, if there is a herbivore next to c, then c moves on top of the herbivore, eats it, and gains the herbivore's energy.
* If c has sufficient energy reserves, then it will spawn a baby carnivore on the space that it just exited.
* Else, c will move into a randomly selected empty space that is next to c's current location. If there are no empty spaces, then c will move through plants.
the rules are fairly simple but the result is complex. carnivores feed on herbivores that in turn feed on plants. populations grow, get overpopulated and die out just like in nature. the sc code is a bit cryptic using a lot nested arrays for efficiency reasons but near the top there are user settings to play with.
here's also a version for processing...
eco
and a mac osx application written in cinder...
eco.app.zip (228k)
ecoApp.cpp (12k)
whitney balls
Submitted by f0 on Fri, 2010-11-19 00:31clean-up #4:
this is something i originally wrote for the article Audiovisuals with SC and now rewrote as separate classes. there are three classes all implementing the same system slightly differently. one for graphics (Whitney) and the other two for patterns (Pwhitney, Pwhitney2).
the principle for this system is described by John Whitney in his book Digital Harmony (1980). the idea is simple but complex patterns arise - both in graphics and in harmony/rhythm. the innermost ball moves at a certain speed, the ball next to it doubles that speed and the ball next to that triples the speed etc. there's a sound played for each ball as it passes through 0. each ball's sound plays at a different frequency mapped to some scale, overtone series or something else.
the code for the above video example is taken from the helpfile...
s.latency= 0.05;
s.waitForBoot{
var width= 500, height= 500;
var w= Window("Whitney balls", Rect(99, 99, width, height), false);
var u= UserView(w, Rect(0, 0, width, height));
SynthDef(\sin, {|freq= 400, amp= 0.2, pan= 0, rel= 0.9|
var e= EnvGen.ar(Env.perc(0.005, rel), 1, doneAction:2);
var z= SinOsc.ar(freq, e*pi, e);
Out.ar(0, Pan2.ar(z, pan, amp));
}).send(s);
s.sync;
//--set up the whitney system
f= Whitney(20, {|ball, i|
Synth(\sin, [\freq, (64+i).midicps, \amp, 2/f.num]);
Pen.fillOval(Rect.aboutPoint(Point(ball.x, ball.y), 5, 5));
});
u.drawFunc= {
Pen.rotate(2pi*0.75, width*0.5, height*0.5);
Pen.translate(width*0.5, height*0.5);
Pen.strokeColor= Color.red;
Pen.line(Point(0, 0), Point(0, width*0.5));
Pen.stroke;
Pen.color= Color.grey(1, 0.7);
f.next; //update the system
f.balls.do{|b, i| //draw the balls
Pen.strokeOval(Rect.aboutPoint(Point(b.x, b.y), 4, 4));
};
};
CmdPeriod.doOnce({if(w.isClosed.not, {w.close})});
u.background= Color.black;
w.front;
u.animate= true; //replace this line with the one below if you use swingosc
//Routine({while({w.isClosed.not}, {u.refresh; (1/60).wait})}).play(AppClock);
};
)
f.speed= 0.02 //change speed
f.speed= 0.002
f.theta= 0 //restart
f.spread= 15 //change distance between balls
f.spread= 5
(
f.func= {|ball, i|
Synth(\sin, [
\freq, i.linexp(0, f.num-1, 300, 3000),
\amp, i.linlin(0, f.num-1, 0.1, 0.05),
\rel, i.linlin(0, f.num-1, 1, 0.2),
\pan, 0.4.rand2
]);
Pen.fillOval(Rect.aboutPoint(Point(ball.x, ball.y), 5, 5));
}
)
f.num= 10
f.num= 30
f.num= 55
f.speed= 0.01
f.speed= 0.0002
f.speed= 0.001
f.speed= 0.005
(
f.func= {|ball, i|
Synth(\sin, [
\freq, (i.degreeToKey(Scale.indian)+48).midicps,
\amp, i.linlin(0, f.num-1, 0.1, 0.05),
\rel, i.linlin(0, f.num-1, 2, 0.2),
\pan, 0.4.rand2
]);
Pen.fillOval(Rect.aboutPoint(Point(ball.x, ball.y), 6, 6));
};
f.num= 36;
f.theta= 0;
f.spread= 6;
f.speed= 0.001;
)
rot
Submitted by f0 on Wed, 2010-11-17 23:55clean-up #3:
beat rotation as described here...
http://music.columbia.edu/~douglas/strange_things/?p=78
implemented as a method for SequenceableCollection. some test code...
(
SynthDef(\segMono, {|out= 0, buffer, amp= 0.5, rate= 1, offset= 0, atk= 0.01, rel= 0.1, gate= 1|
var env= EnvGen.ar(Env.asr(atk, amp, rel), gate, doneAction:2);
var src= PlayBuf.ar(1, buffer, rate*BufRateScale.ir(buffer), 1, offset*BufFrames.ir(buffer));
OffsetOut.ar(out, Pan2.ar(src*env));
}).add;
SynthDef(\segStereo, {|out= 0, buffer, amp= 0.5, rate= 1, offset= 0, atk= 0.01, rel= 0.1, gate= 1|
var env= EnvGen.ar(Env.asr(atk, amp, rel), gate, doneAction:2);
var src= PlayBuf.ar(2, buffer, rate*BufRateScale.ir(buffer), 1, offset*BufFrames.ir(buffer));
OffsetOut.ar(out, src*env);
}).add;
)
b= Buffer.read(s, "sounds/amen.wav")
b.numChannels //use instrument \segStereo for 2 channel files and instrument \segMono for 1 channel files
60/(b.duration/16) //calculate tempo in bpm. 16 is the number of beats in the file
c= TempoClock(1/(b.duration/16)); //create a tempo clock in the tempo of the file
Pdef(\test).play(c, quant:1)
( //rot example 1 - shuffle
Pdef(\test, Pbind(
\instrument, \segStereo,
\buffer, b,
\dur, 1,
\amp, 0.75,
\offset, Pseq((0..15).rot(2, 1, 0, 4)/16, inf)
))
)
( //rot example 2 - double tempo
Pdef(\test, Pbind(
\instrument, \segStereo,
\buffer, b,
\dur, 0.5,
\amp, 0.75,
\offset, Pseq((0..15).rot(2, 1, 1, 4)/16, inf)
))
)
( //rot example 3 - double and triple tempo
Pdef(\test, Pbind(
\instrument, \segStereo,
\buffer, b,
\dur, Pseq([0.5, 0.25, 0.25], inf),
\amp, 0.75,
\offset, Pseq((0..15).rot(0, 1, 1, 8)/16, inf)
))
)
( //rot example 4 - subdivide into 32 segments
Pdef(\test, Pbind(
\instrument, \segStereo,
\buffer, b,
\dur, Pseq([0.5, 0.25, 0.25], inf),
\amp, 0.75,
\offset, Pseq((0..31).rot(1, 1, 1, 4)/32, inf)
))
)
( //rot example 5 - back to original
Pdef(\test, Pbind(
\instrument, \segStereo,
\buffer, b,
\dur, 1,
\amp, 0.75,
\offset, Pseq((0..15).rot(0, 0, 0, 4)/16, inf)
))
)
Pdef(\test).stop
b.free;
in the mp3 recording of the above code, each rotation example gets to play for 16 beats.
0:35 minutes (812.64 KB)
pfork
Submitted by f0 on Wed, 2010-11-17 00:21clean-up #2:
another very old supercollider class i never got around to publish. it's called Pfork and makes it possible to blend or fade out patterns in other ways than plain [volume] crossfading. It was originally written for the installation Intelligent Street (in SC2) where it was used as a way of creating new music styles from a mix of multiple other styles.
here's one example of slowly zeroing out amplitudes in a 16 step pattern. frac is a value slowly changing from 1.0 to 0.0 and indicates how many values to zero out. the fork pattern is [3, 1, 2, 0]. this pattern decides which indexes to zero out and in which order. so here index 3 is first in the fork pattern and will thereby be seen as the least important in the original pattern. all indexes 3 will be zeroed out first. after that all indexes 1 and so on. the last indexes zeroed out (ie kept until frac is almost 0.0) are the indexes 0 - ie the first beat out of 4 in the original amplitude step pattern.
this ascii printout should help visualise what is happening...
1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1
1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0
1 0 1 0 1 1 1 0 1 1 1 0 1 1 1 0
1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 //frac is 0.5
1 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0
1 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0
1 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0
1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 //frac is 0.0
one can also imagine 1 or 0 to be other things than amplitude and basically any array can fork into any other.
here's an example going slowly from one melodic pattern into another. (mp3 recording below)
(
a= 0.2.dup(16); //amplitudes
f= [0, 2, 1, 3]; //forkpattern for left channel
g= [3, 1, 2, 0]; //forkpattern for right channel
Pbind(\pan, -1, \dur, 0.125, \degree, Pseq([5, 6, 7, 8], inf), \amp, Pfork(a, f, Pseries(1, -0.1, 11), 0, 11)).play;
Pbind(\pan, 1, \dur, 0.125, \degree, Pseq([3, 2, 1, 0], inf), \amp, Pfork(a, g, Pseries(0, 0.1, 11), 0, 11)).play;
)
see the helpfile for more examples.
i plan to (someday) write a Pfunc2 class that work in a similar way but inherits from FilterPattern instead of ListPattern.
0:23 minutes (537.13 KB)
bjorklund
Submitted by f0 on Tue, 2010-11-16 02:05clean-up #1:
two supercollider classes i wrote long ago (nov 2008) after a technique described by Godfried Toussaint in his paper 'The Euclidean Algorithm Generates Traditional Musical Rhythms' http://www-cgrl.cs.mcgill.ca/~godfried/publications/banff.pdf
also see http://ruinwesen.com/blog?id=216 for another implementation with some great demos. and Bjorn Westergard has a sc demo here.
lots of typical patterns in say techno music can be described like this using only two numbers (relation).
below is some example supercollider code with resulting output as mp3. the hihat plays a 9/16 rhythm throughout and the snare plays 3 different ones... 5/8, 15/16 and 3/8.
a= Buffer.read(s, "sounds/Free_CR68/CR68_BD_B_03.wav")
b= Buffer.read(s, "sounds/Free_CR68/CR68_SD_B1.wav")
c= Buffer.read(s, "sounds/Free_CR68/CR68_hh_02.wav")
(
SynthDef(\oneshotMono, {|out= 0, amp= 0.1, pan= 0, rate= 1, buffer|
var src= PlayBuf.ar(1, buffer, rate*BufRateScale.ir(buffer), doneAction:2);
Out.ar(out, Pan2.ar(src, pan, amp));
}).add;
)
d= TempoClock(120/60)
Pdef(\bd).play(d, quant:4)
Pdef(\hh).play(d, quant:4)
Pdef(\sd).play(d, quant:4)
Pdef(\bd, Pbind(\instrument, \oneshotMono, \buffer, a, \dur, 1.00, \amp, 0.7))
Pdef(\hh, Pbind(\instrument, \oneshotMono, \buffer, c, \dur, 0.25, \amp, Pbjorklund(9, 16, inf)*0.7, \pan, Pbrown(-1, 1, 0.2, inf)))
Pdef(\sd, Pbind(\instrument, \oneshotMono, \buffer, b, \dur, 0.25, \amp, Pbjorklund(5, 8, inf)*0.3))
Pdef(\sd, Pbind(\instrument, \oneshotMono, \buffer, b, \dur, 0.25, \amp, Pbjorklund(15, 16, inf)*0.3))
Pdef(\sd, Pbind(\instrument, \oneshotMono, \buffer, b, \dur, 0.25, \amp, Pbjorklund(3, 8, inf)*0.3))
Pdef(\bd).stop
Pdef(\sd).stop
Pdef(\hh).stop
update 110316: adapted Pbjorklund to also take patterns as arguments.
update 110320: made a quark out of it
Bjorklund is now available as a supercollider quark. install it via the following commands...
Quarks.gui;
//check Bjorklund, click save and recompile
or download and install it manually from here
0:18 minutes (430.47 KB)
redThermoKontroll
Submitted by f0 on Wed, 2010-07-21 16:40my latest controller. i'll premiere it this friday (23july, 2010) at the bring-your-own-laptop event at staalplaat. it inlcludes a light sensor, 2 touch sensors, some big switches and lots of knobs for control. it is also wireless and runs off either a 9v battery or a 9-14v wall adapter. the controller data is picked up by redWirelessMaster and is then read by the computer via a serial port.
firmware, partslist and schematics attached below. a supercollider class for interpreting the data is also included. (101109: minor updates)

photostream from the build process. i took out most of this beautiful old electronics and replaced it with my own circuit board. only kept the front end interface with the nice knobs.
update 130122: supercollider gui class updated and new helpfiles and midi control (via a nanoKontroll).