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