// Spectral filter. All elements above specified cutoff freq are set to 0. Thus this // is very close to a brick wall filter // note: for accurate results make sure the cutoff is set to some divisor of the SR public class spec_filter { FFT fft_; IFFT ifft_; OnePole lpf_; // in order to get rid of some artifacts // constants: 1024 => int FFT_SIZE; FFT_SIZE / 2 => int WINDOW_SIZE; FFT_SIZE / 4 => int HOP_SIZE; second/samp => float chuck_sr_ => float cutoff_freq_; 0 => lpf_.pole; int cutoff_in_bins_; // set up fft/ifft sizes: FFT_SIZE => fft_.size => ifft_.size; Windowing.blackmanHarris( WINDOW_SIZE ) => fft_.window; // array to hold contents of fft: complex spectrum_[WINDOW_SIZE]; fun void connect( UGen from, UGen to ) { // anlysis/synthesis: need an lpf after resynthesis to get rid of some artifacts from => fft_ => ifft_ => lpf_ => to; } fun int size(){ return FFT_SIZE; } fun int window_size(){ return WINDOW_SIZE; } fun int hop_size(){ return HOP_SIZE; } fun void set_size( int n ) { n => FFT_SIZE => fft_.size => ifft_.size; n/2 => WINDOW_SIZE; Windowing.blackmanHarris( WINDOW_SIZE ); n/4 => HOP_SIZE; } fun void freq( float freq ) { freq => cutoff_freq_; 1. - cutoff_freq_/chuck_sr_ => lpf_.pole; // cutoff freq computed in samples: (2.*cutoff_freq_/chuck_sr_*WINDOW_SIZE) $ int => cutoff_in_bins_; } fun void run() { while( true ) { // do fft: fft_.upchuck(); // get fft contents and store it in spectrum: fft_.spectrum( spectrum_ ); // transformation: for( cutoff_in_bins_ => int i; i < WINDOW_SIZE; i++ ) { #(0, 0) => spectrum_[i]; } // ifft: ifft_.transform( spectrum_ ); HOP_SIZE::samp => now; } } fun float last() { return lpf_.last(); } } //usage: //SndBuf file; //file.read("/Users/eaylon/Desktop/SaraK.aiff"); //spec_filter s; //s.set_size( 1024 ); //s.freq(5512.5); //if( me.args() ) s.freq( Std.atof( me.arg(0) )); //s.connect( file, blackhole ); ////s.connect( adc, blackhole ); //Impulse imp => dac; //spork ~ s.run(); //while( true ) //{ // s.last() => imp.next; // 1::samp => now; //}