| OLD | NEW |
| (Empty) |
| 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 "platform/audio/VectorMath.h" | |
| 35 #include "wtf/MathExtras.h" | |
| 36 #include <dl/sp/api/armSP.h> | |
| 37 #include <dl/sp/api/omxSP.h> | |
| 38 | |
| 39 namespace WebCore { | |
| 40 | |
| 41 #if !ASSERT_DISABLED | |
| 42 const unsigned kMaxFFTPow2Size = 15; | |
| 43 #endif | |
| 44 | |
| 45 // Normal constructor: allocates for a given fftSize. | |
| 46 FFTFrame::FFTFrame(unsigned fftSize) | |
| 47 : m_FFTSize(fftSize) | |
| 48 , m_log2FFTSize(static_cast<unsigned>(log2(fftSize))) | |
| 49 , m_forwardContext(0) | |
| 50 , m_inverseContext(0) | |
| 51 , m_complexData(fftSize) | |
| 52 , m_realData(fftSize / 2) | |
| 53 , m_imagData(fftSize / 2) | |
| 54 { | |
| 55 // We only allow power of two. | |
| 56 ASSERT(1UL << m_log2FFTSize == m_FFTSize); | |
| 57 | |
| 58 m_forwardContext = contextForSize(m_log2FFTSize); | |
| 59 m_inverseContext = contextForSize(m_log2FFTSize); | |
| 60 } | |
| 61 | |
| 62 // Creates a blank/empty frame (interpolate() must later be called). | |
| 63 FFTFrame::FFTFrame() | |
| 64 : m_FFTSize(0) | |
| 65 , m_log2FFTSize(0) | |
| 66 , m_forwardContext(0) | |
| 67 , m_inverseContext(0) | |
| 68 { | |
| 69 } | |
| 70 | |
| 71 // Copy constructor. | |
| 72 FFTFrame::FFTFrame(const FFTFrame& frame) | |
| 73 : m_FFTSize(frame.m_FFTSize) | |
| 74 , m_log2FFTSize(frame.m_log2FFTSize) | |
| 75 , m_forwardContext(0) | |
| 76 , m_inverseContext(0) | |
| 77 , m_complexData(frame.m_FFTSize) | |
| 78 , m_realData(frame.m_FFTSize / 2) | |
| 79 , m_imagData(frame.m_FFTSize / 2) | |
| 80 { | |
| 81 m_forwardContext = contextForSize(m_log2FFTSize); | |
| 82 m_inverseContext = contextForSize(m_log2FFTSize); | |
| 83 | |
| 84 // Copy/setup frame data. | |
| 85 unsigned nbytes = sizeof(float) * (m_FFTSize / 2); | |
| 86 memcpy(realData(), frame.realData(), nbytes); | |
| 87 memcpy(imagData(), frame.imagData(), nbytes); | |
| 88 } | |
| 89 | |
| 90 void FFTFrame::initialize() | |
| 91 { | |
| 92 } | |
| 93 | |
| 94 void FFTFrame::cleanup() | |
| 95 { | |
| 96 } | |
| 97 | |
| 98 FFTFrame::~FFTFrame() | |
| 99 { | |
| 100 if (m_forwardContext) | |
| 101 free(m_forwardContext); | |
| 102 if (m_inverseContext) | |
| 103 free(m_inverseContext); | |
| 104 } | |
| 105 | |
| 106 void FFTFrame::multiply(const FFTFrame& frame) | |
| 107 { | |
| 108 FFTFrame& frame1 = *this; | |
| 109 FFTFrame& frame2 = const_cast<FFTFrame&>(frame); | |
| 110 | |
| 111 float* realP1 = frame1.realData(); | |
| 112 float* imagP1 = frame1.imagData(); | |
| 113 const float* realP2 = frame2.realData(); | |
| 114 const float* imagP2 = frame2.imagData(); | |
| 115 | |
| 116 unsigned halfSize = fftSize() / 2; | |
| 117 float real0 = realP1[0]; | |
| 118 float imag0 = imagP1[0]; | |
| 119 | |
| 120 VectorMath::zvmul(realP1, imagP1, realP2, imagP2, realP1, imagP1, halfSize); | |
| 121 | |
| 122 // Multiply the packed DC/nyquist component | |
| 123 realP1[0] = real0 * realP2[0]; | |
| 124 imagP1[0] = imag0 * imagP2[0]; | |
| 125 } | |
| 126 | |
| 127 void FFTFrame::doFFT(const float* data) | |
| 128 { | |
| 129 ASSERT(m_forwardContext); | |
| 130 | |
| 131 if (m_forwardContext) { | |
| 132 AudioFloatArray complexFFT(m_FFTSize + 2); | |
| 133 | |
| 134 omxSP_FFTFwd_RToCCS_F32(data, complexFFT.data(), m_forwardContext); | |
| 135 | |
| 136 unsigned len = m_FFTSize / 2; | |
| 137 | |
| 138 // Split FFT data into real and imaginary arrays. | |
| 139 const float* c = complexFFT.data(); | |
| 140 float* real = m_realData.data(); | |
| 141 float* imag = m_imagData.data(); | |
| 142 for (unsigned k = 1; k < len; ++k) { | |
| 143 int index = 2 * k; | |
| 144 real[k] = c[index]; | |
| 145 imag[k] = c[index + 1]; | |
| 146 } | |
| 147 real[0] = c[0]; | |
| 148 imag[0] = c[m_FFTSize]; | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 void FFTFrame::doInverseFFT(float* data) | |
| 153 { | |
| 154 ASSERT(m_inverseContext); | |
| 155 | |
| 156 if (m_inverseContext) { | |
| 157 AudioFloatArray fftDataArray(m_FFTSize + 2); | |
| 158 | |
| 159 unsigned len = m_FFTSize / 2; | |
| 160 | |
| 161 // Pack the real and imaginary data into the complex array format | |
| 162 float* fftData = fftDataArray.data(); | |
| 163 const float* real = m_realData.data(); | |
| 164 const float* imag = m_imagData.data(); | |
| 165 for (unsigned k = 1; k < len; ++k) { | |
| 166 int index = 2 * k; | |
| 167 fftData[index] = real[k]; | |
| 168 fftData[index + 1] = imag[k]; | |
| 169 } | |
| 170 fftData[0] = real[0]; | |
| 171 fftData[1] = 0; | |
| 172 fftData[m_FFTSize] = imag[0]; | |
| 173 fftData[m_FFTSize + 1] = 0; | |
| 174 | |
| 175 omxSP_FFTInv_CCSToR_F32(fftData, data, m_inverseContext); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 float* FFTFrame::realData() const | |
| 180 { | |
| 181 return const_cast<float*>(m_realData.data()); | |
| 182 } | |
| 183 | |
| 184 float* FFTFrame::imagData() const | |
| 185 { | |
| 186 return const_cast<float*>(m_imagData.data()); | |
| 187 } | |
| 188 | |
| 189 OMXFFTSpec_R_F32* FFTFrame::contextForSize(unsigned log2FFTSize) | |
| 190 { | |
| 191 ASSERT(log2FFTSize); | |
| 192 ASSERT(log2FFTSize <= kMaxFFTPow2Size); | |
| 193 int bufSize; | |
| 194 OMXResult status = omxSP_FFTGetBufSize_R_F32(log2FFTSize, &bufSize); | |
| 195 | |
| 196 if (status == OMX_Sts_NoErr) { | |
| 197 OMXFFTSpec_R_F32* context = static_cast<OMXFFTSpec_R_F32*>(malloc(bufSiz
e)); | |
| 198 omxSP_FFTInit_R_F32(context, log2FFTSize); | |
| 199 return context; | |
| 200 } | |
| 201 | |
| 202 return 0; | |
| 203 } | |
| 204 | |
| 205 } // namespace WebCore | |
| 206 | |
| 207 #endif // #if OS(ANDROID) && !USE(WEBAUDIO_OPENMAX_DL_FFT) | |
| 208 | |
| 209 #endif // ENABLE(WEB_AUDIO) | |
| OLD | NEW |