// @title wavesTracker.ck // @author Brent Townshend // @note amplitude/spectrum tracking using UAna ugens // track amplitude for triggering of an instrument // frequency will track centroid of the input spectrum SndBuf snd; "announce-birds.wav"=>snd.read; snd => BPF bp => FFT fft =^ RMS rms => blackhole; fft =^ Centroid cent => blackhole; 1000.0=>bp.freq; 1.0=>bp.Q; // setup FFT: choose high-quality transform parameters 2048 => fft.size; 0.5 => float hop; second / samp => float srate; // actual audio graph and parameter setting // NOTE: gain 'g' prevents direct connection bug if (me.args() && me.arg(0)=="1") snd => Gain g => Binaural4.input[0]; 0=>int done; // Create a set of instruments with slightly different thresholds, and pitches each a fifth higher for (0=>int j;j<3;j++) { spork ~ updateInstrument(j,(j+1)/6.0*Math.PI*2,10,5.0+j*3,0.1/Math.pow(2.0,4.0*j/12)); } fun void updateInstrument(int id, float azimuth, float mindb,float threshinc, float fscale) { // Instrument (azimuth/(Math.PI/2))$int => int c1; PercFlut instr => Gain g1 => Binaural4.input[c1]; instr => Gain g2 => Binaural4.input[(c1+1)%4]; Math.cos(azimuth-c1*Math.PI/2)=>g1.gain; Math.sin(azimuth-c1*Math.PI/2)=>g2.gain; <<<"Id ",id,", azim=",azimuth,", c1=",c1," g1=",g1.gain(),", g2=",g2.gain()>>>; // initial gain 0.3 => instr.gain; // Parameters for mapping amplitude in dB to note-on trigger 40=>float maxdb; mindb=>float thresh; // instantiate a smoother to smooth tracker results (see below) Smooth sma, smf; // set time constant: shorter time constant gives faster // response but more jittery values sma.setTimeConstant((fft.size() * 2)::samp); smf.setTimeConstant((fft.size() * 1)::samp); smf.setNext(60); sma.setNext(0); now=>time starttime; // main inf-loop 0=>int ison; while(~done) { // hop in time by overlap amount (fft.size() * hop)::samp => now; // then we've gotten our first bufferful // compute the FFT and RMS analyses rms.upchuck(); rms.fval(0) => float a; Math.rmstodb(a) => float db; Math.min(maxdb, db) => db; if (db>thresh && ~ison) { // Fire a note (smf.getLast()*fscale => Std.ftom) $int => int note; <<>>; 0=>ison; } // compute spectral centroid cent.upchuck(); cent.fval(0) * srate / 2 => float c; //<<<"db=",db,", f=",c>>>; // set lower boundary: prevents note too low Math.max(60,c) => c; smf.setNext(c); } } 61::second => now; 1=>done;