content/media/webaudio/FFTBlock.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     7 #ifndef FFTBlock_h_
     8 #define FFTBlock_h_
    10 #include "nsTArray.h"
    11 #include "AudioNodeEngine.h"
    12 #include "kiss_fft/kiss_fftr.h"
    14 namespace mozilla {
    16 // This class defines an FFT block, loosely modeled after Blink's FFTFrame
    17 // class to make sharing code with Blink easy.
    18 // Currently it's implemented on top of KissFFT on all platforms.
    19 class FFTBlock {
    20 public:
    21   explicit FFTBlock(uint32_t aFFTSize)
    22     : mFFT(nullptr)
    23     , mIFFT(nullptr)
    24     , mFFTSize(aFFTSize)
    25   {
    26     MOZ_COUNT_CTOR(FFTBlock);
    27     mOutputBuffer.SetLength(aFFTSize / 2 + 1);
    28     PodZero(mOutputBuffer.Elements(), aFFTSize / 2 + 1);
    29   }
    30   ~FFTBlock()
    31   {
    32     MOZ_COUNT_DTOR(FFTBlock);
    33     Clear();
    34   }
    36   // Return a new FFTBlock with frequency components interpolated between
    37   // |block0| and |block1| with |interp| between 0.0 and 1.0.
    38   static FFTBlock*
    39   CreateInterpolatedBlock(const FFTBlock& block0,
    40                           const FFTBlock& block1, double interp);
    42   // Transform FFTSize() points of aData and store the result internally.
    43   void PerformFFT(const float* aData)
    44   {
    45     EnsureFFT();
    46     kiss_fftr(mFFT, aData, mOutputBuffer.Elements());
    47   }
    48   // Inverse-transform internal data and store the resulting FFTSize()
    49   // points in aData.
    50   void GetInverse(float* aDataOut)
    51   {
    52     GetInverseWithoutScaling(aDataOut);
    53     AudioBufferInPlaceScale(aDataOut, 1.0f / mFFTSize, mFFTSize);
    54   }
    55   // Inverse-transform internal frequency data and store the resulting
    56   // FFTSize() points in |aDataOut|.  If frequency data has not already been
    57   // scaled, then the output will need scaling by 1/FFTSize().
    58   void GetInverseWithoutScaling(float* aDataOut)
    59   {
    60     EnsureIFFT();
    61     kiss_fftri(mIFFT, mOutputBuffer.Elements(), aDataOut);
    62   }
    63   // Inverse-transform the FFTSize()/2+1 points of data in each
    64   // of aRealDataIn and aImagDataIn and store the resulting
    65   // FFTSize() points in aRealDataOut.
    66   void PerformInverseFFT(float* aRealDataIn,
    67                          float *aImagDataIn,
    68                          float *aRealDataOut)
    69   {
    70     EnsureIFFT();
    71     const uint32_t inputSize = mFFTSize / 2 + 1;
    72     nsTArray<kiss_fft_cpx> inputBuffer;
    73     inputBuffer.SetLength(inputSize);
    74     for (uint32_t i = 0; i < inputSize; ++i) {
    75       inputBuffer[i].r = aRealDataIn[i];
    76       inputBuffer[i].i = aImagDataIn[i];
    77     }
    78     kiss_fftri(mIFFT, inputBuffer.Elements(), aRealDataOut);
    79     for (uint32_t i = 0; i < mFFTSize; ++i) {
    80       aRealDataOut[i] /= mFFTSize;
    81     }
    82   }
    84   void Multiply(const FFTBlock& aFrame)
    85   {
    86     BufferComplexMultiply(reinterpret_cast<const float*>(mOutputBuffer.Elements()),
    87                           reinterpret_cast<const float*>(aFrame.mOutputBuffer.Elements()),
    88                           reinterpret_cast<float*>(mOutputBuffer.Elements()),
    89                           mFFTSize / 2 + 1);
    90   }
    92   // Perform a forward FFT on |aData|, assuming zeros after dataSize samples,
    93   // and pre-scale the generated internal frequency domain coefficients so
    94   // that GetInverseWithoutScaling() can be used to transform to the time
    95   // domain.  This is useful for convolution kernels.
    96   void PadAndMakeScaledDFT(const float* aData, size_t dataSize)
    97   {
    98     MOZ_ASSERT(dataSize <= FFTSize());
    99     nsTArray<float> paddedData;
   100     paddedData.SetLength(FFTSize());
   101     AudioBufferCopyWithScale(aData, 1.0f / FFTSize(),
   102                              paddedData.Elements(), dataSize);
   103     PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize);
   104     PerformFFT(paddedData.Elements());
   105   }
   107   void SetFFTSize(uint32_t aSize)
   108   {
   109     mFFTSize = aSize;
   110     mOutputBuffer.SetLength(aSize / 2 + 1);
   111     PodZero(mOutputBuffer.Elements(), aSize / 2 + 1);
   112     Clear();
   113   }
   115   // Return the average group delay and removes this from the frequency data.
   116   double ExtractAverageGroupDelay();
   118   uint32_t FFTSize() const
   119   {
   120     return mFFTSize;
   121   }
   122   float RealData(uint32_t aIndex) const
   123   {
   124     return mOutputBuffer[aIndex].r;
   125   }
   126   float ImagData(uint32_t aIndex) const
   127   {
   128     return mOutputBuffer[aIndex].i;
   129   }
   131   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   132   {
   133     size_t amount = 0;
   134     amount += aMallocSizeOf(mFFT);
   135     amount += aMallocSizeOf(mIFFT);
   136     amount += mOutputBuffer.SizeOfExcludingThis(aMallocSizeOf);
   137     return amount;
   138   }
   140   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   141   {
   142     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   143   }
   145 private:
   146   FFTBlock(const FFTBlock& other) MOZ_DELETE;
   147   void operator=(const FFTBlock& other) MOZ_DELETE;
   149   void EnsureFFT()
   150   {
   151     if (!mFFT) {
   152       mFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr);
   153     }
   154   }
   155   void EnsureIFFT()
   156   {
   157     if (!mIFFT) {
   158       mIFFT = kiss_fftr_alloc(mFFTSize, 1, nullptr, nullptr);
   159     }
   160   }
   161   void Clear()
   162   {
   163     free(mFFT);
   164     free(mIFFT);
   165     mFFT = mIFFT = nullptr;
   166   }
   167   void AddConstantGroupDelay(double sampleFrameDelay);
   168   void InterpolateFrequencyComponents(const FFTBlock& block0,
   169                                       const FFTBlock& block1, double interp);
   171   kiss_fftr_cfg mFFT, mIFFT;
   172   nsTArray<kiss_fft_cpx> mOutputBuffer;
   173   uint32_t mFFTSize;
   174 };
   176 }
   178 #endif

mercurial