tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / platform / audio / FFTFrame.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30
31 #if ENABLE(WEB_AUDIO)
32
33 #include "FFTFrame.h"
34
35 #ifndef NDEBUG
36 #include <stdio.h>
37 #endif
38
39 #include "Logging.h"
40 #include <wtf/Complex.h>
41 #include <wtf/MathExtras.h>
42 #include <wtf/OwnPtr.h>
43
44 namespace WebCore {
45
46 void FFTFrame::doPaddedFFT(const float* data, size_t dataSize)
47 {
48     // Zero-pad the impulse response
49     AudioFloatArray paddedResponse(fftSize()); // zero-initialized
50     paddedResponse.copyToRange(data, 0, dataSize);
51
52     // Get the frequency-domain version of padded response
53     doFFT(paddedResponse.data());
54 }
55
56 PassOwnPtr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
57 {
58     OwnPtr<FFTFrame> newFrame = adoptPtr(new FFTFrame(frame1.fftSize()));
59
60     newFrame->interpolateFrequencyComponents(frame1, frame2, x);
61
62     // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
63     int fftSize = newFrame->fftSize();
64     AudioFloatArray buffer(fftSize);
65     newFrame->doInverseFFT(buffer.data());
66     buffer.zeroRange(fftSize / 2, fftSize);
67
68     // Put back into frequency domain.
69     newFrame->doFFT(buffer.data());
70
71     return newFrame.release();
72 }
73
74 void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
75 {
76     // FIXME : with some work, this method could be optimized
77
78     float* realP = realData();
79     float* imagP = imagData();
80
81     const float* realP1 = frame1.realData();
82     const float* imagP1 = frame1.imagData();
83     const float* realP2 = frame2.realData();
84     const float* imagP2 = frame2.imagData();
85
86     m_FFTSize = frame1.fftSize();
87     m_log2FFTSize = frame1.log2FFTSize();
88
89     double s1base = (1.0 - interp);
90     double s2base = interp;
91
92     double phaseAccum = 0.0;
93     double lastPhase1 = 0.0;
94     double lastPhase2 = 0.0;
95
96     realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
97     imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);
98
99     int n = m_FFTSize / 2;
100
101     for (int i = 1; i < n; ++i) {
102         Complex c1(realP1[i], imagP1[i]);
103         Complex c2(realP2[i], imagP2[i]);
104
105         double mag1 = abs(c1);
106         double mag2 = abs(c2);
107
108         // Interpolate magnitudes in decibels
109         double mag1db = 20.0 * log10(mag1);
110         double mag2db = 20.0 * log10(mag2);
111
112         double s1 = s1base;
113         double s2 = s2base;
114
115         double magdbdiff = mag1db - mag2db;
116
117         // Empirical tweak to retain higher-frequency zeroes
118         double threshold =  (i > 16) ? 5.0 : 2.0;
119
120         if (magdbdiff < -threshold && mag1db < 0.0) {
121             s1 = pow(s1, 0.75);
122             s2 = 1.0 - s1;
123         } else if (magdbdiff > threshold && mag2db < 0.0) {
124             s2 = pow(s2, 0.75);
125             s1 = 1.0 - s2;
126         }
127
128         // Average magnitude by decibels instead of linearly
129         double magdb = s1 * mag1db + s2 * mag2db;
130         double mag = pow(10.0, 0.05 * magdb);
131
132         // Now, deal with phase
133         double phase1 = arg(c1);
134         double phase2 = arg(c2);
135
136         double deltaPhase1 = phase1 - lastPhase1;
137         double deltaPhase2 = phase2 - lastPhase2;
138         lastPhase1 = phase1;
139         lastPhase2 = phase2;
140
141         // Unwrap phase deltas
142         if (deltaPhase1 > piDouble)
143             deltaPhase1 -= 2.0 * piDouble;
144         if (deltaPhase1 < -piDouble)
145             deltaPhase1 += 2.0 * piDouble;
146         if (deltaPhase2 > piDouble)
147             deltaPhase2 -= 2.0 * piDouble;
148         if (deltaPhase2 < -piDouble)
149             deltaPhase2 += 2.0 * piDouble;
150
151         // Blend group-delays
152         double deltaPhaseBlend;
153
154         if (deltaPhase1 - deltaPhase2 > piDouble)
155             deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * piDouble + deltaPhase2);
156         else if (deltaPhase2 - deltaPhase1 > piDouble)
157             deltaPhaseBlend = s1 * (2.0 * piDouble + deltaPhase1) + s2 * deltaPhase2;
158         else
159             deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
160
161         phaseAccum += deltaPhaseBlend;
162
163         // Unwrap
164         if (phaseAccum > piDouble)
165             phaseAccum -= 2.0 * piDouble;
166         if (phaseAccum < -piDouble)
167             phaseAccum += 2.0 * piDouble;
168
169         Complex c = complexFromMagnitudePhase(mag, phaseAccum);
170
171         realP[i] = static_cast<float>(c.real());
172         imagP[i] = static_cast<float>(c.imag());
173     }
174 }
175
176 double FFTFrame::extractAverageGroupDelay()
177 {
178     float* realP = realData();
179     float* imagP = imagData();
180
181     double aveSum = 0.0;
182     double weightSum = 0.0;
183     double lastPhase = 0.0;
184
185     int halfSize = fftSize() / 2;
186
187     const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
188
189     // Calculate weighted average group delay
190     for (int i = 0; i < halfSize; i++) {
191         Complex c(realP[i], imagP[i]);
192         double mag = abs(c);
193         double phase = arg(c);
194
195         double deltaPhase = phase - lastPhase;
196         lastPhase = phase;
197
198         // Unwrap
199         if (deltaPhase < -piDouble)
200             deltaPhase += 2.0 * piDouble;
201         if (deltaPhase > piDouble)
202             deltaPhase -= 2.0 * piDouble;
203
204         aveSum += mag * deltaPhase;
205         weightSum += mag;
206     }
207
208     // Note how we invert the phase delta wrt frequency since this is how group delay is defined
209     double ave = aveSum / weightSum;
210     double aveSampleDelay = -ave / kSamplePhaseDelay;
211
212     // Leave 20 sample headroom (for leading edge of impulse)
213     if (aveSampleDelay > 20.0)
214         aveSampleDelay -= 20.0;
215
216     // Remove average group delay (minus 20 samples for headroom)
217     addConstantGroupDelay(-aveSampleDelay);
218
219     // Remove DC offset
220     realP[0] = 0.0f;
221
222     return aveSampleDelay;
223 }
224
225 void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
226 {
227     int halfSize = fftSize() / 2;
228
229     float* realP = realData();
230     float* imagP = imagData();
231
232     const double kSamplePhaseDelay = (2.0 * piDouble) / double(fftSize());
233
234     double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
235
236     // Add constant group delay
237     for (int i = 1; i < halfSize; i++) {
238         Complex c(realP[i], imagP[i]);
239         double mag = abs(c);
240         double phase = arg(c);
241
242         phase += i * phaseAdj;
243
244         Complex c2 = complexFromMagnitudePhase(mag, phase);
245
246         realP[i] = static_cast<float>(c2.real());
247         imagP[i] = static_cast<float>(c2.imag());
248     }
249 }
250
251 #ifndef NDEBUG
252 void FFTFrame::print()
253 {
254     FFTFrame& frame = *this;
255     float* realP = frame.realData();
256     float* imagP = frame.imagData();
257     LOG(WebAudio, "**** \n");
258     LOG(WebAudio, "DC = %f : nyquist = %f\n", realP[0], imagP[0]);
259
260     int n = m_FFTSize / 2;
261
262     for (int i = 1; i < n; i++) {
263         double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]);
264         double phase = atan2(realP[i], imagP[i]);
265
266         LOG(WebAudio, "[%d] (%f %f)\n", i, mag, phase);
267     }
268     LOG(WebAudio, "****\n");
269 }
270 #endif // NDEBUG
271
272 } // namespace WebCore
273
274 #endif // ENABLE(WEB_AUDIO)