1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27// FFTFrame implementation using Intel IPP's DFT algorithm,
28// suitable for use on Linux.
29
30#include "config.h"
31
32#if ENABLE(WEB_AUDIO)
33
34#if USE(WEBAUDIO_IPP)
35
36#include "platform/audio/FFTFrame.h"
37
38#include "wtf/MathExtras.h"
39
40namespace blink {
41
42const unsigned maximumFFTPower2Size = 24;
43
44// Normal constructor: allocates for a given fftSize.
45FFTFrame::FFTFrame(unsigned fftSize)
46    : m_FFTSize(fftSize)
47    , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
48    , m_realData(fftSize / 2)
49    , m_imagData(fftSize / 2)
50    , m_complexData(fftSize)
51{
52    // We only allow power of two.
53    ASSERT(1UL << m_log2FFTSize == m_FFTSize);
54    ASSERT(m_log2FFTSize <= maximumFFTPower2Size);
55
56    ippsDFTInitAlloc_R_32f(&m_DFTSpec, m_FFTSize, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast);
57    int bufferSize = 0;
58    ippsDFTGetBufSize_R_32f(m_DFTSpec, &bufferSize);
59    m_buffer = ippsMalloc_8u(bufferSize);
60}
61
62// Creates a blank/empty frame (interpolate() must later be called).
63FFTFrame::FFTFrame()
64    : m_FFTSize(0)
65    , m_log2FFTSize(0)
66{
67}
68
69// Copy constructor.
70FFTFrame::FFTFrame(const FFTFrame& frame)
71    : m_FFTSize(frame.m_FFTSize)
72    , m_log2FFTSize(frame.m_log2FFTSize)
73    , m_realData(frame.m_FFTSize / 2)
74    , m_imagData(frame.m_FFTSize / 2)
75    , m_complexData(frame.m_FFTSize)
76{
77    ippsDFTInitAlloc_R_32f(&m_DFTSpec, m_FFTSize, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast);
78    int bufferSize = 0;
79    ippsDFTGetBufSize_R_32f(m_DFTSpec, &bufferSize);
80    m_buffer = ippsMalloc_8u(bufferSize);
81
82    // Copy/setup frame data.
83    unsigned numberOfBytes = sizeof(float) * m_FFTSize;
84    memcpy(realData(), frame.realData(), numberOfBytes);
85    memcpy(imagData(), frame.imagData(), numberOfBytes);
86}
87
88void FFTFrame::initialize()
89{
90}
91
92void FFTFrame::cleanup()
93{
94}
95
96FFTFrame::~FFTFrame()
97{
98    ippsFree(m_buffer);
99    ippsDFTFree_R_32f(m_DFTSpec);
100}
101
102void FFTFrame::doFFT(const float* data)
103{
104    Ipp32f* complexP = m_complexData.data();
105
106    // Compute Forward transform to perm format.
107    ippsDFTFwd_RToPerm_32f(reinterpret_cast<Ipp32f*>(const_cast<float*>(data)), complexP, m_DFTSpec, m_buffer);
108
109    Ipp32f* realP = m_realData.data();
110    Ipp32f* imagP = m_imagData.data();
111    ippsCplxToReal_32fc(reinterpret_cast<Ipp32fc*>(complexP), realP, imagP, m_FFTSize >> 1);
112}
113
114void FFTFrame::doInverseFFT(float* data)
115{
116    Ipp32f* complexP = getUpToDateComplexData();
117
118    // Compute inverse transform.
119    ippsDFTInv_PermToR_32f(complexP, reinterpret_cast<Ipp32f*>(data), m_DFTSpec, m_buffer);
120
121    // Scale so that a forward then inverse FFT yields exactly the original data.
122    const float scale = 1.0 / m_FFTSize;
123
124    ippsMulC_32f_I(scale, reinterpret_cast<Ipp32f*>(data), m_FFTSize);
125}
126
127float* FFTFrame::getUpToDateComplexData()
128{
129    int len = m_FFTSize >> 1;
130    // Merge the real and imagimary vectors to complex vector.
131    Ipp32f* realP = m_realData.data();
132    Ipp32f* imagP = m_imagData.data();
133    Ipp32fc* complexP = reinterpret_cast<Ipp32fc*>(m_complexData.data());
134    ippsRealToCplx_32f(realP, imagP, complexP, len);
135
136    return const_cast<float*>(m_complexData.data());
137}
138
139} // namespace blink
140
141#endif // USE(WEBAUDIO_IPP)
142
143#endif // ENABLE(WEB_AUDIO)
144