Wind Chimes

posted by on 2013.06.23, under Supercollider
23:

It has been a while, but I have been busy with a new work to be released in July, and recently I have spent some time fiddleing with Reaktor, which I have to say is quite good fun.
So, here’s something very simple and a classic in generative music, i.e. a wind chimes generator. I have decided to use only one graph synth in Supercollider (everything happens at “server side”), using a geiger generator (Dust) with varying density as a master clock, and a Demand Ugen as pitch selector. There is also a bit of FM synthesis, which is a nice way to get “tubular” type of sounds in this case. Finally, some delay and reverb.

s.boot;
{
    var pitch,env,density,scale,root,sig,mod,trig,pan,volenv;
    volenv=EnvGen.kr(Env.linen(10,80,20),1,doneAction:2);
    density=LFTri.kr(0.01).range(0.01,2.5);
    trig=Dust.kr(density);
    root=Demand.kr(trig,0,Drand([72,60,48,36],inf));
    pan=TRand.kr(-0.4,0.4,trig);
    scale=root+[0,2,4,5,7,9,11,12];
    pitch=Demand.kr(trig,0,Drand(scale,inf));
    env=EnvGen.kr(Env.perc(0.001,0.3),trig);
    mod=SinOsc.ar(pitch.midicps*4,0,800)*env;
    sig=SinOsc.ar(pitch.midicps+mod,0,0.2);
    FreeVerb.ar(CombL.ar(Pan2.ar(sig*env,pan),5,0.2,5))*volenv;
}.play;
s.quit;

Here’s how it sounds

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

Flares

posted by on 2013.06.05, under Processing, Supercollider
05:

I am not usually excited about the sketches I make in Processing: I mean, I do like them, but I always think they could have come out better, somehow.
This one, instead, I really like, and I’m quite happy about. It is the outcome of playing with an amazing particle systems library for Processing, called toxiclibs.
The whole idea is particularly simple: take a huge number of points, and connect them with springs with a short rest length, so to form a circular shape. Moreover, add an attraction towards the center, and start the animation with the particles far from the center. They’ll start bouncing under elastic forces and the attraction to the center until the circular shape becomes relatively small. The interesting choice here, from the visual perspective, was not to “represent” (or draw) the particles, but rather the springs themselves. One of the important feature of the animation, in this case, is to be able to slowly clean the screen from what has been drawn on it, otherwise you’ll end up with a huge white blob (not that pleasant, is it?). This is accomplished by the function fadescr, which goes pixel by pixel and slowly turns it to the value 0 in all of its colour channels, so basically fading the screen to black: all the >> and << binary operations are there to speed up things, which is crucial in these cases. Why not using the celebrated "rectangle over the screen with low alpha"? Because it produces "ghosts", or graphic artifacts. See here for a nice description.
I really like the type of textures the animation develops, it gives me the idea of smooth silk, smoke or… flares. 😉

import toxi.physics2d.*;
import toxi.physics2d.behaviors.*;
import toxi.geom.*;

VerletPhysics2D physics;
int N=2000;
VerletParticle2D[] particles=new VerletParticle2D[N];
VerletParticle2D center;
float r=200;



void setup(){
size(600,600);
background(0);
frameRate(30);
physics=new VerletPhysics2D();
center=new VerletParticle2D(new Vec2D(width/2,height/2));
center.lock();
AttractionBehavior behavior = new AttractionBehavior(center, 800, 0.01);
physics.addBehavior(behavior);

beginShape();
  noFill();
  stroke(255,5);
for (int i=0;i<particles.length;i++){
particles[i]=new VerletParticle2D(new Vec2D(width/2+(r+random(10,30))*cos(radians(i*360/N)),height/2+(r+random(10,30))*sin(radians(i*360/N))));
 vertex(particles[i].x,particles[i].y);
 }
 endShape();
 
 for (int i=0;i<particles.length;i++){
 physics.addParticle(particles[i]);
 };
 for (int i=1;i<particles.length;i++){
 VerletSpring2D spring=new VerletSpring2D(particles[i],particles[i-1],10,0.01);
 physics.addSpring(spring);
 };
 
  VerletSpring2D spring=new VerletSpring2D(particles[0],particles[N-1],20,0.01);
 physics.addSpring(spring);


};

void draw(){
  physics.update();

  beginShape();
  noFill();
  stroke(255,10);
 
 
for (int i=0;i<particles.length;i++){
 vertex(particles[i].x,particles[i].y);
 }
 endShape();

 if (frameCount % 3 == 0)
 {
 fadescr(0,0,0);
};

};

void fadescr(int r, int g, int b) {
  int red, green, blue;
  loadPixels();
  for (int i = 0; i < pixels.length; i++) {
    red = (pixels[i] >> 16) & 0x000000ff;
    green = (pixels[i] >> 8) & 0x000000ff;
    blue = pixels[i] & 0x000000ff;
    pixels[i] = (((red+((r-red)>>8)) << 16) | ((green+((g-green)>>8)) << 8) | (blue+((b-blue)>>8)));
  }
 updatePixels();
}

Here’s a render of the animation

The audio has been generated in SuperCollider, using the following code

s.boot;

~b=Bus.audio(s,2);

File.openDialog("",{|path|
    ~path=path;
    ~buff=Buffer.read(s,path);
})



20.do({
    ~x=~x.add(Buffer.read(s,~path,rrand(0,~buff.numFrames)));
})

(
SynthDef(\playbuff,{arg out=0,in=0,r=1,p=0;
    var sig=PlayBuf.ar(1,in,r,loop:1);
    var env=EnvGen.kr(Env([0,1,1,0],[0.01,Rand(0.1,1),0.01]),gate:1,doneAction:2);

    Out.ar(out,Pan2.ar(sig*env*3,pos:p));
}).add;



SynthDef(\synth,{arg out=0;
    var sig=VarSaw.ar(90,0,0.5*LFTri.kr(0.1).range(1,1.2),mul:0.1)+VarSaw.ar(90.5,0,0.5*LFTri.kr(0.2).range(1,1.2),mul:0.1)+VarSaw.ar(90.8,0,0.5*LFTri.kr(0.3).range(1,1.2),mul:0.1);
    sig=HPF.ar(sig,200);
    sig=FreeVerb.ar(sig);
    Out.ar(out,sig!2)
}).add;

SynthDef(\pad,{arg out=0,f=0;
    var sig=Array.fill(3,{|n| SinOsc.ar(f*(n+1),0,0.05/(n+1))}).sum;
    var env=EnvGen.kr(Env([0,1,1,0],[10,5,10]),gate:1,doneAction:2);
    sig=LPF.ar(sig,3000);
    Out.ar(~b,sig*env!2)
}).add;

SynthDef(\del,{arg out=0;
    var sig=CombC.ar(In.ar(~b,2),0.4,TRand.kr(0.05,0.3,Impulse.kr(0.1)),7);
    Out.ar(out,sig);
}).add;
)

y=Synth(\del);

x=Synth(\synth);

t=fork{
inf.do{
        Synth(\pad,[\f:[48,52,53,55,57].choose.midicps]);
    23.wait;}
};

q=fork{
inf.do{
        Synth(\playbuff,[\in:~x[rrand(0,20).asInteger],\r:[-1,1].choose,\p:rrand(-0.5,0.5),\out:[0,~b].wchoose([0.92,0.08])]);
        rrand(0.5,3).wait}
}


t.stop;
q.stop;
x.free;
y.free;


s.quit;

pagetop