Add support for using ARM FFT in WebAudio
https://bugs.webkit.org/show_bug.cgi?id=109755

Reviewed by Chris Rogers.

Source/WebCore:

No new tests.

* WebCore.gyp/WebCore.gyp: Add dependency on openmax_dl when use_openmax_dl_fft is enabled.
* WebCore.gypi: Add source FFTFrameOpenMAXDLAndroid.cpp
* platform/audio/AudioArray.h:
(WebCore::AudioArray::allocate): Need 32-byte aligntment with the
OpenMAX DL FFT.
* platform/audio/FFTFrame.h:
(FFTFrame): Support OpenMAX DL FFT
* platform/audio/FFTFrameStub.cpp: Support OpenMAX DL FFT
* platform/audio/chromium/FFTFrameOpenMAXDLAndroid.cpp: Added.  Implements the
necessary interface using the OpenMAX DL FFT routines.
(WebCore):
(WebCore::FFTFrame::FFTFrame):
(WebCore::FFTFrame::initialize):
(WebCore::FFTFrame::cleanup):
(WebCore::FFTFrame::~FFTFrame):
(WebCore::FFTFrame::multiply):
(WebCore::FFTFrame::doFFT):
(WebCore::FFTFrame::doInverseFFT):
(WebCore::FFTFrame::realData):
(WebCore::FFTFrame::imagData):
(WebCore::FFTFrame::contextForSize):

Source/WebKit/chromium:

* features.gypi: Support building with the OpenMAX DL FFT.


git-svn-id: svn://svn.chromium.org/blink/trunk@147491 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 23723a7..220f86b 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,34 @@
+2013-04-02  Raymond Toy  <rtoy@google.com>
+
+        Add support for using ARM FFT in WebAudio
+        https://bugs.webkit.org/show_bug.cgi?id=109755
+
+        Reviewed by Chris Rogers.
+
+        No new tests.
+
+        * WebCore.gyp/WebCore.gyp: Add dependency on openmax_dl when use_openmax_dl_fft is enabled.
+        * WebCore.gypi: Add source FFTFrameOpenMAXDLAndroid.cpp
+        * platform/audio/AudioArray.h:
+        (WebCore::AudioArray::allocate): Need 32-byte aligntment with the
+        OpenMAX DL FFT.
+        * platform/audio/FFTFrame.h:
+        (FFTFrame): Support OpenMAX DL FFT
+        * platform/audio/FFTFrameStub.cpp: Support OpenMAX DL FFT
+        * platform/audio/chromium/FFTFrameOpenMAXDLAndroid.cpp: Added.  Implements the
+        necessary interface using the OpenMAX DL FFT routines.
+        (WebCore):
+        (WebCore::FFTFrame::FFTFrame):
+        (WebCore::FFTFrame::initialize):
+        (WebCore::FFTFrame::cleanup):
+        (WebCore::FFTFrame::~FFTFrame):
+        (WebCore::FFTFrame::multiply):
+        (WebCore::FFTFrame::doFFT):
+        (WebCore::FFTFrame::doInverseFFT):
+        (WebCore::FFTFrame::realData):
+        (WebCore::FFTFrame::imagData):
+        (WebCore::FFTFrame::contextForSize):
+
 2013-04-02  Sudarsana Nagineni  <sudarsana.nagineni@intel.com>
 
         [GStreamer] Memory leaks in MediaPlayerPrivateGStreamer
diff --git a/Source/WebCore/WebCore.gyp/WebCore.gyp b/Source/WebCore/WebCore.gyp/WebCore.gyp
index 1d2e320..7d609d8 100644
--- a/Source/WebCore/WebCore.gyp/WebCore.gyp
+++ b/Source/WebCore/WebCore.gyp/WebCore.gyp
@@ -280,6 +280,11 @@
           '<(SHARED_INTERMEDIATE_DIR)/webkit/bindings/V8DerivedSources19.cpp',
         ],
       }],
+     ['OS=="android" and use_openmax_dl_fft!=0', {
+       'webcore_include_dirs': [
+         '<(DEPTH)/third_party/openmax_dl'
+       ]
+     }],
     ],
   },  # variables
 
