2013-06-10 13:08:21 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef FFTBlock_h_
|
|
|
|
#define FFTBlock_h_
|
|
|
|
|
|
|
|
#include "nsTArray.h"
|
|
|
|
#include "AudioNodeEngine.h"
|
|
|
|
#include "kiss_fft/kiss_fftr.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
// This class defines an FFT block, loosely modeled after Blink's FFTFrame
|
|
|
|
// class to make sharing code with Blink easy.
|
|
|
|
// Currently it's implemented on top of KissFFT on all platforms.
|
|
|
|
class FFTBlock {
|
|
|
|
public:
|
|
|
|
explicit FFTBlock(uint32_t aFFTSize)
|
2013-06-10 13:09:25 -07:00
|
|
|
: mFFT(nullptr)
|
|
|
|
, mIFFT(nullptr)
|
|
|
|
, mFFTSize(aFFTSize)
|
2013-06-10 13:08:21 -07:00
|
|
|
{
|
2013-08-08 02:38:24 -07:00
|
|
|
MOZ_COUNT_CTOR(FFTBlock);
|
2013-06-10 13:08:21 -07:00
|
|
|
mOutputBuffer.SetLength(aFFTSize / 2 + 1);
|
|
|
|
PodZero(mOutputBuffer.Elements(), aFFTSize / 2 + 1);
|
|
|
|
}
|
2013-06-10 13:09:25 -07:00
|
|
|
~FFTBlock()
|
|
|
|
{
|
2013-08-08 02:38:24 -07:00
|
|
|
MOZ_COUNT_DTOR(FFTBlock);
|
2013-06-25 17:37:56 -07:00
|
|
|
Clear();
|
2013-06-10 13:09:25 -07:00
|
|
|
}
|
2013-06-10 13:08:21 -07:00
|
|
|
|
2013-08-08 02:38:24 -07:00
|
|
|
// Return a new FFTBlock with frequency components interpolated between
|
|
|
|
// |block0| and |block1| with |interp| between 0.0 and 1.0.
|
|
|
|
static FFTBlock*
|
|
|
|
CreateInterpolatedBlock(const FFTBlock& block0,
|
|
|
|
const FFTBlock& block1, double interp);
|
|
|
|
|
2013-06-10 13:08:21 -07:00
|
|
|
void PerformFFT(const float* aData)
|
|
|
|
{
|
2013-06-10 13:09:25 -07:00
|
|
|
EnsureFFT();
|
|
|
|
kiss_fftr(mFFT, aData, mOutputBuffer.Elements());
|
2013-06-10 13:08:21 -07:00
|
|
|
}
|
2013-06-10 13:09:25 -07:00
|
|
|
void PerformInverseFFT(float* aData)
|
2013-06-10 13:08:21 -07:00
|
|
|
{
|
2013-06-10 13:09:25 -07:00
|
|
|
EnsureIFFT();
|
|
|
|
kiss_fftri(mIFFT, mOutputBuffer.Elements(), aData);
|
2013-06-10 13:08:21 -07:00
|
|
|
for (uint32_t i = 0; i < mFFTSize; ++i) {
|
|
|
|
aData[i] /= mFFTSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Multiply(const FFTBlock& aFrame)
|
|
|
|
{
|
|
|
|
BufferComplexMultiply(reinterpret_cast<const float*>(mOutputBuffer.Elements()),
|
|
|
|
reinterpret_cast<const float*>(aFrame.mOutputBuffer.Elements()),
|
|
|
|
reinterpret_cast<float*>(mOutputBuffer.Elements()),
|
|
|
|
mFFTSize / 2 + 1);
|
|
|
|
}
|
|
|
|
|
2013-06-10 13:09:01 -07:00
|
|
|
void PerformPaddedFFT(const float* aData, size_t dataSize)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(dataSize <= FFTSize());
|
|
|
|
nsTArray<float> paddedData;
|
|
|
|
paddedData.SetLength(FFTSize());
|
|
|
|
PodCopy(paddedData.Elements(), aData, dataSize);
|
|
|
|
PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize);
|
|
|
|
PerformFFT(paddedData.Elements());
|
|
|
|
}
|
|
|
|
|
2013-06-10 13:08:21 -07:00
|
|
|
void SetFFTSize(uint32_t aSize)
|
|
|
|
{
|
|
|
|
mFFTSize = aSize;
|
|
|
|
mOutputBuffer.SetLength(aSize / 2 + 1);
|
|
|
|
PodZero(mOutputBuffer.Elements(), aSize / 2 + 1);
|
2013-06-25 17:37:56 -07:00
|
|
|
Clear();
|
2013-06-10 13:08:21 -07:00
|
|
|
}
|
|
|
|
|
2013-08-08 02:38:24 -07:00
|
|
|
// Return the average group delay and removes this from the frequency data.
|
|
|
|
double ExtractAverageGroupDelay();
|
|
|
|
|
2013-06-10 13:09:01 -07:00
|
|
|
uint32_t FFTSize() const
|
2013-06-10 13:08:21 -07:00
|
|
|
{
|
|
|
|
return mFFTSize;
|
|
|
|
}
|
|
|
|
float RealData(uint32_t aIndex) const
|
|
|
|
{
|
|
|
|
return mOutputBuffer[aIndex].r;
|
|
|
|
}
|
|
|
|
float ImagData(uint32_t aIndex) const
|
|
|
|
{
|
|
|
|
return mOutputBuffer[aIndex].i;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-08-08 02:38:24 -07:00
|
|
|
FFTBlock(const FFTBlock& other) MOZ_DELETE;
|
|
|
|
void operator=(const FFTBlock& other) MOZ_DELETE;
|
|
|
|
|
2013-06-10 13:09:25 -07:00
|
|
|
void EnsureFFT()
|
|
|
|
{
|
|
|
|
if (!mFFT) {
|
|
|
|
mFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void EnsureIFFT()
|
|
|
|
{
|
|
|
|
if (!mIFFT) {
|
|
|
|
mIFFT = kiss_fftr_alloc(mFFTSize, 1, nullptr, nullptr);
|
|
|
|
}
|
|
|
|
}
|
2013-06-25 17:37:56 -07:00
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
free(mFFT);
|
|
|
|
free(mIFFT);
|
|
|
|
mFFT = mIFFT = nullptr;
|
|
|
|
}
|
2013-08-08 02:38:24 -07:00
|
|
|
void AddConstantGroupDelay(double sampleFrameDelay);
|
|
|
|
void InterpolateFrequencyComponents(const FFTBlock& block0,
|
|
|
|
const FFTBlock& block1, double interp);
|
2013-06-10 13:09:25 -07:00
|
|
|
|
|
|
|
kiss_fftr_cfg mFFT, mIFFT;
|
2013-06-10 13:08:21 -07:00
|
|
|
nsTArray<kiss_fft_cpx> mOutputBuffer;
|
|
|
|
uint32_t mFFTSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|