summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/audio/Biquad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/audio/Biquad.cpp')
-rw-r--r--Source/WebCore/platform/audio/Biquad.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/Source/WebCore/platform/audio/Biquad.cpp b/Source/WebCore/platform/audio/Biquad.cpp
new file mode 100644
index 0000000..20143e3
--- /dev/null
+++ b/Source/WebCore/platform/audio/Biquad.cpp
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "Biquad.h"
+
+#include <algorithm>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if OS(DARWIN)
+#include <Accelerate/Accelerate.h>
+#endif
+
+namespace WebCore {
+
+const int kBufferSize = 1024;
+
+Biquad::Biquad()
+{
+#if OS(DARWIN)
+ // Allocate two samples more for filter history
+ m_inputBuffer.resize(kBufferSize + 2);
+ m_outputBuffer.resize(kBufferSize + 2);
+#endif
+
+ // Initialize as pass-thru (straight-wire, no filter effect)
+ m_a0 = 1.0;
+ m_a1 = 0.0;
+ m_a2 = 0.0;
+ m_b1 = 0.0;
+ m_b2 = 0.0;
+
+ m_g = 1.0;
+
+ reset(); // clear filter memory
+}
+
+void Biquad::process(const float* sourceP, float* destP, size_t framesToProcess)
+{
+#if OS(DARWIN)
+ // Use vecLib if available
+ processFast(sourceP, destP, framesToProcess);
+#else
+ int n = framesToProcess;
+
+ // Create local copies of member variables
+ double x1 = m_x1;
+ double x2 = m_x2;
+ double y1 = m_y1;
+ double y2 = m_y2;
+
+ double a0 = m_a0;
+ double a1 = m_a1;
+ double a2 = m_a2;
+ double b1 = m_b1;
+ double b2 = m_b2;
+
+ while (n--) {
+ // FIXME: this can be optimized by pipelining the multiply adds...
+ float x = *sourceP++;
+ float y = a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2;
+
+ y *= m_g;
+
+ *destP++ = y;
+
+ // Update state variables
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ }
+
+ // Local variables back to member
+ m_x1 = x1;
+ m_x2 = x2;
+ m_y1 = y1;
+ m_y2 = y2;
+
+ m_a0 = a0;
+ m_a1 = a1;
+ m_a2 = a2;
+ m_b1 = b1;
+ m_b2 = b2;
+#endif
+}
+
+#if OS(DARWIN)
+
+// Here we have optimized version using Accelerate.framework
+
+void Biquad::processFast(const float* sourceP, float* destP, size_t framesToProcess)
+{
+ // Filter coefficients
+ double B[5];
+ B[0] = m_a0;
+ B[1] = m_a1;
+ B[2] = m_a2;
+ B[3] = m_b1;
+ B[4] = m_b2;
+
+ double* inputP = m_inputBuffer.data();
+ double* outputP = m_outputBuffer.data();
+
+ double* input2P = inputP + 2;
+ double* output2P = outputP + 2;
+
+ // Break up processing into smaller slices (kBufferSize) if necessary.
+
+ int n = framesToProcess;
+
+ while (n > 0) {
+ int framesThisTime = n < kBufferSize ? n : kBufferSize;
+
+ // Copy input to input buffer
+ for (int i = 0; i < framesThisTime; ++i)
+ input2P[i] = *sourceP++;
+
+ processSliceFast(inputP, outputP, B, framesThisTime);
+
+ // Copy output buffer to output (converts float -> double).
+ for (int i = 0; i < framesThisTime; ++i)
+ *destP++ = static_cast<float>(output2P[i]);
+
+ n -= framesThisTime;
+ }
+}
+
+void Biquad::processSliceFast(double* sourceP, double* destP, double* coefficientsP, size_t framesToProcess)
+{
+ // Use double-precision for filter stability
+ vDSP_deq22D(sourceP, 1, coefficientsP, destP, 1, framesToProcess);
+
+ // Save history. Note that sourceP and destP reference m_inputBuffer and m_outputBuffer respectively.
+ // These buffers are allocated (in the constructor) with space for two extra samples so it's OK to access
+ // array values two beyond framesToProcess.
+ sourceP[0] = sourceP[framesToProcess - 2 + 2];
+ sourceP[1] = sourceP[framesToProcess - 1 + 2];
+ destP[0] = destP[framesToProcess - 2 + 2];
+ destP[1] = destP[framesToProcess - 1 + 2];
+}
+
+#endif // OS(DARWIN)
+
+
+void Biquad::reset()
+{
+ m_x1 = m_x2 = m_y1 = m_y2 = 0.0;
+
+#if OS(DARWIN)
+ // Two extra samples for filter history
+ double* inputP = m_inputBuffer.data();
+ inputP[0] = 0.0;
+ inputP[1] = 0.0;
+
+ double* outputP = m_outputBuffer.data();
+ outputP[0] = 0.0;
+ outputP[1] = 0.0;
+#endif
+}
+
+void Biquad::setLowpassParams(double cutoff, double resonance)
+{
+ resonance = std::max(0.0, resonance); // can't go negative
+
+ double g = pow(10.0, 0.05 * resonance);
+ double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0);
+
+ // Compute biquad coefficients for lopass filter
+ double theta = piDouble * cutoff;
+ double sn = 0.5 * d * sin(theta);
+ double beta = 0.5 * (1.0 - sn) / (1.0 + sn);
+ double gamma = (0.5 + beta) * cos(theta);
+ double alpha = 0.25 * (0.5 + beta - gamma);
+
+ m_a0 = 2.0 * alpha;
+ m_a1 = 2.0 * 2.0*alpha;
+ m_a2 = 2.0 * alpha;
+ m_b1 = 2.0 * -gamma;
+ m_b2 = 2.0 * beta;
+}
+
+void Biquad::setHighpassParams(double cutoff, double resonance)
+{
+ resonance = std::max(0.0, resonance); // can't go negative
+
+ double g = pow(10.0, 0.05 * resonance);
+ double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0);
+
+ // Compute biquad coefficients for highpass filter
+ double theta = piDouble * cutoff;
+ double sn = 0.5 * d * sin(theta);
+ double beta = 0.5 * (1.0 - sn) / (1.0 + sn);
+ double gamma = (0.5 + beta) * cos(theta);
+ double alpha = 0.25 * (0.5 + beta + gamma);
+
+ m_a0 = 2.0 * alpha;
+ m_a1 = 2.0 * -2.0*alpha;
+ m_a2 = 2.0 * alpha;
+ m_b1 = 2.0 * -gamma;
+ m_b2 = 2.0 * beta;
+}
+
+void Biquad::setLowShelfParams(double cutoff, double dbGain)
+{
+ double theta = piDouble * cutoff;
+
+ double A = pow(10.0, dbGain / 40.0);
+ double S = 1.0; // filter slope (1.0 is max value)
+ double alpha = 0.5 * sin(theta) * sqrt((A + 1.0 / A) * (1.0 / S - 1.0) + 2.0);
+
+ double k = cos(theta);
+ double k2 = 2.0 * sqrt(A) * alpha;
+
+ double b0 = A * ((A + 1.0) - (A - 1.0) * k + k2);
+ double b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * k);
+ double b2 = A * ((A + 1.0) - (A - 1.0) * k - k2);
+ double a0 = (A + 1.0) + (A - 1.0) * k + k2;
+ double a1 = -2.0 * ((A - 1.0) + (A + 1.0) * k);
+ double a2 = (A + 1.0) + (A - 1.0) * k - k2;
+
+ double a0Inverse = 1.0 / a0;
+
+ m_a0 = b0 * a0Inverse;
+ m_a1 = b1 * a0Inverse;
+ m_a2 = b2 * a0Inverse;
+ m_b1 = a1 * a0Inverse;
+ m_b2 = a2 * a0Inverse;
+}
+
+void Biquad::setZeroPolePairs(const Complex &zero, const Complex &pole)
+{
+ m_a0 = 1.0;
+ m_a1 = -2.0 * zero.real();
+
+ double zeroMag = abs(zero);
+ m_a2 = zeroMag * zeroMag;
+
+ m_b1 = -2.0 * pole.real();
+
+ double poleMag = abs(pole);
+ m_b2 = poleMag * poleMag;
+}
+
+void Biquad::setAllpassPole(const Complex &pole)
+{
+ Complex zero = Complex(1.0, 0.0) / pole;
+ setZeroPolePairs(zero, pole);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)