b=956604 optimize inverse FFT scaling during convolution r=padenot

--HG--
extra : transplant_source : %FD%10%CEAnU%98w%15%9D%9E6l%A7Q1%E1V%CDD
This commit is contained in:
Karl Tomlinson 2014-01-08 16:58:11 +13:00
parent 3ef01a9b6c
commit 1c1570d60b
6 changed files with 25 additions and 12 deletions

View File

@ -46,7 +46,8 @@ FFTBlock* FFTBlock::CreateInterpolatedBlock(const FFTBlock& block0, const FFTBlo
int fftSize = newBlock->FFTSize();
nsTArray<float> buffer;
buffer.SetLength(fftSize);
newBlock->PerformInverseFFT(buffer.Elements());
newBlock->GetInverseWithoutScaling(buffer.Elements());
AudioBufferInPlaceScale(buffer.Elements(), 1.0f / fftSize, fftSize / 2);
PodZero(buffer.Elements() + fftSize / 2, fftSize / 2);
// Put back into frequency domain.

View File

@ -47,13 +47,18 @@ public:
}
// Inverse-transform internal data and store the resulting FFTSize()
// points in aData.
void PerformInverseFFT(float* aData)
void GetInverse(float* aDataOut)
{
GetInverseWithoutScaling(aDataOut);
AudioBufferInPlaceScale(aDataOut, 1.0f / mFFTSize, mFFTSize);
}
// Inverse-transform internal frequency data and store the resulting
// FFTSize() points in |aDataOut|. If frequency data has not already been
// scaled, then the output will need scaling by 1/FFTSize().
void GetInverseWithoutScaling(float* aDataOut)
{
EnsureIFFT();
kiss_fftri(mIFFT, mOutputBuffer.Elements(), aData);
for (uint32_t i = 0; i < mFFTSize; ++i) {
aData[i] /= mFFTSize;
}
kiss_fftri(mIFFT, mOutputBuffer.Elements(), aDataOut);
}
// Inverse-transform the FFTSize()/2+1 points of data in each
// of aRealDataIn and aImagDataIn and store the resulting
@ -84,12 +89,17 @@ public:
mFFTSize / 2 + 1);
}
void PerformPaddedFFT(const float* aData, size_t dataSize)
// Perform a forward FFT on |aData|, assuming zeros after dataSize samples,
// and pre-scale the generated internal frequency domain coefficients so
// that GetInverseWithoutScaling() can be used to transform to the time
// domain. This is useful for convolution kernels.
void PadAndMakeScaledDFT(const float* aData, size_t dataSize)
{
MOZ_ASSERT(dataSize <= FFTSize());
nsTArray<float> paddedData;
paddedData.SetLength(FFTSize());
PodCopy(paddedData.Elements(), aData, dataSize);
AudioBufferCopyWithScale(aData, 1.0f / FFTSize(),
paddedData.Elements(), dataSize);
PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize);
PerformFFT(paddedData.Elements());
}

View File

@ -88,7 +88,7 @@ void FFTConvolver::process(FFTBlock* fftKernel, const float* sourceP, float* des
// The input buffer is now filled (get frequency-domain version)
m_frame.PerformFFT(m_inputBuffer.Elements());
m_frame.Multiply(*fftKernel);
m_frame.PerformInverseFFT(m_outputBuffer.Elements());
m_frame.GetInverseWithoutScaling(m_outputBuffer.Elements());
// Overlap-add 1st half from previous time
AudioBufferAddWithScale(m_lastOverlapBuffer.Elements(), 1.0f,

View File

@ -42,6 +42,8 @@ public:
// fftSize must be a power of two
FFTConvolver(size_t fftSize);
// |fftKernel| must be pre-scaled for FFTBlock::GetInverseWithoutScaling().
//
// For now, with multiple calls to Process(), framesToProcess MUST add up EXACTLY to fftSize / 2
//
// FIXME: Later, we can do more sophisticated buffering to relax this requirement...

View File

@ -42,7 +42,7 @@ static float extractAverageGroupDelay(float* impulseP, size_t length)
estimationFrame.PerformFFT(impulseP);
float frameDelay = static_cast<float>(estimationFrame.ExtractAverageGroupDelay());
estimationFrame.PerformInverseFFT(impulseP);
estimationFrame.GetInverse(impulseP);
return frameDelay;
}
@ -70,7 +70,7 @@ HRTFKernel::HRTFKernel(float* impulseResponse, size_t length, float sampleRate)
}
m_fftFrame = new FFTBlock(fftSize);
m_fftFrame->PerformPaddedFFT(impulseResponse, length);
m_fftFrame->PadAndMakeScaledDFT(impulseResponse, length);
}
// Interpolates two kernels with x: 0 -> 1 and returns the result.

View File

@ -49,7 +49,7 @@ ReverbConvolverStage::ReverbConvolverStage(const float* impulseResponse, size_t,
if (!m_directMode) {
m_fftKernel = new FFTBlock(fftSize);
m_fftKernel->PerformPaddedFFT(impulseResponse + stageOffset, stageLength);
m_fftKernel->PadAndMakeScaledDFT(impulseResponse + stageOffset, stageLength);
m_fftConvolver = new FFTConvolver(fftSize);
} else {
m_directKernel.SetLength(fftSize / 2);