‹ Eco rot ›

Whitney Balls

2010-11-19 00:31 supercollider

clean-up #4:

This is something I originally wrote for the article Audiovisuals with SC and now rewrote as separate classes. There are four classes all implementing the same system slightly differently. Two for graphics (Whitney, Whitney2) and the other two for patterns (Pwhitney, Pwhitney2).

The principle for this system is described by John Whitney in his book Digital Harmony (1980) and reimplemented musically by Jim Bumgardner in his Whitney Music Box (2006). 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.

whitney balls system running

The code for the above video example is taken from the help file...

(
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;

  Routine({
    var nextTime;
    while({w.isClosed.not}, {
      nextTime= Main.elapsedTime+(1/60);
      u.refresh;
      (nextTime-Main.elapsedTime).max(0.001).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;
)

Updates:

Attachments:


‹ Eco rot ›