Hi List, I was wondering if someone might be able to help with a performance issue I am having with ChucK in respect to the use of FFT/IFFT. I've written a Pulsar Generator and I've added a convolution function to the pulse train of the generator. I found a previous thread that I've used as a basis for the convolution (see the posting below). The main change was to replace the following line: adc => Gain input => FFT fftx => blackhole; with this one: SinOsc sin => WinFuncEnv env => Pan2 pan => Gain input => FFT fftx => blackhole; At rest, the JACK DSP Load is about 2.2%. When I run the Pulsar Generator at a reasonable rate, the DSP Load jumps to about 3.5% or so without convolution. When I add the convolution function as below, it quickly jumps to a 100% usage with steady Xruns. The sample sizes I am using for the SndBuf statement below are somewhere between 18000 and 28000 samples. Is there a strategy anyone could suggest to achieve greater performance of the convolution function below or are there alternative strategies for implementing convolution in general? I'd appreciate any advice. +++ [chuck-users] Daniel: Convolution (FFT version) Perry R Cook prc at CS.Princeton.EDU Tue Nov 25 19:09:31 EST 2014 Previous message: [chuck-users] Daniel: Convolution Next message: [chuck-users] chugins won't compile Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] FFT version. Most efficient, lots of delay. Could chunk up and factor, overlap-add for less delay. This is the basic idea tho. // FFT convolution with static impulse response // by Perry R. Cook, November 2014 // upsides: as efficient as it could be, save for // constructing a specific fft convolution chugin // downsides: minimum delay is length of impulse response + buffers // fix: break into pieces and overlap add // Other fix: see filter version using my FIR Filter chugin // our fixed convolution kernal (impulse response) SndBuf s => FFT ffth => blackhole; "CelloBodyShort.wav" => s.read; // whatever you like (caution of length!!) 2 => int fftSize; while (fftSize < s.samples()) 2 *=> fftSize; // next highest power of two fftSize => int windowSize; // this is windowsize, only apply to signal blocks windowSize/2 => int hopSize; // this can any whole fraction of windowsize 2 *=> fftSize; // zero pad by 2x factor (for convolve) // our input signal, replace adc with anything you like adc => Gain input => FFT fftx => blackhole; // input signal IFFT outy => dac; // our output fftSize => ffth.size => fftx.size => outy.size; // sizes Windowing.hann(windowSize) => fftx.window; // <<< s.samples(), fftSize >>>; windowSize::samp => now; // load impulse response into h ffth.upchuck() @=> UAnaBlob H; // spectrum of fixed impulse response s =< ffth =< blackhole; // don't need impulse resp signal anymore complex Z[fftSize/2]; 1000 => input.gain; // fiddle with this how you like/need while (true) { fftx.upchuck() @=> UAnaBlob X; // spectrum of input signal // multiply spectra bin by bin (complex for free!): for(0 => int i; i < fftSize/2; i++ ) { fftx.cval(i) * H.cval(i) => Z[i]; } outy.transform( Z ); // take ifft hopSize :: samp => now; // and do it all again } Regards, Mitch
participants (1)
-
Mitch Kaufman