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