‹ Audiovisuals with SC - Example16 - amptrackAudiovisuals with SC - Example18 - waveform ›

Audiovisuals with SC - Example17 - ffttrack

See /f0blog/audiovisuals-with-sc/

//Example17 - ffttrack
(
s.latency= 0.05;
s.waitForBoot{
  l= 256;  //try with 512 if you have a fast machine
  c= Buffer.read(s, Platform.resourceDir+/+"sounds/a11wlk01.wav");
  SynthDef(\avTrk, {|in= 0, t_trig= 0|
    var z= In.ar(in, 1);
    var chain= FFT(LocalBuf(l), z);
    Array.fill(l.div(2), {|i|
      var a= Unpack1FFT(chain, l, i, 0);
      var b= Demand.kr(chain>=0, 0, a);
      SendTrig.kr(t_trig, i, b);
    });
  }).add;
  SynthDef(\avSnd, {|out= 0, bufnum|
    var z= PlayBuf.ar(
      1,
      bufnum,
      BufRateScale.ir(bufnum)*LFPulse.kr(0.05, 0, 0.5, 0.2, -1.5),
      Impulse.kr(LFPulse.kr(0.1, 0, 0.1, 2, 1)),
      BufFrames.ir(bufnum)*LFNoise0.kr(0.2, 0.5, 0.5).round(0.2),
      1
    );
    Out.ar(out, Pan2.ar(z));
  }).add;
};
)

(
//--window setup
var width= 512+10, height= 512+10;
var w= Window("Example17 - ffttrack", Rect(99, 99, width, height), false);
var u= UserView(w, Rect(0, 0, width, height));

//--variables
var scale= if(l<=256, {2}, {1});  //scale can be 1 or 2
var cnt= 0;  //horizontal drawing position
var fftArray= Array.fill(l, 0);
var o= OSCFunc({|m|
  var v= m[3].min(1);  //brutal clip of mags here
  var i= l.div(2);
  fftArray= fftArray.put([i-m[2], i+m[2]], v);  //mirror middle of array
}, '/tr', s.addr);
var trk= Synth(\avTrk, [\in, 0]);
var snd= Synth(\avSnd, [\out, 0, \bufnum, c]);

//--interface
~speed= 1;
~version= 0;
~radius= 2/scale;
~depth= 0.01;
~trails= 0.5;

//--main loop
u.drawFunc= {
  switch(~version,
    0, {  //rectangles
      Pen.translate(5, 5);
      fftArray.do{|a, y|
        var p= Point(cnt*scale, height-10-(y*scale));
        Pen.fillColor= Color.grey((1-a).clip(0, 1));
        Pen.fillRect(Rect.aboutPoint(p, scale*~radius, scale*~radius));
      };
      cnt= cnt+~speed%fftArray.size;
      Pen.strokeColor= Color.red;
      Pen.line(Point(cnt*scale, 0), Point(cnt*scale, l*scale));
      Pen.stroke;
    },
    1, {  //ovals with a little transparency
      Pen.translate(5, 5);
      fftArray.do{|a, y|
        var p= Point(cnt*scale, height-10-(y*scale));
        Pen.fillColor= Color.grey((1-a).clip(0, 1), 0.5);
        Pen.fillOval(Rect.aboutPoint(p, scale*~radius, scale*~radius));
      };
      cnt= cnt+~speed%fftArray.size;
    },
    2, {  //rotation
      Pen.fillColor= Color.grey(1, ~trails);  //clear color with some alpha
      Pen.fillRect(Rect(0, 0, width, height));  //manually clear with rect
      fftArray.do{|a, y|
        var p= Point(cnt*scale, height-(y*scale));
        Pen.rotate(y/l*0.25*scale*2pi*~depth, width*0.5, height*0.5);
        Pen.fillColor= Color.grey((1-a).clip(0, 1));
        Pen.fillOval(Rect.aboutPoint(p, scale*~radius, scale*~radius));
      };
      cnt= cnt+~speed%fftArray.size;
    },
    3, {  //lines
      Pen.fillColor= Color.grey(1, ~trails);
      Pen.fillRect(Rect(0, 0, width, height));
      fftArray.do{|a, y|
        var p= Point(cnt.fold(0, l*scale), height-y);
        Pen.strokeColor= Color.grey(1-(a+0.5).clip(0, 1), 0.5);
        Pen.moveTo(p*a);  //move to before rotation special here
        Pen.rotate(y/l*pi*0.5*scale*~depth, width*0.5, height*0.5);
        Pen.lineTo(p);
        Pen.stroke;
      };
      cnt= cnt+~speed;
    }
  );
  trk.set(\t_trig, 1);  //to all send trigs
};

//--window management
u.clearOnRefresh= false;  //do not erase - just draw on top of
w.onClose= {
  snd.free;
  trk.free;
  o.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);
)

//change these while the program is running
~version= 1;
~radius= 4;
~speed= 8;
~speed= l/6;
~radius= l/25;
~speed= -1;
~version= 2;
~trails= 0.01;
~radius= 5;
~speed= 2;
~radius= 0.5;
~depth= -0.002;
~depth= 3;
~radius= 1;
~trails= 0.5;
~version= 3;
~depth= 0.5;
~speed= 5;
~depth= -0.1;
~depth= -0.01
~trails= 0.01;

//close the window to stop or press cmd+.
c.free;  //free the sound file buffer