--- /dev/null
+/*
+ * Copyright (C) 2012 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+// FFTFrame implementation using the GStreamer FFT library.
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#if USE(WEBAUDIO_GSTREAMER)
+
+#include "platform/audio/FFTFrame.h"
+
+#include "platform/audio/VectorMath.h"
+
+#include "wtf/FastMalloc.h"
+#include "wtf/StdLibExtras.h"
+
+namespace {
+
+size_t unpackedFFTDataSize(unsigned fftSize)
+{
+ return fftSize / 2 + 1;
+}
+
+} // anonymous namespace
+
+namespace blink {
+
+// Normal constructor: allocates for a given fftSize.
+FFTFrame::FFTFrame(unsigned fftSize)
+ : m_FFTSize(fftSize)
+ , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
+ , m_realData(unpackedFFTDataSize(m_FFTSize))
+ , m_imagData(unpackedFFTDataSize(m_FFTSize))
+{
+ m_complexData = new GstFFTF32Complex[unpackedFFTDataSize(m_FFTSize)];
+
+ int fftLength = gst_fft_next_fast_length(m_FFTSize);
+ m_fft = gst_fft_f32_new(fftLength, FALSE);
+ m_inverseFft = gst_fft_f32_new(fftLength, TRUE);
+}
+
+// Creates a blank/empty frame (interpolate() must later be called).
+FFTFrame::FFTFrame()
+ : m_FFTSize(0)
+ , m_log2FFTSize(0)
+{
+ int fftLength = gst_fft_next_fast_length(m_FFTSize);
+ m_fft = gst_fft_f32_new(fftLength, FALSE);
+ m_inverseFft = gst_fft_f32_new(fftLength, TRUE);
+}
+
+// Copy constructor.
+FFTFrame::FFTFrame(const FFTFrame& frame)
+ : m_FFTSize(frame.m_FFTSize)
+ , m_log2FFTSize(frame.m_log2FFTSize)
+ , m_realData(unpackedFFTDataSize(frame.m_FFTSize))
+ , m_imagData(unpackedFFTDataSize(frame.m_FFTSize))
+{
+ m_complexData = new GstFFTF32Complex[unpackedFFTDataSize(m_FFTSize)];
+
+ int fftLength = gst_fft_next_fast_length(m_FFTSize);
+ m_fft = gst_fft_f32_new(fftLength, FALSE);
+ m_inverseFft = gst_fft_f32_new(fftLength, TRUE);
+
+ // Copy/setup frame data.
+ memcpy(realData(), frame.realData(), sizeof(float) * unpackedFFTDataSize(m_FFTSize));
+ memcpy(imagData(), frame.imagData(), sizeof(float) * unpackedFFTDataSize(m_FFTSize));
+}
+
+void FFTFrame::initialize()
+{
+}
+
+void FFTFrame::cleanup()
+{
+}
+
+FFTFrame::~FFTFrame()
+{
+ if (!m_fft)
+ return;
+
+ gst_fft_f32_free(m_fft);
+ m_fft = 0;
+
+ gst_fft_f32_free(m_inverseFft);
+ m_inverseFft = 0;
+
+ delete[](m_complexData);
+}
+
+void FFTFrame::doFFT(const float* data)
+{
+ gst_fft_f32_fft(m_fft, data, m_complexData);
+
+ // Scale the frequency domain data to match vecLib's scale factor
+ // on the Mac. FIXME: if we change the definition of FFTFrame to
+ // eliminate this scale factor then this code will need to change.
+ // Also, if this loop turns out to be hot then we should use SSE
+ // or other intrinsics to accelerate it.
+ float scaleFactor = 2;
+
+ float* imagData = m_imagData.data();
+ float* realData = m_realData.data();
+ for (unsigned i = 0; i < unpackedFFTDataSize(m_FFTSize); ++i) {
+ imagData[i] = m_complexData[i].i * scaleFactor;
+ realData[i] = m_complexData[i].r * scaleFactor;
+ }
+}
+
+void FFTFrame::doInverseFFT(float* data)
+{
+ // Merge the real and imaginary vectors to complex vector.
+ float* realData = m_realData.data();
+ float* imagData = m_imagData.data();
+
+ for (size_t i = 0; i < unpackedFFTDataSize(m_FFTSize); ++i) {
+ m_complexData[i].i = imagData[i];
+ m_complexData[i].r = realData[i];
+ }
+
+ gst_fft_f32_inverse_fft(m_inverseFft, m_complexData, data);
+
+ // Scale so that a forward then inverse FFT yields exactly the original data.
+ const float scaleFactor = 1.0 / (2 * m_FFTSize);
+ VectorMath::vsmul(data, 1, &scaleFactor, data, 1, m_FFTSize);
+}
+
+} // namespace blink
+
+#endif // USE(WEBAUDIO_GSTREAMER)
+
+#endif // ENABLE(WEB_AUDIO)