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)
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/audio/FFTFrame.h"
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/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)
45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)namespace {
46926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
47926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)struct FFTComplexProxy {
48926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int16_t re;
49926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int16_t im;
50926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)};
51926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
52926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)struct FFTContextProxy {
53926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int nbits;
54926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int inverse;
55926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    uint16_t* revtab;
56926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    FFTComplexProxy* tmpBuf;
57926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int mdctSize;
58926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int mdctBits;
59926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void* tcos;
60926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void* tsin;
61926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*fftPermute)();
62926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*fftCalc)();
63926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*imdctCalc)();
64926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*imdctHalf)();
65926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*mdctCalc)();
66926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*mdctCalcw)();
67926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int fftPermutation;
68926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int mdctPermutation;
69926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)};
70926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
71926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)struct RDFTContextProxy {
72926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int nbits;
73926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int inverse;
74926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    int signConvention;
75926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    const void* tcos;
76926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    const void* tsin;
77926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    FFTContextProxy fft;
78926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    void (*rdft_calc)();
79926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)};
80926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
81926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
82926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const int kMaxFFTPow2Size = 24;
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Normal constructor: allocates for a given fftSize.
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::FFTFrame(unsigned fftSize)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_FFTSize(fftSize)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_forwardContext(0)
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_inverseContext(0)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_complexData(fftSize)
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_realData(fftSize / 2)
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_imagData(fftSize / 2)
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We only allow power of two.
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(1UL << m_log2FFTSize == m_FFTSize);
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_forwardContext = contextForSize(fftSize, DFT_R2C);
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_inverseContext = contextForSize(fftSize, IDFT_C2R);
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Creates a blank/empty frame (interpolate() must later be called).
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::FFTFrame()
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_FFTSize(0)
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_log2FFTSize(0)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_forwardContext(0)
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_inverseContext(0)
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copy constructor.
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::FFTFrame(const FFTFrame& frame)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_FFTSize(frame.m_FFTSize)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_log2FFTSize(frame.m_log2FFTSize)
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_forwardContext(0)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_inverseContext(0)
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_complexData(frame.m_FFTSize)
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_realData(frame.m_FFTSize / 2)
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_imagData(frame.m_FFTSize / 2)
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_forwardContext = contextForSize(m_FFTSize, DFT_R2C);
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_inverseContext = contextForSize(m_FFTSize, IDFT_C2R);
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Copy/setup frame data.
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned nbytes = sizeof(float) * (m_FFTSize / 2);
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memcpy(realData(), frame.realData(), nbytes);
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memcpy(imagData(), frame.imagData(), nbytes);
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::initialize()
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::cleanup()
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FFTFrame::~FFTFrame()
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    av_rdft_end(m_forwardContext);
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    av_rdft_end(m_inverseContext);
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::multiply(const FFTFrame& frame)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FFTFrame& frame1 = *this;
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FFTFrame& frame2 = const_cast<FFTFrame&>(frame);
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* realP1 = frame1.realData();
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* imagP1 = frame1.imagData();
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const float* realP2 = frame2.realData();
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const float* imagP2 = frame2.imagData();
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned halfSize = fftSize() / 2;
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float real0 = realP1[0];
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float imag0 = imagP1[0];
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
16002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    VectorMath::zvmul(realP1, imagP1, realP2, imagP2, realP1, imagP1, halfSize);
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Multiply the packed DC/nyquist component
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    realP1[0] = real0 * realP2[0];
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    imagP1[0] = imag0 * imagP2[0];
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Scale accounts the peculiar scaling of vecLib on the Mac.
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This ensures the right scaling all the way back to inverse FFT.
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: if we change the scaling on the Mac then this scale
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // factor will need to change too.
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float scale = 0.5f;
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    VectorMath::vsmul(realP1, 1, &scale, realP1, 1, halfSize);
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    VectorMath::vsmul(imagP1, 1, &scale, imagP1, 1, halfSize);
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::doFFT(const float* data)
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Copy since processing is in-place.
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* p = m_complexData.data();
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memcpy(p, data, sizeof(float) * m_FFTSize);
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compute Forward transform.
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    av_rdft_calc(m_forwardContext, p);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // De-interleave to separate real and complex arrays.
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int len = m_FFTSize / 2;
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: see above comment in multiply() about scaling.
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const float scale = 2.0f;
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = 0; i < len; ++i) {
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int baseComplexIndex = 2 * i;
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // m_realData[0] is the DC component and m_imagData[0] is the nyquist component
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // since the interleaved complex data is packed.
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_realData[i] = scale * p[baseComplexIndex];
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_imagData[i] = scale * p[baseComplexIndex + 1];
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FFTFrame::doInverseFFT(float* data)
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Prepare interleaved data.
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* interleavedData = getUpToDateComplexData();
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Compute inverse transform.
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    av_rdft_calc(m_inverseContext, interleavedData);
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Scale so that a forward then inverse FFT yields exactly the original data.
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const float scale = 1.0 / m_FFTSize;
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    VectorMath::vsmul(interleavedData, 1, &scale, data, 1, m_FFTSize);
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float* FFTFrame::realData() const
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return const_cast<float*>(m_realData.data());
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float* FFTFrame::imagData() const
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return const_cast<float*>(m_imagData.data());
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float* FFTFrame::getUpToDateComplexData()
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: if we can't completely get rid of this method, SSE
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // optimization could be considered if it shows up hot on profiles.
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int len = m_FFTSize / 2;
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = 0; i < len; ++i) {
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int baseComplexIndex = 2 * i;
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_complexData[baseComplexIndex] = m_realData[i];
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_complexData[baseComplexIndex + 1] = m_imagData[i];
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return const_cast<float*>(m_complexData.data());
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RDFTContext* FFTFrame::contextForSize(unsigned fftSize, int trans)
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: This is non-optimal. Ideally, we'd like to share the contexts for FFTFrames of the same size.
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // But FFmpeg's RDFT uses a scratch buffer inside the context and so they are not thread-safe.
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // We could improve this by sharing the FFTFrames on a per-thread basis.
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(fftSize);
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int pow2size = static_cast<int>(log2(fftSize));
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(pow2size < kMaxFFTPow2Size);
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    RDFTContext* context = av_rdft_init(pow2size, (RDFTransformType)trans);
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return context;
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // !OS(DARWIN) && USE(WEBAUDIO_FFMPEG)
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // ENABLE(WEB_AUDIO)
254