initial import
[vuplus_webkit] / Source / WebCore / platform / audio / mac / FFTFrameMac.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 // Mac OS X - specific FFTFrame implementation
30
31 #include "config.h"
32
33 #if ENABLE(WEB_AUDIO)
34
35 #if OS(DARWIN) && !USE(WEBAUDIO_FFMPEG)
36
37 #include "FFTFrame.h"
38
39 namespace WebCore {
40
41 const int kMaxFFTPow2Size = 24;
42
43 FFTSetup* FFTFrame::fftSetups = 0;
44
45 // Normal constructor: allocates for a given fftSize
46 FFTFrame::FFTFrame(unsigned fftSize)
47     : m_realData(fftSize)
48     , m_imagData(fftSize)
49 {
50     m_FFTSize = fftSize;
51     m_log2FFTSize = static_cast<unsigned>(log2(fftSize));
52
53     // We only allow power of two
54     ASSERT(1UL << m_log2FFTSize == m_FFTSize);
55
56     // Lazily create and share fftSetup with other frames
57     m_FFTSetup = fftSetupForSize(fftSize);
58
59     // Setup frame data
60     m_frame.realp = m_realData.data();
61     m_frame.imagp = m_imagData.data();
62 }
63
64 // Creates a blank/empty frame (interpolate() must later be called)
65 FFTFrame::FFTFrame()
66     : m_realData(0)
67     , m_imagData(0)
68 {
69     // Later will be set to correct values when interpolate() is called
70     m_frame.realp = 0;
71     m_frame.imagp = 0;
72
73     m_FFTSize = 0;
74     m_log2FFTSize = 0;
75 }
76
77 // Copy constructor
78 FFTFrame::FFTFrame(const FFTFrame& frame)
79     : m_FFTSize(frame.m_FFTSize)
80     , m_log2FFTSize(frame.m_log2FFTSize)
81     , m_FFTSetup(frame.m_FFTSetup)
82     , m_realData(frame.m_FFTSize)
83     , m_imagData(frame.m_FFTSize)
84 {
85     // Setup frame data
86     m_frame.realp = m_realData.data();
87     m_frame.imagp = m_imagData.data();
88
89     // Copy/setup frame data
90     unsigned nbytes = sizeof(float) * m_FFTSize;
91     memcpy(realData(), frame.m_frame.realp, nbytes);
92     memcpy(imagData(), frame.m_frame.imagp, nbytes);
93 }
94
95 FFTFrame::~FFTFrame()
96 {
97 }
98
99 void FFTFrame::multiply(const FFTFrame& frame)
100 {
101     FFTFrame& frame1 = *this;
102     const FFTFrame& frame2 = frame;
103
104     float* realP1 = frame1.realData();
105     float* imagP1 = frame1.imagData();
106     const float* realP2 = frame2.realData();
107     const float* imagP2 = frame2.imagData();
108
109     // Scale accounts for vecLib's peculiar scaling
110     // This ensures the right scaling all the way back to inverse FFT
111     float scale = 0.5f;
112
113     // Multiply packed DC/nyquist component
114     realP1[0] *= scale * realP2[0];
115     imagP1[0] *= scale * imagP2[0];
116
117     // Multiply the rest, skipping packed DC/Nyquist components
118     DSPSplitComplex sc1 = frame1.dspSplitComplex();
119     sc1.realp++;
120     sc1.imagp++;
121
122     DSPSplitComplex sc2 = frame2.dspSplitComplex();
123     sc2.realp++;
124     sc2.imagp++;
125
126     unsigned halfSize = m_FFTSize / 2;
127
128     // Complex multiply
129     vDSP_zvmul(&sc1, 1, &sc2, 1, &sc1, 1, halfSize - 1, 1 /* normal multiplication */);
130
131     // We've previously scaled the packed part, now scale the rest.....
132     vDSP_vsmul(sc1.realp, 1, &scale, sc1.realp, 1, halfSize - 1);
133     vDSP_vsmul(sc1.imagp, 1, &scale, sc1.imagp, 1, halfSize - 1);
134 }
135
136 void FFTFrame::doFFT(float* data)
137 {
138     vDSP_ctoz((DSPComplex*)data, 2, &m_frame, 1, m_FFTSize / 2);
139     vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_FORWARD);
140 }
141
142 void FFTFrame::doInverseFFT(float* data)
143 {
144     vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_INVERSE);
145     vDSP_ztoc(&m_frame, 1, (DSPComplex*)data, 2, m_FFTSize / 2);
146
147     // Do final scaling so that x == IFFT(FFT(x))
148     float scale = 0.5f / m_FFTSize;
149     vDSP_vsmul(data, 1, &scale, data, 1, m_FFTSize);
150 }
151
152 FFTSetup FFTFrame::fftSetupForSize(unsigned fftSize)
153 {
154     if (!fftSetups) {
155         fftSetups = (FFTSetup*)malloc(sizeof(FFTSetup) * kMaxFFTPow2Size);
156         memset(fftSetups, 0, sizeof(FFTSetup) * kMaxFFTPow2Size);
157     }
158
159     int pow2size = static_cast<int>(log2(fftSize));
160     ASSERT(pow2size < kMaxFFTPow2Size);
161     if (!fftSetups[pow2size])
162         fftSetups[pow2size] = vDSP_create_fftsetup(pow2size, FFT_RADIX2);
163
164     return fftSetups[pow2size];
165 }
166
167 void FFTFrame::initialize()
168 {
169 }
170
171 void FFTFrame::cleanup()
172 {
173     if (!fftSetups)
174         return;
175
176     for (int i = 0; i < kMaxFFTPow2Size; ++i) {
177         if (fftSetups[i])
178             vDSP_destroy_fftsetup(fftSetups[i]);
179     }
180
181     free(fftSetups);
182     fftSetups = 0;
183 }
184
185 float* FFTFrame::realData() const
186 {
187     return m_frame.realp;
188 }
189     
190 float* FFTFrame::imagData() const
191 {
192     return m_frame.imagp;
193 }
194
195 } // namespace WebCore
196
197 #endif // #if OS(DARWIN) && !USE(WEBAUDIO_FFMPEG)
198
199 #endif // ENABLE(WEB_AUDIO)