[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc
crogers at google.com
crogers at google.com
Wed Dec 22 15:25:02 UTC 2010
The following commit has been merged in the debian/experimental branch:
commit cb1d3ae8849677e2a12d7836ea68d65578d236b0
Author: crogers at google.com <crogers at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Wed Nov 3 00:44:34 2010 +0000
2010-11-02 Chris Rogers <crogers at google.com>
Reviewed by Kenneth Russell.
Add RealtimeAnalyser files
https://bugs.webkit.org/show_bug.cgi?id=48810
No new tests since audio API is not yet implemented.
* webaudio/RealtimeAnalyser.cpp: Added.
(WebCore::RealtimeAnalyser::RealtimeAnalyser):
(WebCore::RealtimeAnalyser::~RealtimeAnalyser):
(WebCore::RealtimeAnalyser::reset):
(WebCore::RealtimeAnalyser::setFftSize):
(WebCore::RealtimeAnalyser::writeInput):
(WebCore::RealtimeAnalyser::doFFTAnalysis):
(WebCore::RealtimeAnalyser::getFloatFrequencyData):
(WebCore::RealtimeAnalyser::getByteFrequencyData):
(WebCore::RealtimeAnalyser::getByteTimeDomainData):
* webaudio/RealtimeAnalyser.h: Added.
(WebCore::RealtimeAnalyser::fftSize):
(WebCore::RealtimeAnalyser::frequencyBinCount):
(WebCore::RealtimeAnalyser::setMinDecibels):
(WebCore::RealtimeAnalyser::minDecibels):
(WebCore::RealtimeAnalyser::setMaxDecibels):
(WebCore::RealtimeAnalyser::maxDecibels):
(WebCore::RealtimeAnalyser::setSmoothingTimeConstant):
(WebCore::RealtimeAnalyser::smoothingTimeConstant):
(WebCore::RealtimeAnalyser::magnitudeBuffer):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@71193 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 99eaaaf..de2484f 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,33 @@
+2010-11-02 Chris Rogers <crogers at google.com>
+
+ Reviewed by Kenneth Russell.
+
+ Add RealtimeAnalyser files
+ https://bugs.webkit.org/show_bug.cgi?id=48810
+
+ No new tests since audio API is not yet implemented.
+
+ * webaudio/RealtimeAnalyser.cpp: Added.
+ (WebCore::RealtimeAnalyser::RealtimeAnalyser):
+ (WebCore::RealtimeAnalyser::~RealtimeAnalyser):
+ (WebCore::RealtimeAnalyser::reset):
+ (WebCore::RealtimeAnalyser::setFftSize):
+ (WebCore::RealtimeAnalyser::writeInput):
+ (WebCore::RealtimeAnalyser::doFFTAnalysis):
+ (WebCore::RealtimeAnalyser::getFloatFrequencyData):
+ (WebCore::RealtimeAnalyser::getByteFrequencyData):
+ (WebCore::RealtimeAnalyser::getByteTimeDomainData):
+ * webaudio/RealtimeAnalyser.h: Added.
+ (WebCore::RealtimeAnalyser::fftSize):
+ (WebCore::RealtimeAnalyser::frequencyBinCount):
+ (WebCore::RealtimeAnalyser::setMinDecibels):
+ (WebCore::RealtimeAnalyser::minDecibels):
+ (WebCore::RealtimeAnalyser::setMaxDecibels):
+ (WebCore::RealtimeAnalyser::maxDecibels):
+ (WebCore::RealtimeAnalyser::setSmoothingTimeConstant):
+ (WebCore::RealtimeAnalyser::smoothingTimeConstant):
+ (WebCore::RealtimeAnalyser::magnitudeBuffer):
+
2010-11-02 Ilya Sherman <isherman at chromium.org>
Reviewed by Kent Tamura.
diff --git a/WebCore/webaudio/RealtimeAnalyser.cpp b/WebCore/webaudio/RealtimeAnalyser.cpp
new file mode 100644
index 0000000..282f299
--- /dev/null
+++ b/WebCore/webaudio/RealtimeAnalyser.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2010, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "RealtimeAnalyser.h"
+
+#include "AudioBus.h"
+#include "AudioUtilities.h"
+#include "FFTFrame.h"
+
+#if ENABLE(3D_CANVAS)
+#include "Float32Array.h"
+#include "Uint8Array.h"
+#endif
+
+#include <algorithm>
+#include <limits.h>
+#include <wtf/Complex.h>
+#include <wtf/Threading.h>
+
+using namespace std;
+
+namespace WebCore {
+
+const double RealtimeAnalyser::DefaultSmoothingTimeConstant = 0.8;
+const double RealtimeAnalyser::DefaultMinDecibels = -100.0;
+const double RealtimeAnalyser::DefaultMaxDecibels = -30.0;
+
+const unsigned RealtimeAnalyser::DefaultFFTSize = 2048;
+const unsigned RealtimeAnalyser::MaxFFTSize = 2048;
+const unsigned RealtimeAnalyser::InputBufferSize = RealtimeAnalyser::MaxFFTSize * 2;
+
+RealtimeAnalyser::RealtimeAnalyser()
+ : m_inputBuffer(InputBufferSize)
+ , m_writeIndex(0)
+ , m_fftSize(DefaultFFTSize)
+ , m_magnitudeBuffer(DefaultFFTSize / 2)
+ , m_smoothingTimeConstant(DefaultSmoothingTimeConstant)
+ , m_minDecibels(DefaultMinDecibels)
+ , m_maxDecibels(DefaultMaxDecibels)
+{
+ m_analysisFrame = adoptPtr(new FFTFrame(DefaultFFTSize));
+}
+
+RealtimeAnalyser::~RealtimeAnalyser()
+{
+}
+
+void RealtimeAnalyser::reset()
+{
+ m_writeIndex = 0;
+ m_inputBuffer.zero();
+ m_magnitudeBuffer.zero();
+}
+
+void RealtimeAnalyser::setFftSize(size_t size)
+{
+ ASSERT(isMainThread());
+
+ // Only allow powers of two.
+ unsigned log2size = static_cast<unsigned>(log2(size));
+ bool isPOT(1UL << log2size == size);
+
+ if (!isPOT || size > MaxFFTSize) {
+ // FIXME: It would be good to also set an exception.
+ return;
+ }
+
+ if (m_fftSize != size) {
+ m_analysisFrame = adoptPtr(new FFTFrame(m_fftSize));
+ m_magnitudeBuffer.resize(size);
+ m_fftSize = size;
+ }
+}
+
+void RealtimeAnalyser::writeInput(AudioBus* bus, size_t framesToProcess)
+{
+ bool isBusGood = bus && bus->numberOfChannels() > 0 && bus->channel(0)->length() >= framesToProcess;
+ ASSERT(isBusGood);
+ if (!isBusGood)
+ return;
+
+ // FIXME : allow to work with non-FFTSize divisible chunking
+ bool isDestinationGood = m_writeIndex < m_inputBuffer.size() && m_writeIndex + framesToProcess <= m_inputBuffer.size();
+ ASSERT(isDestinationGood);
+ if (!isDestinationGood)
+ return;
+
+ // Perform real-time analysis
+ // FIXME : for now just use left channel (must mix if stereo source)
+ float* source = bus->channel(0)->data();
+
+ // The source has already been sanity checked with isBusGood above.
+
+ memcpy(m_inputBuffer.data() + m_writeIndex, source, sizeof(float) * framesToProcess);
+
+ m_writeIndex += framesToProcess;
+ if (m_writeIndex >= InputBufferSize)
+ m_writeIndex = 0;
+}
+
+namespace {
+
+void applyWindow(float* p, size_t n)
+{
+ ASSERT(isMainThread());
+
+ // Blackman window
+ double alpha = 0.16;
+ double a0 = 0.5 * (1.0 - alpha);
+ double a1 = 0.5;
+ double a2 = 0.5 * alpha;
+
+ for (unsigned i = 0; i < n; ++i) {
+ double x = static_cast<double>(i) / static_cast<double>(n);
+ double window = a0 - a1 * cos(2.0 * M_PI * x) + a2 * cos(4.0 * M_PI * x);
+ p[i] *= float(window);
+ }
+}
+
+} // namespace
+
+void RealtimeAnalyser::doFFTAnalysis()
+{
+ ASSERT(isMainThread());
+
+ // Unroll the input buffer into a temporary buffer, where we'll apply an analysis window followed by an FFT.
+ size_t fftSize = this->fftSize();
+
+ AudioFloatArray temporaryBuffer(fftSize);
+ float* inputBuffer = m_inputBuffer.data();
+ float* tempP = temporaryBuffer.data();
+
+ // Take the previous fftSize values from the input buffer and copy into the temporary buffer.
+ // FIXME : optimize with memcpy().
+ unsigned writeIndex = m_writeIndex;
+ for (unsigned i = 0; i < fftSize; ++i)
+ tempP[i] = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize];
+
+ // Window the input samples.
+ applyWindow(tempP, fftSize);
+
+ // Do the analysis.
+ m_analysisFrame->doFFT(tempP);
+
+ size_t n = DefaultFFTSize / 2;
+
+ float* realP = m_analysisFrame->realData();
+ float* imagP = m_analysisFrame->imagData();
+
+ // Blow away the packed nyquist component.
+ imagP[0] = 0.0f;
+
+ // Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor).
+ const double MagnitudeScale = 1.0 / DefaultFFTSize;
+
+ // A value of 0 does no averaging with the previous result. Larger values produce slower, but smoother changes.
+ double k = m_smoothingTimeConstant;
+ k = max(0.0, k);
+ k = min(1.0, k);
+
+ // Convert the analysis data from complex to magnitude and average with the previous result.
+ float* destination = magnitudeBuffer().data();
+ for (unsigned i = 0; i < n; ++i) {
+ Complex c(realP[i], imagP[i]);
+ double scalarMagnitude = abs(c) * MagnitudeScale;
+ destination[i] = float(k * destination[i] + (1.0 - k) * scalarMagnitude);
+ }
+}
+
+#if ENABLE(3D_CANVAS)
+
+void RealtimeAnalyser::getFloatFrequencyData(Float32Array* destinationArray)
+{
+ ASSERT(isMainThread());
+
+ if (!destinationArray)
+ return;
+
+ doFFTAnalysis();
+
+ // Convert from linear magnitude to floating-point decibels.
+ const double MinDecibels = m_minDecibels;
+ unsigned sourceLength = magnitudeBuffer().size();
+ size_t len = min(sourceLength, destinationArray->length());
+ if (len > 0) {
+ const float* source = magnitudeBuffer().data();
+ float* destination = destinationArray->data();
+
+ for (unsigned i = 0; i < len; ++i) {
+ float linearValue = source[i];
+ double dbMag = !linearValue ? MinDecibels : AudioUtilities::linearToDecibels(linearValue);
+ destination[i] = float(dbMag);
+ }
+ }
+}
+
+void RealtimeAnalyser::getByteFrequencyData(Uint8Array* destinationArray)
+{
+ ASSERT(isMainThread());
+
+ if (!destinationArray)
+ return;
+
+ doFFTAnalysis();
+
+ // Convert from linear magnitude to unsigned-byte decibels.
+ unsigned sourceLength = magnitudeBuffer().size();
+ size_t len = min(sourceLength, destinationArray->length());
+ if (len > 0) {
+ const double RangeScaleFactor = m_maxDecibels == m_minDecibels ? 1.0 : 1.0 / (m_maxDecibels - m_minDecibels);
+
+ const float* source = magnitudeBuffer().data();
+ unsigned char* destination = destinationArray->data();
+
+ for (unsigned i = 0; i < len; ++i) {
+ float linearValue = source[i];
+ double dbMag = !linearValue ? m_minDecibels : AudioUtilities::linearToDecibels(linearValue);
+
+ // The range m_minDecibels to m_maxDecibels will be scaled to byte values from 0 to UCHAR_MAX.
+ double scaledValue = UCHAR_MAX * (dbMag - m_minDecibels) * RangeScaleFactor;
+
+ // Clip to valid range.
+ if (scaledValue < 0.0)
+ scaledValue = 0.0;
+ if (scaledValue > UCHAR_MAX)
+ scaledValue = UCHAR_MAX;
+
+ destination[i] = static_cast<unsigned char>(scaledValue);
+ }
+ }
+}
+
+void RealtimeAnalyser::getByteTimeDomainData(Uint8Array* destinationArray)
+{
+ ASSERT(isMainThread());
+
+ if (!destinationArray)
+ return;
+
+ unsigned fftSize = this->fftSize();
+ size_t len = min(fftSize, destinationArray->length());
+ if (len > 0) {
+ bool isInputBufferGood = m_inputBuffer.size() == InputBufferSize && m_inputBuffer.size() > fftSize;
+ ASSERT(isInputBufferGood);
+ if (!isInputBufferGood)
+ return;
+
+ float* inputBuffer = m_inputBuffer.data();
+ unsigned char* destination = destinationArray->data();
+
+ unsigned writeIndex = m_writeIndex;
+
+ for (unsigned i = 0; i < len; ++i) {
+ // Buffer access is protected due to modulo operation.
+ float value = inputBuffer[(i + writeIndex - fftSize + InputBufferSize) % InputBufferSize];
+
+ // Scale from nominal -1.0 -> +1.0 to unsigned byte.
+ double scaledValue = 128.0 * (value + 1.0);
+
+ // Clip to valid range.
+ if (scaledValue < 0.0)
+ scaledValue = 0.0;
+ if (scaledValue > UCHAR_MAX)
+ scaledValue = UCHAR_MAX;
+
+ destination[i] = static_cast<unsigned char>(scaledValue);
+ }
+ }
+}
+
+#endif // 3D_CANVAS
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/webaudio/RealtimeAnalyser.h b/WebCore/webaudio/RealtimeAnalyser.h
new file mode 100644
index 0000000..686c17c
--- /dev/null
+++ b/WebCore/webaudio/RealtimeAnalyser.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RealtimeAnalyser_h
+#define RealtimeAnalyser_h
+
+#include "AudioArray.h"
+#include <wtf/NonCopyable.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class AudioBus;
+class FFTFrame;
+
+#if ENABLE(3D_CANVAS)
+class Float32Array;
+class Uint8Array;
+#endif
+
+class RealtimeAnalyser : public Noncopyable {
+public:
+ RealtimeAnalyser();
+ virtual ~RealtimeAnalyser();
+
+ void reset();
+
+ size_t fftSize() const { return m_fftSize; }
+ void setFftSize(size_t size);
+
+ unsigned frequencyBinCount() const { return m_fftSize / 2; }
+
+ void setMinDecibels(float k) { m_minDecibels = k; }
+ float minDecibels() const { return static_cast<float>(m_minDecibels); }
+
+ void setMaxDecibels(float k) { m_maxDecibels = k; }
+ float maxDecibels() const { return static_cast<float>(m_maxDecibels); }
+
+ void setSmoothingTimeConstant(float k) { m_smoothingTimeConstant = k; }
+ float smoothingTimeConstant() const { return static_cast<float>(m_smoothingTimeConstant); }
+
+#if ENABLE(3D_CANVAS)
+ void getFloatFrequencyData(Float32Array*);
+ void getByteFrequencyData(Uint8Array*);
+ void getByteTimeDomainData(Uint8Array*);
+#endif
+
+ // The audio thread writes input data here.
+ void writeInput(AudioBus*, size_t framesToProcess);
+
+ static const double DefaultSmoothingTimeConstant;
+ static const double DefaultMinDecibels;
+ static const double DefaultMaxDecibels;
+
+ static const unsigned DefaultFFTSize;
+ static const unsigned MaxFFTSize;
+ static const unsigned InputBufferSize;
+
+private:
+ // The audio thread writes the input audio here.
+ AudioFloatArray m_inputBuffer;
+ unsigned m_writeIndex;
+
+ size_t m_fftSize;
+ OwnPtr<FFTFrame> m_analysisFrame;
+ void doFFTAnalysis();
+
+ // doFFTAnalysis() stores the floating-point magnitude analysis data here.
+ AudioFloatArray m_magnitudeBuffer;
+ AudioFloatArray& magnitudeBuffer() { return m_magnitudeBuffer; }
+
+ // A value between 0 and 1 which averages the previous version of m_magnitudeBuffer with the current analysis magnitude data.
+ double m_smoothingTimeConstant;
+
+ // The range used when converting when using getByteFrequencyData().
+ double m_minDecibels;
+ double m_maxDecibels;
+};
+
+} // namespace WebCore
+
+#endif // RealtimeAnalyser_h
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list