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