1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29// Mac OS X - specific FFTFrame implementation
30
31#include "config.h"
32
33#if ENABLE(WEB_AUDIO)
34
35#if OS(MACOSX)
36
37#include "platform/audio/FFTFrame.h"
38
39#include "platform/audio/VectorMath.h"
40
41namespace blink {
42
43const int kMaxFFTPow2Size = 24;
44
45FFTSetup* FFTFrame::fftSetups = 0;
46
47// Normal constructor: allocates for a given fftSize
48FFTFrame::FFTFrame(unsigned fftSize)
49    : m_realData(fftSize)
50    , m_imagData(fftSize)
51{
52    m_FFTSize = fftSize;
53    m_log2FFTSize = static_cast<unsigned>(log2(fftSize));
54
55    // We only allow power of two
56    ASSERT(1UL << m_log2FFTSize == m_FFTSize);
57
58    // Lazily create and share fftSetup with other frames
59    m_FFTSetup = fftSetupForSize(fftSize);
60
61    // Setup frame data
62    m_frame.realp = m_realData.data();
63    m_frame.imagp = m_imagData.data();
64}
65
66// Creates a blank/empty frame (interpolate() must later be called)
67FFTFrame::FFTFrame()
68    : m_realData(0)
69    , m_imagData(0)
70{
71    // Later will be set to correct values when interpolate() is called
72    m_frame.realp = 0;
73    m_frame.imagp = 0;
74
75    m_FFTSize = 0;
76    m_log2FFTSize = 0;
77}
78
79// Copy constructor
80FFTFrame::FFTFrame(const FFTFrame& frame)
81    : m_FFTSize(frame.m_FFTSize)
82    , m_log2FFTSize(frame.m_log2FFTSize)
83    , m_realData(frame.m_FFTSize)
84    , m_imagData(frame.m_FFTSize)
85    , m_FFTSetup(frame.m_FFTSetup)
86{
87    // Setup frame data
88    m_frame.realp = m_realData.data();
89    m_frame.imagp = m_imagData.data();
90
91    // Copy/setup frame data
92    unsigned nbytes = sizeof(float) * m_FFTSize;
93    memcpy(realData(), frame.m_frame.realp, nbytes);
94    memcpy(imagData(), frame.m_frame.imagp, nbytes);
95}
96
97FFTFrame::~FFTFrame()
98{
99}
100
101void FFTFrame::doFFT(const float* data)
102{
103    AudioFloatArray scaledData(m_FFTSize);
104    // veclib fft returns a result that is twice as large as would be expected. Compensate for that
105    // by scaling the input by half so the FFT has the correct scaling.
106    float scale = 0.5f;
107    VectorMath::vsmul(data, 1, &scale, scaledData.data(), 1, m_FFTSize);
108
109    vDSP_ctoz((DSPComplex*)scaledData.data(), 2, &m_frame, 1, m_FFTSize / 2);
110    vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_FORWARD);
111}
112
113void FFTFrame::doInverseFFT(float* data)
114{
115    vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_INVERSE);
116    vDSP_ztoc(&m_frame, 1, (DSPComplex*)data, 2, m_FFTSize / 2);
117
118    // Do final scaling so that x == IFFT(FFT(x))
119    float scale = 1.0f / m_FFTSize;
120    VectorMath::vsmul(data, 1, &scale, data, 1, m_FFTSize);
121}
122
123FFTSetup FFTFrame::fftSetupForSize(unsigned fftSize)
124{
125    if (!fftSetups) {
126        fftSetups = (FFTSetup*)malloc(sizeof(FFTSetup) * kMaxFFTPow2Size);
127        memset(fftSetups, 0, sizeof(FFTSetup) * kMaxFFTPow2Size);
128    }
129
130    int pow2size = static_cast<int>(log2(fftSize));
131    ASSERT(pow2size < kMaxFFTPow2Size);
132    if (!fftSetups[pow2size])
133        fftSetups[pow2size] = vDSP_create_fftsetup(pow2size, FFT_RADIX2);
134
135    return fftSetups[pow2size];
136}
137
138void FFTFrame::initialize()
139{
140}
141
142void FFTFrame::cleanup()
143{
144    if (!fftSetups)
145        return;
146
147    for (int i = 0; i < kMaxFFTPow2Size; ++i) {
148        if (fftSetups[i])
149            vDSP_destroy_fftsetup(fftSetups[i]);
150    }
151
152    free(fftSetups);
153    fftSetups = 0;
154}
155
156} // namespace blink
157
158#endif // #if OS(MACOSX)
159
160#endif // ENABLE(WEB_AUDIO)
161