1 /* Copyright (C) 2013 Google Inc. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions 5 * are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "config.h" 26 27 #if ENABLE(WEB_AUDIO) 28 29 #if OS(ANDROID) && USE(WEBAUDIO_OPENMAX_DL_FFT) 30 31 #include "platform/audio/FFTFrame.h" 32 33 #include "platform/audio/AudioArray.h" 34 #include "wtf/MathExtras.h" 35 #include <dl/sp/api/armSP.h> 36 #include <dl/sp/api/omxSP.h> 37 38 namespace WebCore { 39 40 #if ASSERT_ENABLED 41 const unsigned kMaxFFTPow2Size = 15; 42 #endif 43 44 // Normal constructor: allocates for a given fftSize. 45 FFTFrame::FFTFrame(unsigned fftSize) 46 : m_FFTSize(fftSize) 47 , m_log2FFTSize(static_cast<unsigned>(log2(fftSize))) 48 , m_forwardContext(0) 49 , m_inverseContext(0) 50 , m_complexData(fftSize) 51 , m_realData(fftSize / 2) 52 , m_imagData(fftSize / 2) 53 { 54 // We only allow power of two. 55 ASSERT(1UL << m_log2FFTSize == m_FFTSize); 56 57 m_forwardContext = contextForSize(m_log2FFTSize); 58 m_inverseContext = contextForSize(m_log2FFTSize); 59 } 60 61 // Creates a blank/empty frame (interpolate() must later be called). 62 FFTFrame::FFTFrame() 63 : m_FFTSize(0) 64 , m_log2FFTSize(0) 65 , m_forwardContext(0) 66 , m_inverseContext(0) 67 { 68 } 69 70 // Copy constructor. 71 FFTFrame::FFTFrame(const FFTFrame& frame) 72 : m_FFTSize(frame.m_FFTSize) 73 , m_log2FFTSize(frame.m_log2FFTSize) 74 , m_forwardContext(0) 75 , m_inverseContext(0) 76 , m_complexData(frame.m_FFTSize) 77 , m_realData(frame.m_FFTSize / 2) 78 , m_imagData(frame.m_FFTSize / 2) 79 { 80 m_forwardContext = contextForSize(m_log2FFTSize); 81 m_inverseContext = contextForSize(m_log2FFTSize); 82 83 // Copy/setup frame data. 84 unsigned nbytes = sizeof(float) * (m_FFTSize / 2); 85 memcpy(realData(), frame.realData(), nbytes); 86 memcpy(imagData(), frame.imagData(), nbytes); 87 } 88 89 void FFTFrame::initialize() 90 { 91 } 92 93 void FFTFrame::cleanup() 94 { 95 } 96 97 FFTFrame::~FFTFrame() 98 { 99 if (m_forwardContext) 100 free(m_forwardContext); 101 if (m_inverseContext) 102 free(m_inverseContext); 103 } 104 105 void FFTFrame::doFFT(const float* data) 106 { 107 ASSERT(m_forwardContext); 108 109 if (m_forwardContext) { 110 AudioFloatArray complexFFT(m_FFTSize + 2); 111 112 omxSP_FFTFwd_RToCCS_F32(data, complexFFT.data(), m_forwardContext); 113 114 unsigned len = m_FFTSize / 2; 115 116 // Split FFT data into real and imaginary arrays. 117 const float* c = complexFFT.data(); 118 float* real = m_realData.data(); 119 float* imag = m_imagData.data(); 120 for (unsigned k = 1; k < len; ++k) { 121 int index = 2 * k; 122 real[k] = c[index]; 123 imag[k] = c[index + 1]; 124 } 125 real[0] = c[0]; 126 imag[0] = c[m_FFTSize]; 127 } 128 } 129 130 void FFTFrame::doInverseFFT(float* data) 131 { 132 ASSERT(m_inverseContext); 133 134 if (m_inverseContext) { 135 AudioFloatArray fftDataArray(m_FFTSize + 2); 136 137 unsigned len = m_FFTSize / 2; 138 139 // Pack the real and imaginary data into the complex array format 140 float* fftData = fftDataArray.data(); 141 const float* real = m_realData.data(); 142 const float* imag = m_imagData.data(); 143 for (unsigned k = 1; k < len; ++k) { 144 int index = 2 * k; 145 fftData[index] = real[k]; 146 fftData[index + 1] = imag[k]; 147 } 148 fftData[0] = real[0]; 149 fftData[1] = 0; 150 fftData[m_FFTSize] = imag[0]; 151 fftData[m_FFTSize + 1] = 0; 152 153 omxSP_FFTInv_CCSToR_F32(fftData, data, m_inverseContext); 154 } 155 } 156 157 float* FFTFrame::realData() const 158 { 159 return const_cast<float*>(m_realData.data()); 160 } 161 162 float* FFTFrame::imagData() const 163 { 164 return const_cast<float*>(m_imagData.data()); 165 } 166 167 OMXFFTSpec_R_F32* FFTFrame::contextForSize(unsigned log2FFTSize) 168 { 169 ASSERT(log2FFTSize); 170 ASSERT(log2FFTSize <= kMaxFFTPow2Size); 171 int bufSize; 172 OMXResult status = omxSP_FFTGetBufSize_R_F32(log2FFTSize, &bufSize); 173 174 if (status == OMX_Sts_NoErr) { 175 OMXFFTSpec_R_F32* context = static_cast<OMXFFTSpec_R_F32*>(malloc(bufSize)); 176 omxSP_FFTInit_R_F32(context, log2FFTSize); 177 return context; 178 } 179 180 return 0; 181 } 182 183 } // namespace WebCore 184 185 #endif // #if OS(ANDROID) && !USE(WEBAUDIO_OPENMAX_DL_FFT) 186 187 #endif // ENABLE(WEB_AUDIO) 188