15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2010, 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) * 1.  Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if ENABLE(WEB_AUDIO)
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/webaudio/RealtimeAnalyser.h"
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/AudioBus.h"
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/AudioUtilities.h"
331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/FFTFrame.h"
341e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/audio/VectorMath.h"
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <algorithm>
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <limits.h>
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/Complex.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/Float32Array.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/MainThread.h"
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/MathExtras.h"
4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/Uint8Array.h"
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace std;
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const double RealtimeAnalyser::DefaultSmoothingTimeConstant  = 0.8;
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const double RealtimeAnalyser::DefaultMinDecibels = -100;
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const double RealtimeAnalyser::DefaultMaxDecibels = -30;
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const unsigned RealtimeAnalyser::DefaultFFTSize = 2048;
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// All FFT implementations are expected to handle power-of-two sizes MinFFTSize <= size <= MaxFFTSize.
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const unsigned RealtimeAnalyser::MinFFTSize = 32;
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const unsigned RealtimeAnalyser::MaxFFTSize = 2048;
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const unsigned RealtimeAnalyser::InputBufferSize = RealtimeAnalyser::MaxFFTSize * 2;
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)RealtimeAnalyser::RealtimeAnalyser()
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_inputBuffer(InputBufferSize)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_writeIndex(0)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_fftSize(DefaultFFTSize)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_magnitudeBuffer(DefaultFFTSize / 2)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_smoothingTimeConstant(DefaultSmoothingTimeConstant)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_minDecibels(DefaultMinDecibels)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_maxDecibels(DefaultMaxDecibels)
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_analysisFrame = adoptPtr(new FFTFrame(DefaultFFTSize));
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RealtimeAnalyser::reset()
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_writeIndex = 0;
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_inputBuffer.zero();
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_magnitudeBuffer.zero();
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool RealtimeAnalyser::setFftSize(size_t size)
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isMainThread());
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Only allow powers of two.
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned log2size = static_cast<unsigned>(log2(size));
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isPOT(1UL << log2size == size);
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isPOT || size > MaxFFTSize || size < MinFFTSize)
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_fftSize != size) {
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_analysisFrame = adoptPtr(new FFTFrame(size));
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // m_magnitudeBuffer has size = fftSize / 2 because it contains floats reduced from complex values in m_analysisFrame.
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_magnitudeBuffer.allocate(size / 2);
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_fftSize = size;
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RealtimeAnalyser::writeInput(AudioBus* bus, size_t framesToProcess)
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isBusGood = bus && bus->numberOfChannels() > 0 && bus->channel(0)->length() >= framesToProcess;
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isBusGood);
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isBusGood)
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
10402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME : allow to work with non-FFTSize divisible chunking
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    bool isDestinationGood = m_writeIndex < m_inputBuffer.size() && m_writeIndex + framesToProcess <= m_inputBuffer.size();
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isDestinationGood);
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!isDestinationGood)
10902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        return;
11002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Perform real-time analysis
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const float* source = bus->channel(0)->data();
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* dest = m_inputBuffer.data() + m_writeIndex;
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The source has already been sanity checked with isBusGood above.
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memcpy(dest, source, sizeof(float) * framesToProcess);
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Sum all channels in one if numberOfChannels > 1.
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned numberOfChannels = bus->numberOfChannels();
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (numberOfChannels > 1) {
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned i = 1; i < numberOfChannels; i++) {
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            source = bus->channel(i)->data();
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            VectorMath::vadd(dest, 1, source, 1, dest, 1, framesToProcess);
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const float scale =  1.0 / numberOfChannels;
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        VectorMath::vsmul(dest, 1, &scale, dest, 1, framesToProcess);
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_writeIndex += framesToProcess;
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_writeIndex >= InputBufferSize)
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_writeIndex = 0;
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace {
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void applyWindow(float* p, size_t n)
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isMainThread());
13902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Blackman window
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double alpha = 0.16;
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a0 = 0.5 * (1 - alpha);
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a1 = 0.5;
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double a2 = 0.5 * alpha;
14502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < n; ++i) {
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        double x = static_cast<double>(i) / static_cast<double>(n);
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        double window = a0 - a1 * cos(2 * piDouble * x) + a2 * cos(4 * piDouble * x);
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        p[i] *= float(window);
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RealtimeAnalyser::doFFTAnalysis()
15602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch{
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isMainThread());
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Unroll the input buffer into a temporary buffer, where we'll apply an analysis window followed by an FFT.
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t fftSize = this->fftSize();
16102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    AudioFloatArray temporaryBuffer(fftSize);
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* inputBuffer = m_inputBuffer.data();
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* tempP = temporaryBuffer.data();
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Take the previous fftSize values from the input buffer and copy into the temporary buffer.
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned writeIndex = m_writeIndex;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (writeIndex < fftSize) {
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        memcpy(tempP, inputBuffer + writeIndex - fftSize + InputBufferSize, sizeof(*tempP) * (fftSize - writeIndex));
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        memcpy(tempP + fftSize - writeIndex, inputBuffer, sizeof(*tempP) * writeIndex);
17102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    } else
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        memcpy(tempP, inputBuffer + writeIndex - fftSize, sizeof(*tempP) * fftSize);
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
17402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Window the input samples.
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    applyWindow(tempP, fftSize);
17702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Do the analysis.
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_analysisFrame->doFFT(tempP);
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* realP = m_analysisFrame->realData();
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* imagP = m_analysisFrame->imagData();
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Blow away the packed nyquist component.
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    imagP[0] = 0;
18602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor).
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const double magnitudeScale = 1.0 / DefaultFFTSize;
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // A value of 0 does no averaging with the previous result.  Larger values produce slower, but smoother changes.
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    double k = m_smoothingTimeConstant;
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    k = max(0.0, k);
19302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    k = min(1.0, k);
19402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Convert the analysis data from complex to magnitude and average with the previous result.
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* destination = magnitudeBuffer().data();
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t n = magnitudeBuffer().size();
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < n; ++i) {
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Complex c(realP[i], imagP[i]);
20002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        double scalarMagnitude = abs(c) * magnitudeScale;
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        destination[i] = float(k * destination[i] + (1 - k) * scalarMagnitude);
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RealtimeAnalyser::getFloatFrequencyData(Float32Array* destinationArray)
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isMainThread());
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!destinationArray)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
21102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    doFFTAnalysis();
21302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Convert from linear magnitude to floating-point decibels.
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const double minDecibels = m_minDecibels;
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned sourceLength = magnitudeBuffer().size();
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t len = min(sourceLength, destinationArray->length());
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (len > 0) {
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const float* source = magnitudeBuffer().data();
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        float* destination = destinationArray->data();
22102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned i = 0; i < len; ++i) {
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float linearValue = source[i];
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            double dbMag = !linearValue ? minDecibels : AudioUtilities::linearToDecibels(linearValue);
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            destination[i] = float(dbMag);
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RealtimeAnalyser::getByteFrequencyData(Uint8Array* destinationArray)
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isMainThread());
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!destinationArray)
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
23602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    doFFTAnalysis();
23802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Convert from linear magnitude to unsigned-byte decibels.
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned sourceLength = magnitudeBuffer().size();
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t len = min(sourceLength, destinationArray->length());
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (len > 0) {
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const double rangeScaleFactor = m_maxDecibels == m_minDecibels ? 1 : 1 / (m_maxDecibels - m_minDecibels);
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const double minDecibels = m_minDecibels;
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const float* source = magnitudeBuffer().data();
24702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        unsigned char* destination = destinationArray->data();
24802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned i = 0; i < len; ++i) {
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float linearValue = source[i];
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            double dbMag = !linearValue ? minDecibels : AudioUtilities::linearToDecibels(linearValue);
25202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // The range m_minDecibels to m_maxDecibels will be scaled to byte values from 0 to UCHAR_MAX.
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            double scaledValue = UCHAR_MAX * (dbMag - minDecibels) * rangeScaleFactor;
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Clip to valid range.
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (scaledValue < 0)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                scaledValue = 0;
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (scaledValue > UCHAR_MAX)
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                scaledValue = UCHAR_MAX;
26102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            destination[i] = static_cast<unsigned char>(scaledValue);
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void RealtimeAnalyser::getByteTimeDomainData(Uint8Array* destinationArray)
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(isMainThread());
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!destinationArray)
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
27302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    unsigned fftSize = this->fftSize();
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t len = min(fftSize, destinationArray->length());
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (len > 0) {
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        bool isInputBufferGood = m_inputBuffer.size() == InputBufferSize && m_inputBuffer.size() > fftSize;
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(isInputBufferGood);
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!isInputBufferGood)
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
28202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch        float* inputBuffer = m_inputBuffer.data();
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        unsigned char* destination = destinationArray->data();
28402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        unsigned writeIndex = m_writeIndex;
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (unsigned i = 0; i < len; ++i) {
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Buffer access is protected due to modulo operation.
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float value = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize];
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Scale from nominal -1 -> +1 to unsigned byte.
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            double scaledValue = 128 * (value + 1);
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Clip to valid range.
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (scaledValue < 0)
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                scaledValue = 0;
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (scaledValue > UCHAR_MAX)
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                scaledValue = UCHAR_MAX;
29902772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            destination[i] = static_cast<unsigned char>(scaledValue);
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif // ENABLE(WEB_AUDIO)
308