15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Google Inc. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met: 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * documentation and/or other materials provided with the distribution. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// FFTFrame implementation using FFmpeg's RDFT algorithm, 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// suitable for use on Windows and Linux. 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if ENABLE(WEB_AUDIO) 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if USE(WEBAUDIO_FFMPEG) 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/FFTFrame.h" 365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 371e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/VectorMath.h" 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)extern "C" { 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) #include <libavcodec/avfft.h> 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MathExtras.h" 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 45c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 47197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT) 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const int kMaxFFTPow2Size = 24; 4919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#endif 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Normal constructor: allocates for a given fftSize. 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::FFTFrame(unsigned fftSize) 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : m_FFTSize(fftSize) 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_log2FFTSize(static_cast<unsigned>(log2(fftSize))) 557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci , m_realData(fftSize / 2) 567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci , m_imagData(fftSize / 2) 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_forwardContext(0) 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_inverseContext(0) 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_complexData(fftSize) 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We only allow power of two. 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(1UL << m_log2FFTSize == m_FFTSize); 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_forwardContext = contextForSize(fftSize, DFT_R2C); 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_inverseContext = contextForSize(fftSize, IDFT_C2R); 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Creates a blank/empty frame (interpolate() must later be called). 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::FFTFrame() 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : m_FFTSize(0) 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_log2FFTSize(0) 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_forwardContext(0) 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_inverseContext(0) 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copy constructor. 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::FFTFrame(const FFTFrame& frame) 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : m_FFTSize(frame.m_FFTSize) 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_log2FFTSize(frame.m_log2FFTSize) 817242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci , m_realData(frame.m_FFTSize / 2) 827242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci , m_imagData(frame.m_FFTSize / 2) 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_forwardContext(0) 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_inverseContext(0) 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_complexData(frame.m_FFTSize) 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_forwardContext = contextForSize(m_FFTSize, DFT_R2C); 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_inverseContext = contextForSize(m_FFTSize, IDFT_C2R); 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Copy/setup frame data. 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned nbytes = sizeof(float) * (m_FFTSize / 2); 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) memcpy(realData(), frame.realData(), nbytes); 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) memcpy(imagData(), frame.imagData(), nbytes); 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::initialize() 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::cleanup() 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::~FFTFrame() 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) av_rdft_end(m_forwardContext); 1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) av_rdft_end(m_inverseContext); 1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::doFFT(const float* data) 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Copy since processing is in-place. 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float* p = m_complexData.data(); 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) memcpy(p, data, sizeof(float) * m_FFTSize); 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Compute Forward transform. 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) av_rdft_calc(m_forwardContext, p); 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // De-interleave to separate real and complex arrays. 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int len = m_FFTSize / 2; 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 12209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) float* real = m_realData.data(); 12309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) float* imag = m_imagData.data(); 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < len; ++i) { 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int baseComplexIndex = 2 * i; 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // m_realData[0] is the DC component and m_imagData[0] is the nyquist component 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // since the interleaved complex data is packed. 128d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) real[i] = p[baseComplexIndex]; 129d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) imag[i] = p[baseComplexIndex + 1]; 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::doInverseFFT(float* data) 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Prepare interleaved data. 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) float* interleavedData = getUpToDateComplexData(); 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Compute inverse transform. 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) av_rdft_calc(m_inverseContext, interleavedData); 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 141d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) // Scale so that a forward then inverse FFT yields exactly the original data. For some reason 142d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) // av_rdft_calc above returns values that are half of what I expect. Hence make the scale factor 143d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) // twice as large to compensate for that. 144d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) const float scale = 2.0 / m_FFTSize; 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) VectorMath::vsmul(interleavedData, 1, &scale, data, 1, m_FFTSize); 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float* FFTFrame::getUpToDateComplexData() 1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: if we can't completely get rid of this method, SSE 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // optimization could be considered if it shows up hot on profiles. 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int len = m_FFTSize / 2; 15309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) const float* real = m_realData.data(); 15409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) const float* imag = m_imagData.data(); 15509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) float* c = m_complexData.data(); 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (int i = 0; i < len; ++i) { 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int baseComplexIndex = 2 * i; 15809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) c[baseComplexIndex] = real[i]; 15909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) c[baseComplexIndex + 1] = imag[i]; 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return const_cast<float*>(m_complexData.data()); 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RDFTContext* FFTFrame::contextForSize(unsigned fftSize, int trans) 1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: This is non-optimal. Ideally, we'd like to share the contexts for FFTFrames of the same size. 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // But FFmpeg's RDFT uses a scratch buffer inside the context and so they are not thread-safe. 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We could improve this by sharing the FFTFrames on a per-thread basis. 1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(fftSize); 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int pow2size = static_cast<int>(log2(fftSize)); 1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(pow2size < kMaxFFTPow2Size); 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RDFTContext* context = av_rdft_init(pow2size, (RDFTransformType)trans); 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return context; 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 177c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 17909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#endif // USE(WEBAUDIO_FFMPEG) 1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // ENABLE(WEB_AUDIO) 182