LCOV - code coverage report
Current view: top level - dom/media/webaudio - FFTBlock.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 82 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef FFTBlock_h_
       8             : #define FFTBlock_h_
       9             : 
      10             : #ifdef BUILD_ARM_NEON
      11             : #include <cmath>
      12             : #include "mozilla/arm.h"
      13             : #include "dl/sp/api/omxSP.h"
      14             : #endif
      15             : 
      16             : #include "AlignedTArray.h"
      17             : #include "AudioNodeEngine.h"
      18             : #if defined(MOZ_LIBAV_FFT)
      19             : #ifdef __cplusplus
      20             : extern "C" {
      21             : #endif
      22             : #include "libavcodec/avfft.h"
      23             : #ifdef __cplusplus
      24             : }
      25             : #endif
      26             : #else
      27             : #include "kiss_fft/kiss_fftr.h"
      28             : #endif
      29             : 
      30             : namespace mozilla {
      31             : 
      32             : // This class defines an FFT block, loosely modeled after Blink's FFTFrame
      33             : // class to make sharing code with Blink easy.
      34             : // Currently it's implemented on top of KissFFT on all platforms.
      35             : class FFTBlock final
      36             : {
      37             :   union ComplexU {
      38             : #if !defined(MOZ_LIBAV_FFT)
      39             :     kiss_fft_cpx c;
      40             : #endif
      41             :     float f[2];
      42             :     struct {
      43             :       float r;
      44             :       float i;
      45             :     };
      46             :   };
      47             : 
      48             : public:
      49           0 :   explicit FFTBlock(uint32_t aFFTSize)
      50             : #if defined(MOZ_LIBAV_FFT)
      51           0 :     : mAvRDFT(nullptr)
      52           0 :     , mAvIRDFT(nullptr)
      53             : #else
      54             :     : mKissFFT(nullptr)
      55             :     , mKissIFFT(nullptr)
      56             : #ifdef BUILD_ARM_NEON
      57             :     , mOmxFFT(nullptr)
      58             :     , mOmxIFFT(nullptr)
      59             : #endif
      60             : #endif
      61             :   {
      62           0 :     MOZ_COUNT_CTOR(FFTBlock);
      63           0 :     SetFFTSize(aFFTSize);
      64           0 :   }
      65           0 :   ~FFTBlock()
      66           0 :   {
      67           0 :     MOZ_COUNT_DTOR(FFTBlock);
      68           0 :     Clear();
      69           0 :   }
      70             : 
      71             :   // Return a new FFTBlock with frequency components interpolated between
      72             :   // |block0| and |block1| with |interp| between 0.0 and 1.0.
      73             :   static FFTBlock*
      74             :   CreateInterpolatedBlock(const FFTBlock& block0,
      75             :                           const FFTBlock& block1, double interp);
      76             : 
      77             :   // Transform FFTSize() points of aData and store the result internally.
      78           0 :   void PerformFFT(const float* aData)
      79             :   {
      80           0 :     EnsureFFT();
      81             : #if defined(MOZ_LIBAV_FFT)
      82           0 :     PodCopy(mOutputBuffer.Elements()->f, aData, mFFTSize);
      83           0 :     av_rdft_calc(mAvRDFT, mOutputBuffer.Elements()->f);
      84             :     // Recover packed Nyquist.
      85           0 :     mOutputBuffer[mFFTSize / 2].r = mOutputBuffer[0].i;
      86           0 :     mOutputBuffer[0].i = 0.0f;
      87             : #else
      88             : #ifdef BUILD_ARM_NEON
      89             :     if (mozilla::supports_neon()) {
      90             :       omxSP_FFTFwd_RToCCS_F32_Sfs(aData, mOutputBuffer.Elements()->f, mOmxFFT);
      91             :     } else
      92             : #endif
      93             :     {
      94             :       kiss_fftr(mKissFFT, aData, &(mOutputBuffer.Elements()->c));
      95             :     }
      96             : #endif
      97           0 :   }
      98             :   // Inverse-transform internal data and store the resulting FFTSize()
      99             :   // points in aDataOut.
     100           0 :   void GetInverse(float* aDataOut)
     101             :   {
     102           0 :     GetInverseWithoutScaling(aDataOut);
     103           0 :     AudioBufferInPlaceScale(aDataOut, 1.0f / mFFTSize, mFFTSize);
     104           0 :   }
     105             :   // Inverse-transform internal frequency data and store the resulting
     106             :   // FFTSize() points in |aDataOut|.  If frequency data has not already been
     107             :   // scaled, then the output will need scaling by 1/FFTSize().
     108           0 :   void GetInverseWithoutScaling(float* aDataOut)
     109             :   {
     110           0 :     EnsureIFFT();
     111             : #if defined(MOZ_LIBAV_FFT)
     112             :     {
     113             :       // Even though this function doesn't scale, the libav forward transform
     114             :       // gives a value that needs scaling by 2 in order for things to turn out
     115             :       // similar to how we expect from kissfft/openmax.
     116           0 :       AudioBufferCopyWithScale(mOutputBuffer.Elements()->f, 2.0f,
     117           0 :                                aDataOut, mFFTSize);
     118           0 :       aDataOut[1] = 2.0f * mOutputBuffer[mFFTSize/2].r; // Packed Nyquist
     119           0 :       av_rdft_calc(mAvIRDFT, aDataOut);
     120             :     }
     121             : #else
     122             : #ifdef BUILD_ARM_NEON
     123             :     if (mozilla::supports_neon()) {
     124             :       omxSP_FFTInv_CCSToR_F32_Sfs_unscaled(mOutputBuffer.Elements()->f, aDataOut, mOmxIFFT);
     125             :     } else
     126             : #endif
     127             :     {
     128             :       kiss_fftri(mKissIFFT, &(mOutputBuffer.Elements()->c), aDataOut);
     129             :     }
     130             : #endif
     131           0 :   }
     132             : 
     133           0 :   void Multiply(const FFTBlock& aFrame)
     134             :   {
     135           0 :     uint32_t halfSize = mFFTSize / 2;
     136             :     // DFTs are not packed.
     137           0 :     MOZ_ASSERT(mOutputBuffer[0].i == 0);
     138           0 :     MOZ_ASSERT(aFrame.mOutputBuffer[0].i == 0);
     139             : 
     140           0 :     BufferComplexMultiply(mOutputBuffer.Elements()->f,
     141           0 :                           aFrame.mOutputBuffer.Elements()->f,
     142           0 :                           mOutputBuffer.Elements()->f,
     143           0 :                           halfSize);
     144           0 :     mOutputBuffer[halfSize].r *= aFrame.mOutputBuffer[halfSize].r;
     145             :     // This would have been set to NaN if either real component was NaN.
     146           0 :     mOutputBuffer[0].i = 0.0f;
     147           0 :   }
     148             : 
     149             :   // Perform a forward FFT on |aData|, assuming zeros after dataSize samples,
     150             :   // and pre-scale the generated internal frequency domain coefficients so
     151             :   // that GetInverseWithoutScaling() can be used to transform to the time
     152             :   // domain.  This is useful for convolution kernels.
     153           0 :   void PadAndMakeScaledDFT(const float* aData, size_t dataSize)
     154             :   {
     155           0 :     MOZ_ASSERT(dataSize <= FFTSize());
     156           0 :     AlignedTArray<float> paddedData;
     157           0 :     paddedData.SetLength(FFTSize());
     158           0 :     AudioBufferCopyWithScale(aData, 1.0f / FFTSize(),
     159           0 :                              paddedData.Elements(), dataSize);
     160           0 :     PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize);
     161           0 :     PerformFFT(paddedData.Elements());
     162           0 :   }
     163             : 
     164           0 :   void SetFFTSize(uint32_t aSize)
     165             :   {
     166           0 :     mFFTSize = aSize;
     167           0 :     mOutputBuffer.SetLength(aSize / 2 + 1);
     168           0 :     PodZero(mOutputBuffer.Elements(), aSize / 2 + 1);
     169           0 :     Clear();
     170           0 :   }
     171             : 
     172             :   // Return the average group delay and removes this from the frequency data.
     173             :   double ExtractAverageGroupDelay();
     174             : 
     175           0 :   uint32_t FFTSize() const
     176             :   {
     177           0 :     return mFFTSize;
     178             :   }
     179             :   float RealData(uint32_t aIndex) const
     180             :   {
     181             :     return mOutputBuffer[aIndex].r;
     182             :   }
     183           0 :   float& RealData(uint32_t aIndex)
     184             :   {
     185           0 :     return mOutputBuffer[aIndex].r;
     186             :   }
     187             :   float ImagData(uint32_t aIndex) const
     188             :   {
     189             :     return mOutputBuffer[aIndex].i;
     190             :   }
     191           0 :   float& ImagData(uint32_t aIndex)
     192             :   {
     193           0 :     return mOutputBuffer[aIndex].i;
     194             :   }
     195             : 
     196           0 :   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     197             :   {
     198           0 :     size_t amount = 0;
     199             : #if defined(MOZ_LIBAV_FFT)
     200           0 :     amount += aMallocSizeOf(mAvRDFT);
     201           0 :     amount += aMallocSizeOf(mAvIRDFT);
     202             : #else
     203             :     amount += aMallocSizeOf(mKissFFT);
     204             :     amount += aMallocSizeOf(mKissIFFT);
     205             : #endif
     206           0 :     amount += mOutputBuffer.ShallowSizeOfExcludingThis(aMallocSizeOf);
     207           0 :     return amount;
     208             :   }
     209             : 
     210           0 :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     211             :   {
     212           0 :     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     213             :   }
     214             : 
     215             : private:
     216             :   FFTBlock(const FFTBlock& other) = delete;
     217             :   void operator=(const FFTBlock& other) = delete;
     218             : 
     219           0 :   void EnsureFFT()
     220             :   {
     221             : #if defined(MOZ_LIBAV_FFT)
     222           0 :     if (!mAvRDFT) {
     223           0 :       mAvRDFT = av_rdft_init(log((double)mFFTSize)/M_LN2, DFT_R2C);
     224             :     }
     225             : #else
     226             : #ifdef BUILD_ARM_NEON
     227             :     if (mozilla::supports_neon()) {
     228             :       if (!mOmxFFT) {
     229             :         mOmxFFT = createOmxFFT(mFFTSize);
     230             :       }
     231             :     } else
     232             : #endif
     233             :     {
     234             :       if (!mKissFFT) {
     235             :         mKissFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr);
     236             :       }
     237             :     }
     238             : #endif
     239           0 :   }
     240           0 :   void EnsureIFFT()
     241             :   {
     242             : #if defined(MOZ_LIBAV_FFT)
     243           0 :     if (!mAvIRDFT) {
     244           0 :       mAvIRDFT = av_rdft_init(log((double)mFFTSize)/M_LN2, IDFT_C2R);
     245             :     }
     246             : #else
     247             : #ifdef BUILD_ARM_NEON
     248             :     if (mozilla::supports_neon()) {
     249             :       if (!mOmxIFFT) {
     250             :         mOmxIFFT = createOmxFFT(mFFTSize);
     251             :       }
     252             :     } else
     253             : #endif
     254             :     {
     255             :       if (!mKissIFFT) {
     256             :         mKissIFFT = kiss_fftr_alloc(mFFTSize, 1, nullptr, nullptr);
     257             :       }
     258             :     }
     259             : #endif
     260           0 :   }
     261             : 
     262             : #ifdef BUILD_ARM_NEON
     263             :   static OMXFFTSpec_R_F32* createOmxFFT(uint32_t aFFTSize)
     264             :   {
     265             :     MOZ_ASSERT((aFFTSize & (aFFTSize-1)) == 0);
     266             :     OMX_INT bufSize;
     267             :     OMX_INT order = log((double)aFFTSize)/M_LN2;
     268             :     MOZ_ASSERT(aFFTSize>>order == 1);
     269             :     OMXResult status = omxSP_FFTGetBufSize_R_F32(order, &bufSize);
     270             :     if (status == OMX_Sts_NoErr) {
     271             :       OMXFFTSpec_R_F32* context = static_cast<OMXFFTSpec_R_F32*>(malloc(bufSize));
     272             :       if (omxSP_FFTInit_R_F32(context, order) != OMX_Sts_NoErr) {
     273             :         return nullptr;
     274             :       }
     275             :       return context;
     276             :     }
     277             :     return nullptr;
     278             :   }
     279             : #endif
     280             : 
     281           0 :   void Clear()
     282             :   {
     283             : #if defined(MOZ_LIBAV_FFT)
     284           0 :     av_rdft_end(mAvRDFT);
     285           0 :     av_rdft_end(mAvIRDFT);
     286           0 :     mAvRDFT = mAvIRDFT = nullptr;
     287             : #else
     288             : #ifdef BUILD_ARM_NEON
     289             :     free(mOmxFFT);
     290             :     free(mOmxIFFT);
     291             :     mOmxFFT = mOmxIFFT = nullptr;
     292             : #endif
     293             :     free(mKissFFT);
     294             :     free(mKissIFFT);
     295             :     mKissFFT = mKissIFFT = nullptr;
     296             : #endif
     297           0 :   }
     298             :   void AddConstantGroupDelay(double sampleFrameDelay);
     299             :   void InterpolateFrequencyComponents(const FFTBlock& block0,
     300             :                                       const FFTBlock& block1, double interp);
     301             : #if defined(MOZ_LIBAV_FFT)
     302             :   RDFTContext *mAvRDFT;
     303             :   RDFTContext *mAvIRDFT;
     304             : #else
     305             :   kiss_fftr_cfg mKissFFT;
     306             :   kiss_fftr_cfg mKissIFFT;
     307             : #ifdef BUILD_ARM_NEON
     308             :   OMXFFTSpec_R_F32* mOmxFFT;
     309             :   OMXFFTSpec_R_F32* mOmxIFFT;
     310             : #endif
     311             : #endif
     312             :   AlignedTArray<ComplexU> mOutputBuffer;
     313             :   uint32_t mFFTSize;
     314             : };
     315             : 
     316             : } // namespace mozilla
     317             : 
     318             : #endif
     319             : 

Generated by: LCOV version 1.13