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 |