1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/FFTBlock.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,179 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef FFTBlock_h_ 1.11 +#define FFTBlock_h_ 1.12 + 1.13 +#include "nsTArray.h" 1.14 +#include "AudioNodeEngine.h" 1.15 +#include "kiss_fft/kiss_fftr.h" 1.16 + 1.17 +namespace mozilla { 1.18 + 1.19 +// This class defines an FFT block, loosely modeled after Blink's FFTFrame 1.20 +// class to make sharing code with Blink easy. 1.21 +// Currently it's implemented on top of KissFFT on all platforms. 1.22 +class FFTBlock { 1.23 +public: 1.24 + explicit FFTBlock(uint32_t aFFTSize) 1.25 + : mFFT(nullptr) 1.26 + , mIFFT(nullptr) 1.27 + , mFFTSize(aFFTSize) 1.28 + { 1.29 + MOZ_COUNT_CTOR(FFTBlock); 1.30 + mOutputBuffer.SetLength(aFFTSize / 2 + 1); 1.31 + PodZero(mOutputBuffer.Elements(), aFFTSize / 2 + 1); 1.32 + } 1.33 + ~FFTBlock() 1.34 + { 1.35 + MOZ_COUNT_DTOR(FFTBlock); 1.36 + Clear(); 1.37 + } 1.38 + 1.39 + // Return a new FFTBlock with frequency components interpolated between 1.40 + // |block0| and |block1| with |interp| between 0.0 and 1.0. 1.41 + static FFTBlock* 1.42 + CreateInterpolatedBlock(const FFTBlock& block0, 1.43 + const FFTBlock& block1, double interp); 1.44 + 1.45 + // Transform FFTSize() points of aData and store the result internally. 1.46 + void PerformFFT(const float* aData) 1.47 + { 1.48 + EnsureFFT(); 1.49 + kiss_fftr(mFFT, aData, mOutputBuffer.Elements()); 1.50 + } 1.51 + // Inverse-transform internal data and store the resulting FFTSize() 1.52 + // points in aData. 1.53 + void GetInverse(float* aDataOut) 1.54 + { 1.55 + GetInverseWithoutScaling(aDataOut); 1.56 + AudioBufferInPlaceScale(aDataOut, 1.0f / mFFTSize, mFFTSize); 1.57 + } 1.58 + // Inverse-transform internal frequency data and store the resulting 1.59 + // FFTSize() points in |aDataOut|. If frequency data has not already been 1.60 + // scaled, then the output will need scaling by 1/FFTSize(). 1.61 + void GetInverseWithoutScaling(float* aDataOut) 1.62 + { 1.63 + EnsureIFFT(); 1.64 + kiss_fftri(mIFFT, mOutputBuffer.Elements(), aDataOut); 1.65 + } 1.66 + // Inverse-transform the FFTSize()/2+1 points of data in each 1.67 + // of aRealDataIn and aImagDataIn and store the resulting 1.68 + // FFTSize() points in aRealDataOut. 1.69 + void PerformInverseFFT(float* aRealDataIn, 1.70 + float *aImagDataIn, 1.71 + float *aRealDataOut) 1.72 + { 1.73 + EnsureIFFT(); 1.74 + const uint32_t inputSize = mFFTSize / 2 + 1; 1.75 + nsTArray<kiss_fft_cpx> inputBuffer; 1.76 + inputBuffer.SetLength(inputSize); 1.77 + for (uint32_t i = 0; i < inputSize; ++i) { 1.78 + inputBuffer[i].r = aRealDataIn[i]; 1.79 + inputBuffer[i].i = aImagDataIn[i]; 1.80 + } 1.81 + kiss_fftri(mIFFT, inputBuffer.Elements(), aRealDataOut); 1.82 + for (uint32_t i = 0; i < mFFTSize; ++i) { 1.83 + aRealDataOut[i] /= mFFTSize; 1.84 + } 1.85 + } 1.86 + 1.87 + void Multiply(const FFTBlock& aFrame) 1.88 + { 1.89 + BufferComplexMultiply(reinterpret_cast<const float*>(mOutputBuffer.Elements()), 1.90 + reinterpret_cast<const float*>(aFrame.mOutputBuffer.Elements()), 1.91 + reinterpret_cast<float*>(mOutputBuffer.Elements()), 1.92 + mFFTSize / 2 + 1); 1.93 + } 1.94 + 1.95 + // Perform a forward FFT on |aData|, assuming zeros after dataSize samples, 1.96 + // and pre-scale the generated internal frequency domain coefficients so 1.97 + // that GetInverseWithoutScaling() can be used to transform to the time 1.98 + // domain. This is useful for convolution kernels. 1.99 + void PadAndMakeScaledDFT(const float* aData, size_t dataSize) 1.100 + { 1.101 + MOZ_ASSERT(dataSize <= FFTSize()); 1.102 + nsTArray<float> paddedData; 1.103 + paddedData.SetLength(FFTSize()); 1.104 + AudioBufferCopyWithScale(aData, 1.0f / FFTSize(), 1.105 + paddedData.Elements(), dataSize); 1.106 + PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize); 1.107 + PerformFFT(paddedData.Elements()); 1.108 + } 1.109 + 1.110 + void SetFFTSize(uint32_t aSize) 1.111 + { 1.112 + mFFTSize = aSize; 1.113 + mOutputBuffer.SetLength(aSize / 2 + 1); 1.114 + PodZero(mOutputBuffer.Elements(), aSize / 2 + 1); 1.115 + Clear(); 1.116 + } 1.117 + 1.118 + // Return the average group delay and removes this from the frequency data. 1.119 + double ExtractAverageGroupDelay(); 1.120 + 1.121 + uint32_t FFTSize() const 1.122 + { 1.123 + return mFFTSize; 1.124 + } 1.125 + float RealData(uint32_t aIndex) const 1.126 + { 1.127 + return mOutputBuffer[aIndex].r; 1.128 + } 1.129 + float ImagData(uint32_t aIndex) const 1.130 + { 1.131 + return mOutputBuffer[aIndex].i; 1.132 + } 1.133 + 1.134 + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.135 + { 1.136 + size_t amount = 0; 1.137 + amount += aMallocSizeOf(mFFT); 1.138 + amount += aMallocSizeOf(mIFFT); 1.139 + amount += mOutputBuffer.SizeOfExcludingThis(aMallocSizeOf); 1.140 + return amount; 1.141 + } 1.142 + 1.143 + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const 1.144 + { 1.145 + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 1.146 + } 1.147 + 1.148 +private: 1.149 + FFTBlock(const FFTBlock& other) MOZ_DELETE; 1.150 + void operator=(const FFTBlock& other) MOZ_DELETE; 1.151 + 1.152 + void EnsureFFT() 1.153 + { 1.154 + if (!mFFT) { 1.155 + mFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr); 1.156 + } 1.157 + } 1.158 + void EnsureIFFT() 1.159 + { 1.160 + if (!mIFFT) { 1.161 + mIFFT = kiss_fftr_alloc(mFFTSize, 1, nullptr, nullptr); 1.162 + } 1.163 + } 1.164 + void Clear() 1.165 + { 1.166 + free(mFFT); 1.167 + free(mIFFT); 1.168 + mFFT = mIFFT = nullptr; 1.169 + } 1.170 + void AddConstantGroupDelay(double sampleFrameDelay); 1.171 + void InterpolateFrequencyComponents(const FFTBlock& block0, 1.172 + const FFTBlock& block1, double interp); 1.173 + 1.174 + kiss_fftr_cfg mFFT, mIFFT; 1.175 + nsTArray<kiss_fft_cpx> mOutputBuffer; 1.176 + uint32_t mFFTSize; 1.177 +}; 1.178 + 1.179 +} 1.180 + 1.181 +#endif 1.182 +