b=815643 Add Blink's frequency interpolation and group delay methods from FFTFrame to FFTBlock r=ehsan
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 08 Aug 2013 21:38:24 +1200
changeset 142369 729de18aacef
parent 142368 07e1d8379a30
child 142370 5fd2ef2d9947
push id25093
push usercbook@mozilla.com
push dateTue, 13 Aug 2013 10:34:53 +0000
treeherdermozilla-central@a0e613b4f4d8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs815643
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
b=815643 Add Blink's frequency interpolation and group delay methods from FFTFrame to FFTBlock r=ehsan
content/media/webaudio/FFTBlock.cpp
content/media/webaudio/FFTBlock.h
content/media/webaudio/blink/FFTFrame.cpp
content/media/webaudio/moz.build
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/FFTBlock.cpp
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set ts=4 sw=4 sts=4 et cindent: */
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "FFTBlock.h"
+
+#include "AudioNodeEngine.h"
+
+#include <complex>
+
+namespace mozilla {
+
+typedef std::complex<double> Complex;
+
+FFTBlock* FFTBlock::CreateInterpolatedBlock(const FFTBlock& block0, const FFTBlock& block1, double interp)
+{
+    FFTBlock* newBlock = new FFTBlock(block0.FFTSize());
+
+    newBlock->InterpolateFrequencyComponents(block0, block1, interp);
+
+    // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
+    int fftSize = newBlock->FFTSize();
+    nsTArray<float> buffer;
+    buffer.SetLength(fftSize);
+    newBlock->PerformInverseFFT(buffer.Elements());
+    PodZero(buffer.Elements() + fftSize / 2, fftSize / 2);
+
+    // Put back into frequency domain.
+    newBlock->PerformFFT(buffer.Elements());
+
+    return newBlock;
+}
+
+void FFTBlock::InterpolateFrequencyComponents(const FFTBlock& block0, const FFTBlock& block1, double interp)
+{
+    // FIXME : with some work, this method could be optimized
+
+    kiss_fft_cpx* dft = mOutputBuffer.Elements();
+
+    const kiss_fft_cpx* dft1 = block0.mOutputBuffer.Elements();
+    const kiss_fft_cpx* dft2 = block1.mOutputBuffer.Elements();
+
+    MOZ_ASSERT(mFFTSize == block0.FFTSize());
+    MOZ_ASSERT(mFFTSize == block1.FFTSize());
+    double s1base = (1.0 - interp);
+    double s2base = interp;
+
+    double phaseAccum = 0.0;
+    double lastPhase1 = 0.0;
+    double lastPhase2 = 0.0;
+
+    int n = mFFTSize / 2;
+
+    dft[0].r = static_cast<float>(s1base * dft1[0].r + s2base * dft2[0].r);
+    dft[n].r = static_cast<float>(s1base * dft1[n].r + s2base * dft2[n].r);
+
+    for (int i = 1; i < n; ++i) {
+        Complex c1(dft1[i].r, dft1[i].i);
+        Complex c2(dft2[i].r, dft2[i].i);
+
+        double mag1 = abs(c1);
+        double mag2 = abs(c2);
+
+        // Interpolate magnitudes in decibels
+        double mag1db = 20.0 * log10(mag1);
+        double mag2db = 20.0 * log10(mag2);
+
+        double s1 = s1base;
+        double s2 = s2base;
+
+        double magdbdiff = mag1db - mag2db;
+
+        // Empirical tweak to retain higher-frequency zeroes
+        double threshold =  (i > 16) ? 5.0 : 2.0;
+
+        if (magdbdiff < -threshold && mag1db < 0.0) {
+            s1 = pow(s1, 0.75);
+            s2 = 1.0 - s1;
+        } else if (magdbdiff > threshold && mag2db < 0.0) {
+            s2 = pow(s2, 0.75);
+            s1 = 1.0 - s2;
+        }
+
+        // Average magnitude by decibels instead of linearly
+        double magdb = s1 * mag1db + s2 * mag2db;
+        double mag = pow(10.0, 0.05 * magdb);
+
+        // Now, deal with phase
+        double phase1 = arg(c1);
+        double phase2 = arg(c2);
+
+        double deltaPhase1 = phase1 - lastPhase1;
+        double deltaPhase2 = phase2 - lastPhase2;
+        lastPhase1 = phase1;
+        lastPhase2 = phase2;
+
+        // Unwrap phase deltas
+        if (deltaPhase1 > M_PI)
+            deltaPhase1 -= 2.0 * M_PI;
+        if (deltaPhase1 < -M_PI)
+            deltaPhase1 += 2.0 * M_PI;
+        if (deltaPhase2 > M_PI)
+            deltaPhase2 -= 2.0 * M_PI;
+        if (deltaPhase2 < -M_PI)
+            deltaPhase2 += 2.0 * M_PI;
+
+        // Blend group-delays
+        double deltaPhaseBlend;
+
+        if (deltaPhase1 - deltaPhase2 > M_PI)
+            deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * M_PI + deltaPhase2);
+        else if (deltaPhase2 - deltaPhase1 > M_PI)
+            deltaPhaseBlend = s1 * (2.0 * M_PI + deltaPhase1) + s2 * deltaPhase2;
+        else
+            deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
+
+        phaseAccum += deltaPhaseBlend;
+
+        // Unwrap
+        if (phaseAccum > M_PI)
+            phaseAccum -= 2.0 * M_PI;
+        if (phaseAccum < -M_PI)
+            phaseAccum += 2.0 * M_PI;
+
+        dft[i].r = static_cast<float>(mag * cos(phaseAccum));
+        dft[i].i = static_cast<float>(mag * sin(phaseAccum));
+    }
+}
+
+double FFTBlock::ExtractAverageGroupDelay()
+{
+    kiss_fft_cpx* dft = mOutputBuffer.Elements();
+
+    double aveSum = 0.0;
+    double weightSum = 0.0;
+    double lastPhase = 0.0;
+
+    int halfSize = FFTSize() / 2;
+
+    const double kSamplePhaseDelay = (2.0 * M_PI) / double(FFTSize());
+
+    // Calculate weighted average group delay
+    for (int i = 1; i < halfSize; i++) {
+        Complex c(dft[i].r, dft[i].i);
+        double mag = abs(c);
+        double phase = arg(c);
+
+        double deltaPhase = phase - lastPhase;
+        lastPhase = phase;
+
+        // Unwrap
+        if (deltaPhase < -M_PI)
+            deltaPhase += 2.0 * M_PI;
+        if (deltaPhase > M_PI)
+            deltaPhase -= 2.0 * M_PI;
+
+        aveSum += mag * deltaPhase;
+        weightSum += mag;
+    }
+
+    // Note how we invert the phase delta wrt frequency since this is how group delay is defined
+    double ave = aveSum / weightSum;
+    double aveSampleDelay = -ave / kSamplePhaseDelay;
+
+    // Leave 20 sample headroom (for leading edge of impulse)
+    if (aveSampleDelay > 20.0)
+        aveSampleDelay -= 20.0;
+
+    // Remove average group delay (minus 20 samples for headroom)
+    AddConstantGroupDelay(-aveSampleDelay);
+
+    // Remove DC offset
+    dft[0].r = 0.0f;
+
+    return aveSampleDelay;
+}
+
+void FFTBlock::AddConstantGroupDelay(double sampleFrameDelay)
+{
+    int halfSize = FFTSize() / 2;
+
+    kiss_fft_cpx* dft = mOutputBuffer.Elements();
+
+    const double kSamplePhaseDelay = (2.0 * M_PI) / double(FFTSize());
+
+    double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
+
+    // Add constant group delay
+    for (int i = 1; i < halfSize; i++) {
+        Complex c(dft[i].r, dft[i].i);
+        double mag = abs(c);
+        double phase = arg(c);
+
+        phase += i * phaseAdj;
+
+        dft[i].r = static_cast<float>(mag * cos(phase));
+        dft[i].i = static_cast<float>(mag * sin(phase));
+    }
+}
+
+} // namespace mozilla
--- a/content/media/webaudio/FFTBlock.h
+++ b/content/media/webaudio/FFTBlock.h
@@ -18,24 +18,32 @@ namespace mozilla {
 // Currently it's implemented on top of KissFFT on all platforms.
 class FFTBlock {
 public:
   explicit FFTBlock(uint32_t aFFTSize)
     : mFFT(nullptr)
     , mIFFT(nullptr)
     , mFFTSize(aFFTSize)
   {
+    MOZ_COUNT_CTOR(FFTBlock);
     mOutputBuffer.SetLength(aFFTSize / 2 + 1);
     PodZero(mOutputBuffer.Elements(), aFFTSize / 2 + 1);
   }
   ~FFTBlock()
   {
+    MOZ_COUNT_DTOR(FFTBlock);
     Clear();
   }
 
+  // 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);
+
   void PerformFFT(const float* aData)
   {
     EnsureFFT();
     kiss_fftr(mFFT, aData, mOutputBuffer.Elements());
   }
   void PerformInverseFFT(float* aData)
   {
     EnsureIFFT();
@@ -65,30 +73,36 @@ public:
   void SetFFTSize(uint32_t aSize)
   {
     mFFTSize = aSize;
     mOutputBuffer.SetLength(aSize / 2 + 1);
     PodZero(mOutputBuffer.Elements(), aSize / 2 + 1);
     Clear();
   }
 
+  // Return the average group delay and removes this from the frequency data.
+  double ExtractAverageGroupDelay();
+
   uint32_t FFTSize() const
   {
     return mFFTSize;
   }
   float RealData(uint32_t aIndex) const
   {
     return mOutputBuffer[aIndex].r;
   }
   float ImagData(uint32_t aIndex) const
   {
     return mOutputBuffer[aIndex].i;
   }
 
 private:
+  FFTBlock(const FFTBlock& other) MOZ_DELETE;
+  void operator=(const FFTBlock& other) MOZ_DELETE;
+
   void EnsureFFT()
   {
     if (!mFFT) {
       mFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr);
     }
   }
   void EnsureIFFT()
   {
@@ -97,18 +111,20 @@ private:
     }
   }
   void Clear()
   {
     free(mFFT);
     free(mIFFT);
     mFFT = mIFFT = nullptr;
   }
+  void AddConstantGroupDelay(double sampleFrameDelay);
+  void InterpolateFrequencyComponents(const FFTBlock& block0,
+                                      const FFTBlock& block1, double interp);
 
-private:
   kiss_fftr_cfg mFFT, mIFFT;
   nsTArray<kiss_fft_cpx> mOutputBuffer;
   uint32_t mFFTSize;
 };
 
 }
 
 #endif
