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