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 38namespace blink { 39 40#if ENABLE(ASSERT) 41const unsigned kMaxFFTPow2Size = 15; 42#endif 43 44// Normal constructor: allocates for a given fftSize. 45FFTFrame::FFTFrame(unsigned fftSize) 46 : m_FFTSize(fftSize) 47 , m_log2FFTSize(static_cast<unsigned>(log2(fftSize))) 48 , m_realData(fftSize / 2) 49 , m_imagData(fftSize / 2) 50 , m_forwardContext(0) 51 , m_inverseContext(0) 52 , m_complexData(fftSize) 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). 62FFTFrame::FFTFrame() 63 : m_FFTSize(0) 64 , m_log2FFTSize(0) 65 , m_forwardContext(0) 66 , m_inverseContext(0) 67{ 68} 69 70// Copy constructor. 71FFTFrame::FFTFrame(const FFTFrame& frame) 72 : m_FFTSize(frame.m_FFTSize) 73 , m_log2FFTSize(frame.m_log2FFTSize) 74 , m_realData(frame.m_FFTSize / 2) 75 , m_imagData(frame.m_FFTSize / 2) 76 , m_forwardContext(0) 77 , m_inverseContext(0) 78 , m_complexData(frame.m_FFTSize) 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 89void FFTFrame::initialize() 90{ 91} 92 93void FFTFrame::cleanup() 94{ 95} 96 97FFTFrame::~FFTFrame() 98{ 99 if (m_forwardContext) 100 free(m_forwardContext); 101 if (m_inverseContext) 102 free(m_inverseContext); 103} 104 105void 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 130void 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 157OMXFFTSpec_R_F32* FFTFrame::contextForSize(unsigned log2FFTSize) 158{ 159 ASSERT(log2FFTSize); 160 ASSERT(log2FFTSize <= kMaxFFTPow2Size); 161 int bufSize; 162 OMXResult status = omxSP_FFTGetBufSize_R_F32(log2FFTSize, &bufSize); 163 164 if (status == OMX_Sts_NoErr) { 165 OMXFFTSpec_R_F32* context = static_cast<OMXFFTSpec_R_F32*>(malloc(bufSize)); 166 omxSP_FFTInit_R_F32(context, log2FFTSize); 167 return context; 168 } 169 170 return 0; 171} 172 173} // namespace blink 174 175#endif // #if OS(ANDROID) && !USE(WEBAUDIO_OPENMAX_DL_FFT) 176 177#endif // ENABLE(WEB_AUDIO) 178