Re: vDSP distortion/buzzing
Re: vDSP distortion/buzzing
- Subject: Re: vDSP distortion/buzzing
- From: Aristotel Digenis <email@hidden>
- Date: Sat, 17 Jul 2004 17:26:46 +0100
Hello Urs,
Thanks for the quick reply! Your explanation makes sense and will prove
useful soon. But first I should point out that the buzz/distortion
appears to be a result of ctozD() and ztocD(). As mentioned in my first
post, I have tried commenting different parts of the processing to pin
point the source of the noise.
1) incoming signal - ctozD() - FFT - multiply with HRTF - iFFT - ztocD()
- outgoing signal
Result: There is the audio signal but also buzz/distortion added.
2) incoming signal - ctozD() - FFT - iFFT - ztocD() - outgoing signal
Result: There is the audio signal but also buzz/distortion added.
3) incoming signal - ctozD() - ztocD() - outgoing signal
Result: There is the audio signal but also buzz/distortion added.
However the noise is less obvious.
It appears that using ctoZD() and then ztocD() is the course of the
noise. Adding FFT and iFFT in between seems to exadurate that noise.
Ofcourse this seems crazy as these are Apple's functions which logically
work correctly (especialy as it seems others have managed to use them
fine). My processing is done in the same way that it is done in Apple's
example code that comes with the Acceleration framework.
Once again thank you!!! 8-)
Aristotel
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BBinaural::BBinaural
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BBinaural::BBinaural(AudioUnit component) : AUEffectBase(component)
{
log2n = 9;
n = 1 << log2n;
nOver2 = n / 2;
stride = 1;
fft512Setup = create_fftsetupD(log2n, kFFTRadix2);
scale = (float) 1.0 / (2 * n);
bufferCount = 0;
//// HRTF_0Degree0ElevationSplitDoubleComplex declared in header
HRTF_0Degree0ElevationSplitDoubleComplex.realp = (double*)
malloc(nOver2 * sizeof(double));
HRTF_0Degree0ElevationSplitDoubleComplex.imagp = (double*)
malloc(nOver2 * sizeof(double));
//// Convert real data array to Double Complex Split
ctozD((DOUBLE_COMPLEX *) front0elevation0, 2,
&HRTF_0Degree0ElevationSplitDoubleComplex, 1, nOver2);
//// Convert the HRTF inpulse response to frequency domain
fft_zripD(fft512Setup, &HRTF_0Degree0ElevationSplitDoubleComplex,
stride, log2n, kFFTDirection_Forward);
//// DOUBLE_COMPLEX_SPLIT speakersSplitDoubleComplex declared in
header
speakersSplitDoubleComplex.realp = (double*) malloc(nOver2 *
sizeof(double));
speakersSplitDoubleComplex.imagp = (double*) malloc(nOver2 *
sizeof(double));
//// double array declared in header, now initialized
for(int a = 0; a < 512; a++)
{
speakerTempBuffer[a] = 0.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BBinaural::ProcessBufferLists
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus BBinaural::ProcessBufferLists(AudioUnitRenderActionFlags&
iFlags, const AudioBufferList& inBufferList, AudioBufferList&
outBufferList, UInt32 iFrames)
{
float* audioData = (float*) inBufferList.mBuffers[0].mData;
for(UInt32 j = 0; j < iFrames; j++)
{
audioData[j] = audioData[j];
if(bufferCount < 512)
{
speakerTempBuffer[bufferCount] = audioData[j];
bufferCount++;
}
if(bufferCount == 512)
{
//// Split the 512 samples into odd-even complex double array
ctozD((DOUBLE_COMPLEX *) speakerTempBuffer, 2,
&speakersSplitDoubleComplex, 1, nOver2);
//// Convert the 512 samples to frequency domain
fft_zripD(fft512Setup, &speakersSplitDoubleComplex, stride,
log2n, kFFTDirection_Forward);
//// Multiply the frequency spectrum of the input
with the spectrum of the HRTF
zvmulD(&speakersSplitDoubleComplex, stride,
&HRTF_0Degree0ElevationSplitDoubleComplex, stride,
&speakersSplitDoubleComplex, stride, log2n, 1);
//// Convert the 512 samples to time domain
fft_zripD(fft512Setup, &speakersSplitDoubleComplex, stride,
log2n, kFFTDirection_Inverse);
//// Split the 512 samples into properly ordered array
ztocD(&speakersSplitDoubleComplex, 1, (DOUBLE_COMPLEX *)
speakerTempBuffer, 2, nOver2);
//// Place 512 samples into audioData
for(int a = 0; a < (int) log2n; a++)
{
audioData[a] = speakerTempBuffer[a];
}
//// Reset this counter so that the next 512 samples can be
stored at the beginning of the speakerTempBuffer array
bufferCount = 0;
}
}
outBufferList.mBuffers[0].mData = audioData;
return noErr;
}
Urs Heckmann wrote:
Aristotel Digenis:
In ProcessBufferLists() incoming data is stored into an array[size
512]. Once 512 samples have been stored on the temporary buffer, they
are converted to the frequency domain in the same manner the HRTF
samples were. The 512 frequency domain samples of the incoming audio
signal are multiplied with the 512 frequency domain samples. The
results are converted back to the time domain, back to normal array
from Double Complex Split. Lastly the results are assigned to the
output stream.
Hiya Aristotel,
I think the buzzing problem is fundamental thing...
What you actually try to do is convolution in the time domain by
multiplication in the frequency domain.
When convolving two buffers of sizes N and M in the time domain, you
get a result of length N+M-1. The result has a tail, so to say. In FFT
- Multiply - iFFT convolution you have 2 identically sized buffers,
and a same sized output, but not an output of double length. What
happens here is, the tail from the time domain representation doesn't
disappear magically, it actually "wraps around" and populates the same
buffer. IIRC this is called frequency aliasing.
What you have to do to avoid this phenomenon is called Overlap-Add
Method (if you google for Overlap Add, you get a lot of useful hits
about the problem...).
Basically, instead of two 512 sized buffers, you would use two 1024
sized ones, with the additional samples set to 0.0 (aka "zero
padding"). Then, after the convolution, you have the "immediate"
signal in the first 512 samples of the output and another chunk of 512
(in fact only 511 samples, but don't worry about that) containing the
tail, which has to be added to the next buffer (after convolution, of
course).
I think the easiest way to do this is setting up 2 input/output
buffers that you compute alternatively, and then output the first 512
samples of your current output buffer with the second 512 samples of
your alternative buffer added. Dunno.
I hope this helps and that my lack of coffee (8:30am here) doesn't
make me confuse things...
Cheers,
;) Urs
urs heckmann
email@hidden
www.u-he.com
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.