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