[Clam-devel] overlap-save method, trying to apply a fir filter in realtime

Hernán Ordiales h at ordia.com.ar
Tue Dec 4 16:30:32 PST 2007


hi all,

just as a proof of concept (or simple fun) i was trying to implent
this kind of processing:

given one audio input and one finite impulse response (fir filter)[1]
this processing should apply the IR to the input signal using the
overlap-save[2] method (in realtime, doing the convolution in the
spectral domain) given as output another audio signal. As you can
imagine, this could be very useful for a lot of things (it's already
implemented in somewhere? i did not find it)

i had to do all inside one processing because i need to perform FFT's
of different size of the input size (audio length) and remember "old"
data (previous function call) to fill it


well i have some questions related to this (please look between code
for better understanding):

first, some definitions:
L = 512;  // input block length (fixed rigth now)
M = 64+1; // discard points (M = length (h) ) actually FIR filter
length  ; L >> M
N = L+M-1; // processing block length (through FFT)
fft_size = 1024; // next power of two of N (fixed rigth now)

-> comment: rest of buffers init, size set and other configuration are
in the constructor

bool Do(const Audio& in, Audio& out)
{
	int size = in.GetSize();
	CLAM_DEBUG_ASSERT( size==L, "Input audio size different from expected" );

	DataArray& inBlock_L = in.GetBuffer();
	DataArray& outBlock_L = out.GetBuffer();

	for ( int i=0; i<M-1; i++ )
	{
		mProcBuffer[i] = mBufferM[i]; //previous M buffer

		//saving next block of M-1 points
		mBufferM[i] = inBlock_L[ (L-(M-1)-1) + i ];
	}

// 	adding new data to the process block
	for ( int i=0; i<L; i++ )
		mProcBuffer[ (M-1) + i ] = inBlock_L[i];

// 	zero padding until fill the fft_size
	for ( int i=L; i<fft_size; i++ )
		mProcBuffer[ i ] = 0.;

-> comment: (about these for's) AFAIK to perform this kind of
operation a memcpy should be better, don't? but this kind of thing
could be possible in CLAM? also AFAIK all data types in clam are
managed at the end with one std::vector and that's has dynamic
allocations (also AFAIK :-D) i mean not contiguos in memory... or
after a resize that could be guaranteed? i'm not sure about this issue
right now
(btw, i know "early optimizations are the root of all evil" but i
would like to know what do you think about this)
can/should i use std::copy or std:fill? could i break something with
something like this?


	mFFT.Start();
	mFFT.Do( mProcAudio, mProcSpecBuffer );
	mFFT.Stop();

->comment: "Start()" "Stop()" how is working that? is really needed in NE?


// Y_m(k) = X_m(k)H(k)
// 	mSpecProduct.Do( mProcSpecBuffer, mImpulseResponseH, mOutSpecBuffer );

->comment: here i tried to use the SpectrumProduct clas, but i'm
getting: "SpectrumProduct::Do(): Not in execution mode" :-(

->comment: then i replaced it with this "in place" implementation of
the spectrum product:
	Array<Complex>& outbuffer = mOutSpecBuffer.GetComplexArray();
	Array<Complex>& in1specbuffer = mProcSpecBuffer.GetComplexArray();
	Array<Complex>& in2specbuffer = mImpulseResponseH.GetComplexArray();
	for (int i=0; i<fft_size/2+1; i++)
	{
		TData a = in1specbuffer[i].Real();
		TData b = in1specbuffer[i].Imag();
		TData c = in2specbuffer[i].Real();
		TData d = in2specbuffer[i].Imag();

		outbuffer[i].SetReal( a*c - b*d );
		outbuffer[i].SetImag( a*d + b*c );
	}


// 	mIFFT.Start();
// 	mIFFT.Do( mOutSpecBuffer, mOutAudio );
// 	mIFFT.Stop();

->comment: again "IFFT_fftw3: Do(): Not in execution mode" how can avoid this???

// 	discard first M-1 points
	for ( int i=0; i<L; i++ )
		outBlock_L[i] = mOutBuffer[ (M-1) + i ];

	return true;
}


any kind of comments are welcome,

very thanks!

[1] right now is not defined how to load/setup this on the processing
[2] or overlap-add, right now i'm only implemented the first one
-- 
Hernán
http://h.ordia.com.ar
GnuPG: 0xEE8A3FE9




More information about the clam-devel mailing list