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) 36 37 #include "platform/audio/FFTFrame.h" 38 39 #include "platform/audio/VectorMath.h" 40 41 namespace blink { 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_realData(frame.m_FFTSize) 84 , m_imagData(frame.m_FFTSize) 85 , m_FFTSetup(frame.m_FFTSetup) 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::doFFT(const float* data) 102 { 103 AudioFloatArray scaledData(m_FFTSize); 104 // veclib fft returns a result that is twice as large as would be expected. Compensate for that 105 // by scaling the input by half so the FFT has the correct scaling. 106 float scale = 0.5f; 107 VectorMath::vsmul(data, 1, &scale, scaledData.data(), 1, m_FFTSize); 108 109 vDSP_ctoz((DSPComplex*)scaledData.data(), 2, &m_frame, 1, m_FFTSize / 2); 110 vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_FORWARD); 111 } 112 113 void FFTFrame::doInverseFFT(float* data) 114 { 115 vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_INVERSE); 116 vDSP_ztoc(&m_frame, 1, (DSPComplex*)data, 2, m_FFTSize / 2); 117 118 // Do final scaling so that x == IFFT(FFT(x)) 119 float scale = 1.0f / m_FFTSize; 120 VectorMath::vsmul(data, 1, &scale, data, 1, m_FFTSize); 121 } 122 123 FFTSetup FFTFrame::fftSetupForSize(unsigned fftSize) 124 { 125 if (!fftSetups) { 126 fftSetups = (FFTSetup*)malloc(sizeof(FFTSetup) * kMaxFFTPow2Size); 127 memset(fftSetups, 0, sizeof(FFTSetup) * kMaxFFTPow2Size); 128 } 129 130 int pow2size = static_cast<int>(log2(fftSize)); 131 ASSERT(pow2size < kMaxFFTPow2Size); 132 if (!fftSetups[pow2size]) 133 fftSetups[pow2size] = vDSP_create_fftsetup(pow2size, FFT_RADIX2); 134 135 return fftSetups[pow2size]; 136 } 137 138 void FFTFrame::initialize() 139 { 140 } 141 142 void FFTFrame::cleanup() 143 { 144 if (!fftSetups) 145 return; 146 147 for (int i = 0; i < kMaxFFTPow2Size; ++i) { 148 if (fftSetups[i]) 149 vDSP_destroy_fftsetup(fftSetups[i]); 150 } 151 152 free(fftSetups); 153 fftSetups = 0; 154 } 155 156 } // namespace blink 157 158 #endif // #if OS(MACOSX) 159 160 #endif // ENABLE(WEB_AUDIO) 161