128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu/*
228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * Copyright (C) 2010, Google Inc. All rights reserved.
328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *
428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * Redistribution and use in source and binary forms, with or without
528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * modification, are permitted provided that the following conditions
628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * are met:
728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * 1.  Redistributions of source code must retain the above copyright
828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    notice, this list of conditions and the following disclaimer.
928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * 2.  Redistributions in binary form must reproduce the above copyright
1028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    notice, this list of conditions and the following disclaimer in the
1128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *    documentation and/or other materials provided with the distribution.
1228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu *
1328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
1428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
1728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu */
2428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "config.h"
2628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#if ENABLE(WEB_AUDIO)
2828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "RealtimeAnalyser.h"
3028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
3128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioBus.h"
3228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "AudioUtilities.h"
3328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "FFTFrame.h"
3428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#if ENABLE(WEBGL)
3628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "Float32Array.h"
3728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "Uint8Array.h"
3828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#endif
3928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
4028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <algorithm>
4128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <limits.h>
4228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <wtf/Complex.h>
43f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include <wtf/MathExtras.h>
4428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include <wtf/Threading.h>
4528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
4628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuusing namespace std;
4728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
4828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhunamespace WebCore {
4928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst double RealtimeAnalyser::DefaultSmoothingTimeConstant  = 0.8;
5128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst double RealtimeAnalyser::DefaultMinDecibels = -100.0;
5228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst double RealtimeAnalyser::DefaultMaxDecibels = -30.0;
5328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst unsigned RealtimeAnalyser::DefaultFFTSize = 2048;
5528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst unsigned RealtimeAnalyser::MaxFFTSize = 2048;
5628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuconst unsigned RealtimeAnalyser::InputBufferSize = RealtimeAnalyser::MaxFFTSize * 2;
5728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
5828040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuRealtimeAnalyser::RealtimeAnalyser()
5928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    : m_inputBuffer(InputBufferSize)
6028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    , m_writeIndex(0)
6128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    , m_fftSize(DefaultFFTSize)
6228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    , m_magnitudeBuffer(DefaultFFTSize / 2)
6328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    , m_smoothingTimeConstant(DefaultSmoothingTimeConstant)
6428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    , m_minDecibels(DefaultMinDecibels)
6528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    , m_maxDecibels(DefaultMaxDecibels)
6628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
6728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_analysisFrame = adoptPtr(new FFTFrame(DefaultFFTSize));
6828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
6928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
7028040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuRealtimeAnalyser::~RealtimeAnalyser()
7128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
7228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
7328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
7428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::reset()
7528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
7628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_writeIndex = 0;
7728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_inputBuffer.zero();
7828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_magnitudeBuffer.zero();
7928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
8028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
8128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::setFftSize(size_t size)
8228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
8328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
8428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
8528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Only allow powers of two.
8628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    unsigned log2size = static_cast<unsigned>(log2(size));
8728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    bool isPOT(1UL << log2size == size);
8828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
8928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!isPOT || size > MaxFFTSize) {
9028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        // FIXME: It would be good to also set an exception.
9128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
9228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
9328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
9428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (m_fftSize != size) {
9528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_analysisFrame = adoptPtr(new FFTFrame(m_fftSize));
9628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_magnitudeBuffer.resize(size);
9728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_fftSize = size;
9828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
9928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
10028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
10128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::writeInput(AudioBus* bus, size_t framesToProcess)
10228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
10328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    bool isBusGood = bus && bus->numberOfChannels() > 0 && bus->channel(0)->length() >= framesToProcess;
10428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isBusGood);
10528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!isBusGood)
10628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
10728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
10828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // FIXME : allow to work with non-FFTSize divisible chunking
10928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    bool isDestinationGood = m_writeIndex < m_inputBuffer.size() && m_writeIndex + framesToProcess <= m_inputBuffer.size();
11028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isDestinationGood);
11128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!isDestinationGood)
11228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
11328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
11428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Perform real-time analysis
11528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // FIXME : for now just use left channel (must mix if stereo source)
11628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    float* source = bus->channel(0)->data();
11728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
11828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // The source has already been sanity checked with isBusGood above.
11928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
12028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    memcpy(m_inputBuffer.data() + m_writeIndex, source, sizeof(float) * framesToProcess);
12128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
12228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_writeIndex += framesToProcess;
12328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (m_writeIndex >= InputBufferSize)
12428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_writeIndex = 0;
12528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
12628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
12728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhunamespace {
12828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
12928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid applyWindow(float* p, size_t n)
13028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
13128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
13228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
13328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Blackman window
13428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    double alpha = 0.16;
13528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    double a0 = 0.5 * (1.0 - alpha);
13628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    double a1 = 0.5;
13728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    double a2 = 0.5 * alpha;
13828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
13928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    for (unsigned i = 0; i < n; ++i) {
14028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        double x = static_cast<double>(i) / static_cast<double>(n);
141f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch        double window = a0 - a1 * cos(2.0 * piDouble * x) + a2 * cos(4.0 * piDouble * x);
14228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        p[i] *= float(window);
14328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
14428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
14528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
14628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} // namespace
14728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
14828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::doFFTAnalysis()
14928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
15028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
15128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
15228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Unroll the input buffer into a temporary buffer, where we'll apply an analysis window followed by an FFT.
15328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    size_t fftSize = this->fftSize();
15428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
15528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    AudioFloatArray temporaryBuffer(fftSize);
15628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    float* inputBuffer = m_inputBuffer.data();
15728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    float* tempP = temporaryBuffer.data();
15828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
15928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Take the previous fftSize values from the input buffer and copy into the temporary buffer.
16028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // FIXME : optimize with memcpy().
16128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    unsigned writeIndex = m_writeIndex;
16228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    for (unsigned i = 0; i < fftSize; ++i)
16328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        tempP[i] = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize];
16428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
16528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Window the input samples.
16628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    applyWindow(tempP, fftSize);
16728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
16828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Do the analysis.
16928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    m_analysisFrame->doFFT(tempP);
17028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
17128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    size_t n = DefaultFFTSize / 2;
17228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
17328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    float* realP = m_analysisFrame->realData();
17428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    float* imagP = m_analysisFrame->imagData();
17528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
17628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Blow away the packed nyquist component.
17728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    imagP[0] = 0.0f;
17828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
17928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor).
18028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    const double MagnitudeScale = 1.0 / DefaultFFTSize;
18128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
18228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // A value of 0 does no averaging with the previous result.  Larger values produce slower, but smoother changes.
18328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    double k = m_smoothingTimeConstant;
18428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    k = max(0.0, k);
18528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    k = min(1.0, k);
18628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
18728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Convert the analysis data from complex to magnitude and average with the previous result.
18828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    float* destination = magnitudeBuffer().data();
18928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    for (unsigned i = 0; i < n; ++i) {
19028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        Complex c(realP[i], imagP[i]);
19128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        double scalarMagnitude = abs(c) * MagnitudeScale;
19228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        destination[i] = float(k * destination[i] + (1.0 - k) * scalarMagnitude);
19328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
19428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
19528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
1962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#if ENABLE(WEBGL)
19728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
19828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::getFloatFrequencyData(Float32Array* destinationArray)
19928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
20028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
20128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
20228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!destinationArray)
20328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
20428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
20528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    doFFTAnalysis();
20628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
20728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Convert from linear magnitude to floating-point decibels.
20828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    const double MinDecibels = m_minDecibels;
20928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    unsigned sourceLength = magnitudeBuffer().size();
21028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    size_t len = min(sourceLength, destinationArray->length());
21128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (len > 0) {
21228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        const float* source = magnitudeBuffer().data();
21328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        float* destination = destinationArray->data();
21428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
21528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        for (unsigned i = 0; i < len; ++i) {
21628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            float linearValue = source[i];
21728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            double dbMag = !linearValue ? MinDecibels : AudioUtilities::linearToDecibels(linearValue);
21828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            destination[i] = float(dbMag);
21928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        }
22028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
22128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
22228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
22328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::getByteFrequencyData(Uint8Array* destinationArray)
22428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
22528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
22628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
22728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!destinationArray)
22828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
22928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
23028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    doFFTAnalysis();
23128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
23228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Convert from linear magnitude to unsigned-byte decibels.
23328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    unsigned sourceLength = magnitudeBuffer().size();
23428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    size_t len = min(sourceLength, destinationArray->length());
23528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (len > 0) {
23628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        const double RangeScaleFactor = m_maxDecibels == m_minDecibels ? 1.0 : 1.0 / (m_maxDecibels - m_minDecibels);
23728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
23828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        const float* source = magnitudeBuffer().data();
23928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        unsigned char* destination = destinationArray->data();
24028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
24128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        for (unsigned i = 0; i < len; ++i) {
24228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            float linearValue = source[i];
24328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            double dbMag = !linearValue ? m_minDecibels : AudioUtilities::linearToDecibels(linearValue);
24428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
24528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // The range m_minDecibels to m_maxDecibels will be scaled to byte values from 0 to UCHAR_MAX.
24628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            double scaledValue = UCHAR_MAX * (dbMag - m_minDecibels) * RangeScaleFactor;
24728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
24828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Clip to valid range.
24928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            if (scaledValue < 0.0)
25028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu                scaledValue = 0.0;
25128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            if (scaledValue > UCHAR_MAX)
25228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu                scaledValue = UCHAR_MAX;
25328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
25428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            destination[i] = static_cast<unsigned char>(scaledValue);
25528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        }
25628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
25728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
25828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
25928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuvoid RealtimeAnalyser::getByteTimeDomainData(Uint8Array* destinationArray)
26028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{
26128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    ASSERT(isMainThread());
26228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
26328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (!destinationArray)
26428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        return;
26528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
26628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    unsigned fftSize = this->fftSize();
26728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    size_t len = min(fftSize, destinationArray->length());
26828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (len > 0) {
26928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        bool isInputBufferGood = m_inputBuffer.size() == InputBufferSize && m_inputBuffer.size() > fftSize;
27028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        ASSERT(isInputBufferGood);
27128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        if (!isInputBufferGood)
27228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            return;
27328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
27428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        float* inputBuffer = m_inputBuffer.data();
27528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        unsigned char* destination = destinationArray->data();
27628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
27728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        unsigned writeIndex = m_writeIndex;
27828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
27928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        for (unsigned i = 0; i < len; ++i) {
28028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Buffer access is protected due to modulo operation.
28128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            float value = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize];
28228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
28328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Scale from nominal -1.0 -> +1.0 to unsigned byte.
28428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            double scaledValue = 128.0 * (value + 1.0);
28528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
28628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            // Clip to valid range.
28728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            if (scaledValue < 0.0)
28828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu                scaledValue = 0.0;
28928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            if (scaledValue > UCHAR_MAX)
29028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu                scaledValue = UCHAR_MAX;
29128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
29228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu            destination[i] = static_cast<unsigned char>(scaledValue);
29328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        }
29428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    }
29528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu}
29628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
2972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#endif // WEBGL
29828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
29928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} // namespace WebCore
30028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
30128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#endif // ENABLE(WEB_AUDIO)
302