@@ -1590,6 +1595,16 @@
             '<(chromium_src_dir)/third_party/ffmpeg/ffmpeg.gyp:ffmpeg',
           ],
         }],
+       ['"WTF_USE_WEBAUDIO_OPENMAX_DL_FFT=1" in feature_defines', {
+         'direct_dependent_settings': {
+           'include_dirs': [
+             '<(chromium_src_dir)/third_party/openmax_dl',
+           ],
+         },
+         'dependencies': [
+           '<(chromium_src_dir)/third_party/openmax_dl/dl/dl.gyp:openmax_dl',
+         ],
+       }],
         # Windows shared builder needs extra help for linkage
         ['OS=="win" and "WTF_USE_WEBAUDIO_FFMPEG=1" in feature_defines', {
           'export_dependent_settings': [
diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi
index 2e4af1f..c3d2926 100644
--- a/Source/WebCore/WebCore.gypi
+++ b/Source/WebCore/WebCore.gypi
@@ -3780,6 +3780,7 @@
             'platform/audio/chromium/AudioBusChromium.cpp',
             'platform/audio/chromium/AudioDestinationChromium.cpp',
             'platform/audio/chromium/AudioDestinationChromium.h',
+            'platform/audio/chromium/FFTFrameOpenMAXDLAndroid.cpp',
             'platform/audio/ffmpeg/FFTFrameFFMPEG.cpp',
             'platform/audio/mac/FFTFrameMac.cpp',
             'platform/audio/mkl/FFTFrameMKL.cpp',
diff --git a/Source/WebCore/platform/audio/AudioArray.h b/Source/WebCore/platform/audio/AudioArray.h
index 0a6d873..b161cf2 100644
--- a/Source/WebCore/platform/audio/AudioArray.h
+++ b/Source/WebCore/platform/audio/AudioArray.h
@@ -60,7 +60,7 @@
       
         unsigned initialSize = sizeof(T) * n;
 
-#if USE(WEBAUDIO_FFMPEG)
+#if USE(WEBAUDIO_FFMPEG) || USE(WEBAUDIO_OPENMAX_DL_FFT)
         const size_t alignment = 32;
 #else
         const size_t alignment = 16;
diff --git a/Source/WebCore/platform/audio/FFTFrame.h b/Source/WebCore/platform/audio/FFTFrame.h
index 55ad09b..522cb5f 100644
--- a/Source/WebCore/platform/audio/FFTFrame.h
+++ b/Source/WebCore/platform/audio/FFTFrame.h
@@ -54,9 +54,12 @@
 G_END_DECLS
 #endif // USE(WEBAUDIO_GSTREAMER)
 
-#if USE(WEBAUDIO_FFMPEG)
+#if USE(WEBAUDIO_OPENMAX_DL_FFT)
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#elif USE(WEBAUDIO_FFMPEG)
 struct RDFTContext;
-#endif // USE(WEBAUDIO_FFMPEG)
+#endif
 
 #endif // !USE_ACCELERATE_FFT
 
@@ -177,6 +180,17 @@
     AudioFloatArray m_imagData;
 #endif // USE(WEBAUDIO_IPP)
 
+#if USE(WEBAUDIO_OPENMAX_DL_FFT)
+    static OMXFFTSpec_R_F32* contextForSize(unsigned log2FFTSize);
+
+    OMXFFTSpec_R_F32* m_forwardContext;
+    OMXFFTSpec_R_F32* m_inverseContext;
+
+    AudioFloatArray m_complexData;
+    AudioFloatArray m_realData;
+    AudioFloatArray m_imagData;
+#endif
+    
 #endif // !USE_ACCELERATE_FFT
 };
 
diff --git a/Source/WebCore/platform/audio/FFTFrameStub.cpp b/Source/WebCore/platform/audio/FFTFrameStub.cpp
index 6a27be5..3ad3284c 100644
--- a/Source/WebCore/platform/audio/FFTFrameStub.cpp
+++ b/Source/WebCore/platform/audio/FFTFrameStub.cpp
@@ -29,7 +29,7 @@
 
 #if ENABLE(WEB_AUDIO)
 
-#if !OS(DARWIN) && !USE(WEBAUDIO_MKL) && !USE(WEBAUDIO_FFMPEG) && !USE(WEBAUDIO_GSTREAMER) && !USE(WEBAUDIO_IPP)
+#if !OS(DARWIN) && !USE(WEBAUDIO_MKL) && !USE(WEBAUDIO_FFMPEG) && !USE(WEBAUDIO_GSTREAMER) && !USE(WEBAUDIO_IPP) && !USE(WEBAUDIO_OPENMAX_DL_FFT)
 
 #include "FFTFrame.h"
 
diff --git a/Source/WebCore/platform/audio/chromium/FFTFrameOpenMAXDLAndroid.cpp b/Source/WebCore/platform/audio/chromium/FFTFrameOpenMAXDLAndroid.cpp
new file mode 100644
index 0000000..a8fd3a2
--- /dev/null
+++ b/Source/WebCore/platform/audio/chromium/FFTFrameOpenMAXDLAndroid.cpp
@@ -0,0 +1,202 @@
+/* Copyright (C) 2013 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#if OS(ANDROID) && USE(WEBAUDIO_OPENMAX_DL_FFT)
+
+#include "FFTFrame.h"
+
+#include "AudioArray.h"
+#include "VectorMath.h"
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+const int kMaxFFTPow2Size = 15;
+
+// Normal constructor: allocates for a given fftSize.
+FFTFrame::FFTFrame(unsigned fftSize)
+    : m_FFTSize(fftSize)
+    , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
+    , m_forwardContext(0)
+    , m_inverseContext(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_forwardContext = contextForSize(m_log2FFTSize);
+    m_inverseContext = contextForSize(m_log2FFTSize);
+}
+
+// Creates a blank/empty frame (interpolate() must later be called).
+FFTFrame::FFTFrame()
+    : m_FFTSize(0)
+    , m_log2FFTSize(0)
+    , m_forwardContext(0)
+    , m_inverseContext(0)
+{
+}
+
+// Copy constructor.
+FFTFrame::FFTFrame(const FFTFrame& frame)
+    : m_FFTSize(frame.m_FFTSize)
+    , m_log2FFTSize(frame.m_log2FFTSize)
+    , m_forwardContext(0)
+    , m_inverseContext(0)
+    , m_complexData(frame.m_FFTSize)
+    , m_realData(frame.m_FFTSize / 2)
+    , m_imagData(frame.m_FFTSize / 2)
+{
+    m_forwardContext = contextForSize(m_log2FFTSize);
+    m_inverseContext = contextForSize(m_log2FFTSize);
+
+    // Copy/setup frame data.
+    unsigned nbytes = sizeof(float) * (m_FFTSize / 2);
+    memcpy(realData(), frame.realData(), nbytes);
+    memcpy(imagData(), frame.imagData(), nbytes);
+}
+
+void FFTFrame::initialize()
+{
+}
+
+void FFTFrame::cleanup()
+{
+}
+
+FFTFrame::~FFTFrame()
+{
+    if (m_forwardContext)
+        free(m_forwardContext);
+    if (m_inverseContext)
+        free(m_inverseContext);
+}
+
+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();
+
+    unsigned halfSize = fftSize() / 2;
+    float real0 = realP1[0];
+    float imag0 = imagP1[0];
+
+    VectorMath::zvmul(realP1, imagP1, realP2, imagP2, realP1, imagP1, halfSize); 
+
+    // Multiply the packed DC/nyquist component
+    realP1[0] = real0 * realP2[0];
+    imagP1[0] = imag0 * imagP2[0];
+}
+
+void FFTFrame::doFFT(const float* data)
+{
+    ASSERT(m_forwardContext);
+
+    if (m_forwardContext) {
+        AudioFloatArray complexFFT(m_FFTSize + 2);
+
+        omxSP_FFTFwd_RToCCS_F32_Sfs(data, complexFFT.data(), m_forwardContext);
+
+        unsigned len = m_FFTSize / 2;
+
+        // Split FFT data into real and imaginary arrays.
+        for (unsigned k = 1; k < len; ++k) {
+            int index = 2 * k;
+            m_realData[k] = complexFFT[index];
+            m_imagData[k] = complexFFT[index + 1];
+        }
+        m_realData[0] = complexFFT[0];
+        m_imagData[0] = complexFFT[m_FFTSize];
+    }
+}
+
+void FFTFrame::doInverseFFT(float* data)
+{
+    ASSERT(m_inverseContext);
+
+    if (m_inverseContext) {
+        AudioFloatArray fftData(m_FFTSize + 2);
+
+        unsigned len = m_FFTSize / 2;
+
+        // Pack the real and imaginary data into the complex array format
+        for (unsigned k = 1; k < len; ++k) {
+            int index = 2 * k;
+            fftData[index] = m_realData[k];
+            fftData[index + 1] = m_imagData[k];
+        }
+        fftData[0] = m_realData[0];
+        fftData[1] = 0;
+        fftData[m_FFTSize] = m_imagData[0];
+        fftData[m_FFTSize + 1] = 0;
+    
+        omxSP_FFTInv_CCSToR_F32_Sfs(fftData.data(), data, m_inverseContext);
+    }
+}
+
+float* FFTFrame::realData() const
+{
+    return const_cast<float*>(m_realData.data());
+}
+
+float* FFTFrame::imagData() const
+{
+    return const_cast<float*>(m_imagData.data());
+}
+
+OMXFFTSpec_R_F32* FFTFrame::contextForSize(unsigned log2FFTSize)
+{
+    ASSERT(log2FFTSize);
+    ASSERT(log2FFTSize < kMaxFFTPow2Size);
+    int bufSize;
+    OMXResult status = omxSP_FFTGetBufSize_R_F32(log2FFTSize, &bufSize);
+
+    if (status == OMX_Sts_NoErr) {
+        OMXFFTSpec_R_F32* context = static_cast<OMXFFTSpec_R_F32*>(malloc(bufSize));
+        omxSP_FFTInit_R_F32(context, log2FFTSize);
+        return context;
+    }
+
+    return 0;
+}
+
+} // namespace WebCore
+
+#endif // #if OS(ANDROID) && !USE(WEBAUDIO_OPENMAX_DL_FFT)
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/Source/WebKit/chromium/ChangeLog b/Source/WebKit/chromium/ChangeLog
index 8cc5bd6..735e50d 100644
--- a/Source/WebKit/chromium/ChangeLog
+++ b/Source/WebKit/chromium/ChangeLog
@@ -1,3 +1,12 @@
+2013-04-02  Raymond Toy  <rtoy@google.com>
+
+        Add support for using ARM FFT in WebAudio
+        https://bugs.webkit.org/show_bug.cgi?id=109755
+
+        Reviewed by Chris Rogers.
+
+        * features.gypi: Support building with the OpenMAX DL FFT.
+
 2013-04-01  <webkit.review.bot@gmail.com>
 
         [chromium] Roll chromium deps to 191760.
diff --git a/Source/WebKit/chromium/features.gypi b/Source/WebKit/chromium/features.gypi
index 2dc0b23..c57227a 100644
--- a/Source/WebKit/chromium/features.gypi
+++ b/Source/WebKit/chromium/features.gypi
@@ -185,7 +185,6 @@
           # FIXME: Disable once the linking error has been resolved.
           # https://bugs.webkit.org/show_bug.cgi?id=88636
           'ENABLE_SHARED_WORKERS=1',
-          'ENABLE_WEB_AUDIO=0',
           'WTF_USE_NATIVE_FULLSCREEN_VIDEO=1',
         ],
         'enable_touch_icon_loading': 1,
@@ -232,6 +231,14 @@
           'WTF_USE_WEBAUDIO_FFMPEG=1',
         ],
       }],
+      ['OS=="android" and use_openmax_dl_fft!=0', {
+        'feature_defines': [
+          'WTF_USE_WEBAUDIO_OPENMAX_DL_FFT=1',
+          # Enabling the FFT is enough to enable WebAudio support to
+          # allow most WebAudio features to work on Android.
+          'ENABLE_WEB_AUDIO=1',
+        ],
+      }],
       ['OS=="win" or OS=="android" or use_x11==1', {
         'feature_defines': [
           'ENABLE_OPENTYPE_VERTICAL=1',