‹ Audiovisuals with SC - Example18 - waveformAudiovisuals with SC - Example20 - starfield ›

Audiovisuals with SC - Example19 - Japan balls

See /f0blog/audiovisuals-with-sc/

//Example19 - Japan balls
(
s.latency= 0.05;
s.waitForBoot{

  //--window setup
  var width= 500, height= 500;
  var w= Window("Example19 - Japan balls", Rect(99, 99, width, height), false);
  var u= UserView(w, Rect(0, 0, width, height));

  //--variables
  var theta= 0;  //a counter
  var num= 15;  //try also with more balls
  var syns= {
    SynthDef(\av, {|freq= 400, amp= 0, pan= 0|
      var z= SinOsc.ar(0, SinOsc.ar(freq, 0, 2pi), amp);
      Out.ar(0, Pan2.ar(z, pan));
    }, #[0.02, 0.05, 0.05]).play(s);
  }.dup(num);
  s.sync;

  //--interface
  ~speed= 0.25;
  ~radius= 10;
  ~spread= 10;
  ~distancex= 1;
  ~distancey= 0.5;
  ~offsetx= -0.1;
  ~offsety= -0.2;
  ~root= 100;

  //--main loop
  u.drawFunc= {
    Pen.fillColor= Color.red;  //set the fill color to red
    Pen.fillOval(u.bounds);  //draw a filled oval with the size of the whole window
    Pen.translate(width*0.5, height*0.5);  //offset all drawing to middle of the window
    Pen.fillColor= Color.grey(1, 0.5);  //set the fill color with 50% alpha
    num.do{|i|
      var a, x, y;
      a= i%num/num*2pi+theta;  //angle in radians
      x= sin(a+(i*~offsetx))*(~spread+(i*~distancex));
      y= cos(a+(i*~offsety))*(~spread+(i*~distancey));
      Pen.fillOval(Rect.aboutPoint(Point(x, y), ~radius, ~radius));
      if(((x.hypot(y)/1.42/~spread).min(0.5)/num).isNil, {"nil".postln});
      syns[i].set(  //update corresponding synth
        \freq, y.linexp(height.neg*0.5, height*0.5, ~root, 1000),
        \amp, (x.hypot(y)/1.42/~spread).min(0.5)/num,
        \pan, x.linlin(width.neg*0.5, width*0.5, -1, 1)
      );
    };
    theta= theta-~speed%2pi;  //our counter counts in radians
  };

  //--window management
  u.clearOnRefresh= true;
  u.background= Color.white;
  w.onClose= {syns.do{|x| x.free}};
  w.front;
  CmdPeriod.doOnce({w.close});
  Routine({
    var nextTime;
    while({w.isClosed.not}, {
      nextTime= Main.elapsedTime+(1/60);
      u.refresh;
      (nextTime-Main.elapsedTime).max(0.001).wait;
    });
  }).play(AppClock);
};
)

(  //use MIDI input to control the program
MIDIIn.connectAll;  //or MIDIIn.connect(device:1); to select input device
//MIDIdef.trace(true);  //to debug midi in
MIDIdef.cc(\speed, {|val| ~speed= val.linlin(0, 127, 0, 2pi)}, 2);  //ctrl number 2 sets the ~speed
MIDIdef.cc(\radius, {|val| ~radius= val.linlin(0, 127, 1, 100)}, 3);
MIDIdef.cc(\spread, {|val| ~spread= val.linlin(0, 127, 0, 300)}, 4);
MIDIdef.cc(\distancex, {|val| ~distancex= val.linlin(0, 127, -10, 10)}, 5);
MIDIdef.cc(\distancey, {|val| ~distancey= val.linlin(0, 127, -10, 10)}, 6);
MIDIdef.cc(\offsetx, {|val| ~offsetx= val.linlin(0, 127, -pi*0.5, pi*0.5)}, 8);
MIDIdef.cc(\offsety, {|val| ~offsety= val.linlin(0, 127, -pi*0.5, pi*0.5)}, 9);
MIDIdef.noteOn(\root, {|vel, num| ~root= num.postln.midicps});  //note set root frequency
)

//change these while the program is running
~spread= 25;
~distancey= -2.2;
~distancey= -5.7;
~distancex= -6.7;
~spread= 150;
~radius= 50;
~offsetx= 0;
~offsety= -0.6;
~radius= 8;
~spread= 60;
~speed= pi*0.99;
~distancex= -10;
~distancey= 3;
~speed= 0.5;
~speed= -0.15;
~offsety= 0.1;
~offsetx= -0.5;
~offsety= 1;
~speed= 0.02;
~speed= 0.3;
~distancex= 0.12;
~distancey= -9.2;
~speed= 0.2;
~distancex= 5.5;
~offsetx= -0.1;
~offsety= -0.21;
~spread= 100;
~spread= 800;
~spread= 2;
~offsety= 0;
~distancey= 0;
~speed= 0.05
~speed= 11;
~root= 60;
~root= 120;

//close the window to stop or press cmd+.