tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FFTBlock.h (7102B)


      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 #include "AlignedTArray.h"
     11 #include "AudioNodeEngine.h"
     12 #include "FFVPXRuntimeLinker.h"
     13 #include "ffvpx/tx.h"
     14 
     15 namespace mozilla {
     16 
     17 // This class defines an FFT block, loosely modeled after Blink's FFTFrame
     18 // class to make sharing code with Blink easy.
     19 class FFTBlock final {
     20  union ComplexU {
     21    float f[2];
     22    struct {
     23      float r;
     24      float i;
     25    };
     26  };
     27 
     28 public:
     29  static void MainThreadInit() {
     30    FFVPXRuntimeLinker::Init();
     31    if (!sFFTFuncs.init) {
     32      FFVPXRuntimeLinker::GetFFTFuncs(&sFFTFuncs);
     33    }
     34  }
     35  explicit FFTBlock(uint32_t aFFTSize, float aInverseScaling = 1.0f)
     36      : mInverseScaling(aInverseScaling) {
     37    MOZ_COUNT_CTOR(FFTBlock);
     38    SetFFTSize(aFFTSize);
     39  }
     40  ~FFTBlock() {
     41    MOZ_COUNT_DTOR(FFTBlock);
     42    Clear();
     43  }
     44 
     45  // Return a new FFTBlock with frequency components interpolated between
     46  // |block0| and |block1| with |interp| between 0.0 and 1.0.
     47  static FFTBlock* CreateInterpolatedBlock(const FFTBlock& block0,
     48                                           const FFTBlock& block1,
     49                                           double interp);
     50 
     51  // Transform FFTSize() points of aData and store the result internally.
     52  void PerformFFT(const float* aData) {
     53    if (!EnsureFFT()) {
     54      return;
     55    }
     56 
     57    mFn(mTxCtx, mOutputBuffer.Elements()->f, const_cast<float*>(aData),
     58        2 * sizeof(float));
     59 #ifdef DEBUG
     60    mInversePerformed = false;
     61 #endif
     62  }
     63  // Inverse-transform internal frequency data and store the resulting
     64  // FFTSize() points in |aDataOut|.  If frequency data has not already been
     65  // scaled, then the output will need scaling by 1/FFTSize().
     66  void GetInverse(float* aDataOut) {
     67    if (!EnsureIFFT()) {
     68      std::fill_n(aDataOut, mFFTSize, 0.0f);
     69      return;
     70    };
     71    // When performing an inverse transform, tx overwrites the input. This
     72    // asserts that forward / inverse transforms are interleaved to avoid having
     73    // to keep the input around.
     74    MOZ_ASSERT(!mInversePerformed);
     75    mIFn(mITxCtx, aDataOut, mOutputBuffer.Elements()->f, 2 * sizeof(float));
     76 #ifdef DEBUG
     77    mInversePerformed = true;
     78 #endif
     79  }
     80 
     81  void Multiply(const FFTBlock& aFrame) {
     82    MOZ_ASSERT(!mInversePerformed);
     83 
     84    uint32_t halfSize = mFFTSize / 2;
     85    // DFTs are not packed.
     86    MOZ_ASSERT(mOutputBuffer[0].i == 0);
     87    MOZ_ASSERT(aFrame.mOutputBuffer[0].i == 0);
     88 
     89    BufferComplexMultiply(mOutputBuffer.Elements()->f,
     90                          aFrame.mOutputBuffer.Elements()->f,
     91                          mOutputBuffer.Elements()->f, halfSize);
     92    mOutputBuffer[halfSize].r *= aFrame.mOutputBuffer[halfSize].r;
     93    // This would have been set to NaN if either real component was NaN.
     94    mOutputBuffer[0].i = 0.0f;
     95  }
     96 
     97  // Perform a forward FFT on |aData|, assuming zeros after dataSize samples,
     98  // and pre-scale the generated internal frequency domain coefficients so
     99  // that GetInverseWithoutScaling() can be used to transform to the time
    100  // domain.  This is useful for convolution kernels.
    101  void PadAndMakeScaledDFT(const float* aData, size_t dataSize) {
    102    MOZ_ASSERT(dataSize <= FFTSize());
    103    AlignedTArray<float> paddedData;
    104    paddedData.SetLength(FFTSize());
    105    AudioBufferCopyWithScale(aData, 1.0f / AssertedCast<float>(FFTSize()),
    106                             paddedData.Elements(), dataSize);
    107    PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize);
    108    PerformFFT(paddedData.Elements());
    109  }
    110 
    111  // aSize must be a power of 2
    112  void SetFFTSize(uint32_t aSize) {
    113    MOZ_ASSERT(CountPopulation32(aSize) == 1);
    114    mFFTSize = aSize;
    115    mOutputBuffer.SetLength(aSize / 2 + 1);
    116    PodZero(mOutputBuffer.Elements(), aSize / 2 + 1);
    117    Clear();
    118  }
    119 
    120  // Return the average group delay and removes this from the frequency data.
    121  double ExtractAverageGroupDelay();
    122 
    123  uint32_t FFTSize() const { return mFFTSize; }
    124  float RealData(uint32_t aIndex) const {
    125    MOZ_ASSERT(!mInversePerformed);
    126    return mOutputBuffer[aIndex].r;
    127  }
    128  float& RealData(uint32_t aIndex) {
    129    MOZ_ASSERT(!mInversePerformed);
    130    return mOutputBuffer[aIndex].r;
    131  }
    132  float ImagData(uint32_t aIndex) const {
    133    MOZ_ASSERT(!mInversePerformed);
    134    return mOutputBuffer[aIndex].i;
    135  }
    136  float& ImagData(uint32_t aIndex) {
    137    MOZ_ASSERT(!mInversePerformed);
    138    return mOutputBuffer[aIndex].i;
    139  }
    140 
    141  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    142    size_t amount = 0;
    143 
    144    // malloc_usable_size can't be used here because the pointer isn't
    145    // necessarily from malloc. This value has been manually checked.
    146    if (mTxCtx) {
    147      amount += 711;
    148    }
    149    if (mTxCtx) {
    150      amount += 711;
    151    }
    152 
    153    amount += mOutputBuffer.ShallowSizeOfExcludingThis(aMallocSizeOf);
    154    return amount;
    155  }
    156 
    157  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    158    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    159  }
    160 
    161  FFTBlock(const FFTBlock& other) = delete;
    162  void operator=(const FFTBlock& other) = delete;
    163 
    164 private:
    165  bool EnsureFFT() {
    166    if (!mTxCtx) {
    167      if (!sFFTFuncs.init) {
    168        return false;
    169      }
    170      // Forward transform is always unscaled for our purpose.
    171      float scale = 1.0f;
    172      int rv = sFFTFuncs.init(&mTxCtx, &mFn, AV_TX_FLOAT_RDFT, 0 /* forward */,
    173                              AssertedCast<int>(mFFTSize), &scale, 0);
    174      MOZ_ASSERT(!rv, "av_tx_init: invalid parameters (forward)");
    175      return !rv;
    176    }
    177    return true;
    178  }
    179  bool EnsureIFFT() {
    180    if (!mITxCtx) {
    181      if (!sFFTFuncs.init) {
    182        return false;
    183      }
    184      int rv =
    185          sFFTFuncs.init(&mITxCtx, &mIFn, AV_TX_FLOAT_RDFT, 1 /* inverse */,
    186                         AssertedCast<int>(mFFTSize), &mInverseScaling, 0);
    187      MOZ_ASSERT(!rv, "av_tx_init: invalid parameters (inverse)");
    188      return !rv;
    189    }
    190    return true;
    191  }
    192  void Clear() {
    193    if (mTxCtx) {
    194      sFFTFuncs.uninit(&mTxCtx);
    195      mTxCtx = nullptr;
    196      mFn = nullptr;
    197    }
    198    if (mITxCtx) {
    199      sFFTFuncs.uninit(&mITxCtx);
    200      mITxCtx = nullptr;
    201      mIFn = nullptr;
    202    }
    203  }
    204  void AddConstantGroupDelay(double sampleFrameDelay);
    205  void InterpolateFrequencyComponents(const FFTBlock& block0,
    206                                      const FFTBlock& block1, double interp);
    207  static FFmpegFFTFuncs sFFTFuncs;
    208  // Context and function pointer for forward transform
    209  AVTXContext* mTxCtx{};
    210  av_tx_fn mFn{};
    211  // Context and function pointer for inverse transform
    212  AVTXContext* mITxCtx{};
    213  av_tx_fn mIFn{};
    214  AlignedTArray<ComplexU> mOutputBuffer;
    215  uint32_t mFFTSize{};
    216  // A scaling that is performed when doing an inverse transform. The forward
    217  // transform is always unscaled.
    218  float mInverseScaling;
    219 #ifdef DEBUG
    220  bool mInversePerformed = false;
    221 #endif
    222 };
    223 
    224 }  // namespace mozilla
    225 
    226 #endif