summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/audio/mkl
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/audio/mkl
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/audio/mkl')
-rw-r--r--Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp
new file mode 100644
index 0000000..f66a485
--- /dev/null
+++ b/Source/WebCore/platform/audio/mkl/FFTFrameMKL.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// FFTFrame implementation using Intel's Math Kernel Library (MKL),
+// suitable for use on Windows and Linux.
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "FFTFrame.h"
+
+#include "mkl_vml.h"
+#include <wtf/MathExtras.h>
+
+namespace {
+
+DFTI_DESCRIPTOR_HANDLE createDescriptorHandle(int fftSize)
+{
+ DFTI_DESCRIPTOR_HANDLE handle = 0;
+
+ // Create DFTI descriptor for 1D single precision transform.
+ MKL_LONG status = DftiCreateDescriptor(&handle, DFTI_SINGLE, DFTI_REAL, 1, fftSize);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set placement of result to DFTI_NOT_INPLACE.
+ status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set packing format to PERM; this produces the layout which
+ // matches Accelerate.framework's on the Mac, though interleaved.
+ status = DftiSetValue(handle, DFTI_PACKED_FORMAT, DFTI_PERM_FORMAT);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set the forward scale factor to 2 to match Accelerate.framework's.
+ // FIXME: FFTFrameMac's scaling factor could be fixed to be 1.0,
+ // in which case this code would need to be changed as well.
+ status = DftiSetValue(handle, DFTI_FORWARD_SCALE, 2.0);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Set the backward scale factor to 1 / 2n to match Accelerate.framework's.
+ // FIXME: if the above scaling factor is fixed then this needs to be as well.
+ double scale = 1.0 / (2.0 * fftSize);
+ status = DftiSetValue(handle, DFTI_BACKWARD_SCALE, scale);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // Use the default DFTI_CONJUGATE_EVEN_STORAGE = DFTI_COMPLEX_REAL.
+
+ // Commit DFTI descriptor.
+ status = DftiCommitDescriptor(handle);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ return handle;
+}
+
+} // anonymous namespace
+
+namespace WebCore {
+
+const int kMaxFFTPow2Size = 24;
+
+DFTI_DESCRIPTOR_HANDLE* FFTFrame::descriptorHandles = 0;
+
+// Normal constructor: allocates for a given fftSize.
+FFTFrame::FFTFrame(unsigned fftSize)
+ : m_FFTSize(fftSize)
+ , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
+ , m_handle(0)
+ , m_complexData(fftSize)
+ , m_realData(fftSize / 2)
+ , m_imagData(fftSize / 2)
+{
+ // We only allow power of two.
+ ASSERT(1UL << m_log2FFTSize == m_FFTSize);
+
+ m_handle = descriptorHandleForSize(fftSize);
+}
+
+// Creates a blank/empty frame (interpolate() must later be called).
+FFTFrame::FFTFrame()
+ : m_FFTSize(0)
+ , m_log2FFTSize(0)
+ , m_handle(0)
+{
+}
+
+// Copy constructor.
+FFTFrame::FFTFrame(const FFTFrame& frame)
+ : m_FFTSize(frame.m_FFTSize)
+ , m_log2FFTSize(frame.m_log2FFTSize)
+ , m_handle(0)
+ , m_complexData(frame.m_FFTSize)
+ , m_realData(frame.m_FFTSize / 2)
+ , m_imagData(frame.m_FFTSize / 2)
+{
+ m_handle = descriptorHandleForSize(m_FFTSize);
+
+ // Copy/setup frame data.
+ unsigned nbytes = sizeof(float) * (m_FFTSize / 2);
+ memcpy(realData(), frame.realData(), nbytes);
+ memcpy(imagData(), frame.imagData(), nbytes);
+}
+
+FFTFrame::~FFTFrame()
+{
+}
+
+void FFTFrame::multiply(const FFTFrame& frame)
+{
+ FFTFrame& frame1 = *this;
+ FFTFrame& frame2 = const_cast<FFTFrame&>(frame);
+
+ float* realP1 = frame1.realData();
+ float* imagP1 = frame1.imagData();
+ const float* realP2 = frame2.realData();
+ const float* imagP2 = frame2.imagData();
+
+ // Scale accounts for vecLib's peculiar scaling.
+ // This ensures the right scaling all the way back to inverse FFT.
+ // FIXME: this scaling factor will be 1.0f if the above 2.0 -> 1.0
+ // scaling factor is fixed.
+ float scale = 0.5f;
+
+ // Multiply packed DC/nyquist component.
+ realP1[0] *= scale * realP2[0];
+ imagP1[0] *= scale * imagP2[0];
+
+ // Multiply the rest, skipping packed DC/Nyquist components.
+ float* interleavedData1 = frame1.getUpToDateComplexData();
+ float* interleavedData2 = frame2.getUpToDateComplexData();
+
+ unsigned halfSize = m_FFTSize / 2;
+
+ // Complex multiply.
+ vcMul(halfSize - 1,
+ reinterpret_cast<MKL_Complex8*>(interleavedData1) + 1,
+ reinterpret_cast<MKL_Complex8*>(interleavedData2) + 1,
+ reinterpret_cast<MKL_Complex8*>(interleavedData1) + 1);
+
+ // De-interleave and scale the rest of the data.
+ // FIXME: find an MKL routine to do at least the scaling more efficiently.
+ for (unsigned i = 1; i < halfSize; ++i) {
+ int baseComplexIndex = 2 * i;
+ realP1[i] = scale * interleavedData1[baseComplexIndex];
+ imagP1[i] = scale * interleavedData1[baseComplexIndex + 1];
+ }
+}
+
+void FFTFrame::doFFT(float* data)
+{
+ // Compute Forward transform.
+ MKL_LONG status = DftiComputeForward(m_handle, data, m_complexData.data());
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+
+ // De-interleave to separate real and complex arrays. FIXME:
+ // figure out if it's possible to get MKL to use split-complex
+ // form for 1D real-to-complex out-of-place FFTs.
+ int len = m_FFTSize / 2;
+ for (int i = 0; i < len; ++i) {
+ int baseComplexIndex = 2 * i;
+ // m_realData[0] is the DC component and m_imagData[0] the
+ // Nyquist component since the interleaved complex data is
+ // packed.
+ m_realData[i] = m_complexData[baseComplexIndex];
+ m_imagData[i] = m_complexData[baseComplexIndex + 1];
+ }
+}
+
+void FFTFrame::doInverseFFT(float* data)
+{
+ // Prepare interleaved data. FIXME: figure out if it's possible to
+ // get MKL to use split-complex form for 1D backward
+ // (complex-to-real) out-of-place FFTs.
+ float* interleavedData = getUpToDateComplexData();
+
+ // Compute backward transform.
+ MKL_LONG status = DftiComputeBackward(m_handle, interleavedData, data);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+}
+
+void FFTFrame::cleanup()
+{
+ if (!descriptorHandles)
+ return;
+
+ for (int i = 0; i < kMaxFFTPow2Size; ++i) {
+ if (descriptorHandles[i]) {
+ MKL_LONG status = DftiFreeDescriptor(&descriptorHandles[i]);
+ ASSERT(DftiErrorClass(status, DFTI_NO_ERROR));
+ }
+ }
+
+ delete[] descriptorHandles;
+ descriptorHandles = 0;
+}
+
+float* FFTFrame::realData() const
+{
+ return const_cast<float*>(m_realData.data());
+}
+
+float* FFTFrame::imagData() const
+{
+ return const_cast<float*>(m_imagData.data());
+}
+
+float* FFTFrame::getUpToDateComplexData()
+{
+ // FIXME: if we can't completely get rid of this method, SSE
+ // optimization could be considered if it shows up hot on profiles.
+ int len = m_FFTSize / 2;
+ for (int i = 0; i < len; ++i) {
+ int baseComplexIndex = 2 * i;
+ m_complexData[baseComplexIndex] = m_realData[i];
+ m_complexData[baseComplexIndex + 1] = m_imagData[i];
+ }
+ return const_cast<float*>(m_complexData.data());
+}
+
+DFTI_DESCRIPTOR_HANDLE FFTFrame::descriptorHandleForSize(unsigned fftSize)
+{
+ if (!descriptorHandles) {
+ descriptorHandles = new DFTI_DESCRIPTOR_HANDLE[kMaxFFTPow2Size];
+ for (int i = 0; i < kMaxFFTPow2Size; ++i)
+ descriptorHandles[i] = 0;
+ }
+
+ ASSERT(fftSize);
+ int pow2size = static_cast<int>(log2(fftSize));
+ ASSERT(pow2size < kMaxFFTPow2Size);
+ if (!descriptorHandles[pow2size])
+ descriptorHandles[pow2size] = createDescriptorHandle(fftSize);
+ return descriptorHandles[pow2size];
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)