1/* 2 * Copyright (C) 2012 Igalia S.L 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19// FFTFrame implementation using the GStreamer FFT library. 20 21#include "config.h" 22 23#if USE(WEBAUDIO_GSTREAMER) 24 25#include "FFTFrame.h" 26 27#include "VectorMath.h" 28#include <wtf/FastAllocBase.h> 29 30namespace { 31 32size_t unpackedFFTDataSize(unsigned fftSize) 33{ 34 return fftSize / 2 + 1; 35} 36 37} // anonymous namespace 38 39namespace WebCore { 40 41// Normal constructor: allocates for a given fftSize. 42FFTFrame::FFTFrame(unsigned fftSize) 43 : m_FFTSize(fftSize) 44 , m_log2FFTSize(static_cast<unsigned>(log2(fftSize))) 45 , m_realData(unpackedFFTDataSize(m_FFTSize)) 46 , m_imagData(unpackedFFTDataSize(m_FFTSize)) 47{ 48 m_complexData = WTF::fastNewArray<GstFFTF32Complex>(unpackedFFTDataSize(m_FFTSize)); 49 50 int fftLength = gst_fft_next_fast_length(m_FFTSize); 51 m_fft = gst_fft_f32_new(fftLength, FALSE); 52 m_inverseFft = gst_fft_f32_new(fftLength, TRUE); 53} 54 55// Creates a blank/empty frame (interpolate() must later be called). 56FFTFrame::FFTFrame() 57 : m_FFTSize(0) 58 , m_log2FFTSize(0) 59 , m_complexData(0) 60{ 61 int fftLength = gst_fft_next_fast_length(m_FFTSize); 62 m_fft = gst_fft_f32_new(fftLength, FALSE); 63 m_inverseFft = gst_fft_f32_new(fftLength, TRUE); 64} 65 66// Copy constructor. 67FFTFrame::FFTFrame(const FFTFrame& frame) 68 : m_FFTSize(frame.m_FFTSize) 69 , m_log2FFTSize(frame.m_log2FFTSize) 70 , m_realData(unpackedFFTDataSize(frame.m_FFTSize)) 71 , m_imagData(unpackedFFTDataSize(frame.m_FFTSize)) 72{ 73 m_complexData = WTF::fastNewArray<GstFFTF32Complex>(unpackedFFTDataSize(m_FFTSize)); 74 75 int fftLength = gst_fft_next_fast_length(m_FFTSize); 76 m_fft = gst_fft_f32_new(fftLength, FALSE); 77 m_inverseFft = gst_fft_f32_new(fftLength, TRUE); 78 79 // Copy/setup frame data. 80 memcpy(realData(), frame.realData(), sizeof(float) * unpackedFFTDataSize(m_FFTSize)); 81 memcpy(imagData(), frame.imagData(), sizeof(float) * unpackedFFTDataSize(m_FFTSize)); 82} 83 84void FFTFrame::initialize() 85{ 86} 87 88void FFTFrame::cleanup() 89{ 90} 91 92FFTFrame::~FFTFrame() 93{ 94 if (!m_fft) 95 return; 96 97 gst_fft_f32_free(m_fft); 98 m_fft = 0; 99 100 gst_fft_f32_free(m_inverseFft); 101 m_inverseFft = 0; 102 103 WTF::fastDeleteArray(m_complexData); 104} 105 106void FFTFrame::multiply(const FFTFrame& frame) 107{ 108 FFTFrame& frame1 = *this; 109 FFTFrame& frame2 = const_cast<FFTFrame&>(frame); 110 111 float* realP1 = frame1.realData(); 112 float* imagP1 = frame1.imagData(); 113 const float* realP2 = frame2.realData(); 114 const float* imagP2 = frame2.imagData(); 115 116 size_t size = unpackedFFTDataSize(m_FFTSize); 117 VectorMath::zvmul(realP1, imagP1, realP2, imagP2, realP1, imagP1, size); 118 119 // Scale accounts the peculiar scaling of vecLib on the Mac. 120 // This ensures the right scaling all the way back to inverse FFT. 121 // FIXME: if we change the scaling on the Mac then this scale 122 // factor will need to change too. 123 float scale = 0.5f; 124 125 VectorMath::vsmul(realP1, 1, &scale, realP1, 1, size); 126 VectorMath::vsmul(imagP1, 1, &scale, imagP1, 1, size); 127} 128 129void FFTFrame::doFFT(const float* data) 130{ 131 gst_fft_f32_fft(m_fft, data, m_complexData); 132 133 // Scale the frequency domain data to match vecLib's scale factor 134 // on the Mac. FIXME: if we change the definition of FFTFrame to 135 // eliminate this scale factor then this code will need to change. 136 // Also, if this loop turns out to be hot then we should use SSE 137 // or other intrinsics to accelerate it. 138 float scaleFactor = 2; 139 140 float* imagData = m_imagData.data(); 141 float* realData = m_realData.data(); 142 for (unsigned i = 0; i < unpackedFFTDataSize(m_FFTSize); ++i) { 143 imagData[i] = m_complexData[i].i * scaleFactor; 144 realData[i] = m_complexData[i].r * scaleFactor; 145 } 146} 147 148void FFTFrame::doInverseFFT(float* data) 149{ 150 // Merge the real and imaginary vectors to complex vector. 151 float* realData = m_realData.data(); 152 float* imagData = m_imagData.data(); 153 154 for (size_t i = 0; i < unpackedFFTDataSize(m_FFTSize); ++i) { 155 m_complexData[i].i = imagData[i]; 156 m_complexData[i].r = realData[i]; 157 } 158 159 gst_fft_f32_inverse_fft(m_inverseFft, m_complexData, data); 160 161 // Scale so that a forward then inverse FFT yields exactly the original data. 162 const float scaleFactor = 1.0 / (2 * m_FFTSize); 163 VectorMath::vsmul(data, 1, &scaleFactor, data, 1, m_FFTSize); 164} 165 166float* FFTFrame::realData() const 167{ 168 return const_cast<float*>(m_realData.data()); 169} 170 171float* FFTFrame::imagData() const 172{ 173 return const_cast<float*>(m_imagData.data()); 174} 175 176} // namespace WebCore 177 178#endif // USE(WEBAUDIO_GSTREAMER) 179