deleted file mode 100644
--- a/content/media/webaudio/blink/FFTFrame.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if ENABLE(WEB_AUDIO)
-
-#include "core/platform/audio/FFTFrame.h"
-
-#ifndef NDEBUG
-#include <stdio.h>
-#endif
-
-#include "core/platform/Logging.h"
-#include "core/platform/PlatformMemoryInstrumentation.h"
-#include <wtf/Complex.h>
-#include <wtf/MathExtras.h>
-#include <wtf/MemoryObjectInfo.h>
-#include <wtf/OwnPtr.h>
-
-#if !USE_ACCELERATE_FFT && USE(WEBAUDIO_FFMPEG)
-void reportMemoryUsage(const RDFTContext* const&, WTF::MemoryObjectInfo*);
-#endif // USE(WEBAUDIO_FFMPEG)
-
-namespace WebCore {
-
-void FFTFrame::doPaddedFFT(const float* data, size_t dataSize)
-{
-    // Zero-pad the impulse response
-    AudioFloatArray paddedResponse(fftSize()); // zero-initialized
-    paddedResponse.copyToRange(data, 0, dataSize);
-
-    // Get the frequency-domain version of padded response
-    doFFT(paddedResponse.data());
-}
-
-PassOwnPtr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
-{
-    OwnPtr<FFTFrame> newFrame = adoptPtr(new FFTFrame(frame1.fftSize()));
-
-    newFrame->interpolateFrequencyComponents(frame1, frame2, x);
-
-    // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
-    int fftSize = newFrame->fftSize();
-    AudioFloatArray buffer(fftSize);
-    newFrame->doInverseFFT(buffer.data());
-    buffer.zeroRange(fftSize / 2, fftSize);
-
-    // Put back into frequency domain.
-    newFrame->doFFT(buffer.data());
-
-    return newFrame.release();
-}
-
-void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
-{
-    // FIXME : with some work, this method could be optimized
-
-    float* realP = realData();
-    float* imagP = imagData();
-
-    const float* realP1 = frame1.realData();
-    const float* imagP1 = frame1.imagData();
-    const float* realP2 = frame2.realData();
-    const float* imagP2 = frame2.imagData();
-
-    m_FFTSize = frame1.fftSize();
-    m_log2FFTSize = frame1.log2FFTSize();
-
-    double s1base = (1.0 - interp);
-    double s2base = interp;
-
-    double phaseAccum = 0.0;
-    double lastPhase1 = 0.0;
-    double lastPhase2 = 0.0;
-
-    realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
-    imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);
-
-    int n = m_FFTSize / 2;
-
-    for (int i = 1; i < n; ++i) {
-        Complex c1(realP1[i], imagP1[i]);
-        Complex c2(realP2[i], imagP2[i]);
-
-        double mag1 = abs(c1);
-        double mag2 = abs(c2);
-
-        // Interpolate magnitudes in decibels
-        double mag1db = 20.0 * log10(mag1);
-        double mag2db = 20.0 * log10(mag2);
-
-        double s1 = s1base;
-        double s2 = s2base;
-
-        double magdbdiff = mag1db - mag2db;
-
-        // Empirical tweak to retain higher-frequency zeroes
-        double threshold =  (i > 16) ? 5.0 : 2.0;
-
-        if (magdbdiff < -threshold && mag1db < 0.0) {
-            s1 = pow(s1, 0.75);
-            s2 = 1.0 - s1;
-        } else if (magdbdiff > threshold && mag2db < 0.0) {
-            s2 = pow(s2, 0.75);
-            s1 = 1.0 - s2;
-        }
-
-        // Average magnitude by decibels instead of linearly
-        double magdb = s1 * mag1db + s2 * mag2db;
-        double mag = pow(10.0, 0.05 * magdb);
-
-        // Now, deal with phase
-        double phase1 = arg(c1);
-        double phase2 = arg(c2);
-
-        double deltaPhase1 = phase1 - lastPhase1;
-        double deltaPhase2 = phase2 - lastPhase2;
-        lastPhase1 = phase1;
-        lastPhase2 = phase2;
-
-        // Unwrap phase deltas
-        if (deltaPhase1 > piDouble)
-            deltaPhase1 -= 2.0 * piDouble;
-        if (deltaPhase1 < -piDouble)
-            deltaPhase1 += 2.0 * piDouble;
-        if (deltaPhase2 > piDouble)
-            deltaPhase2 -= 2.0 * piDouble;
-        if (deltaPhase2 < -piDouble)
-            deltaPhase2 += 2.0 * piDouble;
-
-        // Blend group-delays
-        double deltaPhaseBlend;
-
-        if (deltaPhase1 - deltaPhase2 > piDouble)
-            deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * piDouble + deltaPhase2);
-        else if (deltaPhase2 - deltaPhase1 > piDouble)
-            deltaPhaseBlend = s1 * (2.0 * piDouble + deltaPhase1) + s2 * deltaPhase2;
-        else
-            deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
-
-        phaseAccum += deltaPhaseBlend;
-
-        // Unwrap
-        if (phaseAccum > piDouble)
-            phaseAccum -= 2.0 * piDouble;
-        if (phaseAccum < -piDouble)
-            phaseAccum += 2.0 * piDouble;
-
-        Complex c = complexFromMagnitudePhase(mag, phaseAccum);
-
-        realP[i] = static_cast<float>(c.real());
-        imagP[i] = static_cast<float>(c.imag());
-    }
-}
-
-double FFTFrame::extractAverageGroupDelay()
-{
-    float* realP = realData();
-    float* imagP = imagData();
-
-    double aveSum = 0.0;
-    double weightSum = 0.0;
-    double lastPhase = 0.0;
-
-    int halfSize = fftSize() / 2;
-
-    const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
-
-    // Calculate weighted average group delay
-    for (int i = 1; i < halfSize; i++) {
-        Complex c(realP[i], imagP[i]);
-        double mag = abs(c);
-        double phase = arg(c);
-
-        double deltaPhase = phase - lastPhase;
-        lastPhase = phase;
-
-        // Unwrap
-        if (deltaPhase < -piDouble)
-            deltaPhase += 2.0 * piDouble;
-        if (deltaPhase > piDouble)
-            deltaPhase -= 2.0 * piDouble;
-
-        aveSum += mag * deltaPhase;
-        weightSum += mag;
-    }
-
-    // Note how we invert the phase delta wrt frequency since this is how group delay is defined
-    double ave = aveSum / weightSum;
-    double aveSampleDelay = -ave / kSamplePhaseDelay;
-
-    // Leave 20 sample headroom (for leading edge of impulse)
-    if (aveSampleDelay > 20.0)
-        aveSampleDelay -= 20.0;
-
-    // Remove average group delay (minus 20 samples for headroom)
-    addConstantGroupDelay(-aveSampleDelay);
-
-    // Remove DC offset
-    realP[0] = 0.0f;
-
-    return aveSampleDelay;
-}
-
-void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
-{
-    int halfSize = fftSize() / 2;
-
-    float* realP = realData();
-    float* imagP = imagData();
-
-    const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
-
-    double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
-
-    // Add constant group delay
-    for (int i = 1; i < halfSize; i++) {
-        Complex c(realP[i], imagP[i]);
-        double mag = abs(c);
-        double phase = arg(c);
-
-        phase += i * phaseAdj;
-
-        Complex c2 = complexFromMagnitudePhase(mag, phase);
-
-        realP[i] = static_cast<float>(c2.real());
-        imagP[i] = static_cast<float>(c2.imag());
-    }
-}
-
-void FFTFrame::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
-    MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::AudioSharedData);
-#if USE_ACCELERATE_FFT
-    info.addMember(m_frame, "frame");
-    info.addMember(m_realData, "realData");
-    info.addMember(m_imagData, "imagData");
-#else // !USE_ACCELERATE_FFT
-
-#if USE(WEBAUDIO_FFMPEG)
-    info.addMember(m_forwardContext, "forwardContext");
-    info.addMember(m_inverseContext, "inverseContext");
-    info.addMember(m_complexData, "complexData");
-    info.addMember(m_realData, "realData");
-    info.addMember(m_imagData, "imagData");
-#endif // USE(WEBAUDIO_FFMPEG)
-
-#if USE(WEBAUDIO_IPP)
-    int size = 0;
-    ippsDFTGetBufSize_R_32f(m_DFTSpec, &size);
-    info.addRawBuffer(m_buffer, size * sizeof(Ipp8u), "buffer");
-    ippsDFTGetSize_R_32f(m_FFTSize, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast, &size, 0, 0);
-    info.addRawBuffer(m_DFTSpec, size, "DFTSpec");
-    info.addMember(m_complexData, "complexData");
-    info.addMember(m_realData, "realData");
-    info.addMember(m_imagData, "imagData");
-#endif // USE(WEBAUDIO_IPP)
-
-#endif // !USE_ACCELERATE_FFT
-}
-
-#ifndef NDEBUG
-void FFTFrame::print()
-{
-    FFTFrame& frame = *this;
-    float* realP = frame.realData();
-    float* imagP = frame.imagData();
-    LOG(WebAudio, "**** \n");
-    LOG(WebAudio, "DC = %f : nyquist = %f\n", realP[0], imagP[0]);
-
-    int n = m_FFTSize / 2;
-
-    for (int i = 1; i < n; i++) {
-        double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]);
-        double phase = atan2(realP[i], imagP[i]);
-
-        LOG(WebAudio, "[%d] (%f %f)\n", i, mag, phase);
-    }
-    LOG(WebAudio, "****\n");
-}
-#endif // NDEBUG
-
-} // namespace WebCore
-
-#endif // ENABLE(WEB_AUDIO)
--- a/content/media/webaudio/moz.build
+++ b/content/media/webaudio/moz.build
@@ -61,16 +61,17 @@ CPP_SOURCES += [
     'AudioProcessingEvent.cpp',
     'BiquadFilterNode.cpp',
     'ChannelMergerNode.cpp',
     'ChannelSplitterNode.cpp',
     'ConvolverNode.cpp',
     'DelayNode.cpp',
     'DynamicsCompressorNode.cpp',
     'EnableWebAudioCheck.cpp',
+    'FFTBlock.cpp',
     'GainNode.cpp',
     'MediaBufferDecoder.cpp',
     'MediaElementAudioSourceNode.cpp',
     'MediaStreamAudioDestinationNode.cpp',
     'MediaStreamAudioSourceNode.cpp',
     'OfflineAudioCompletionEvent.cpp',
     'PannerNode.cpp',
     'PeriodicWave.cpp',