package com.fastbootmobile.encore.providers.bassboost; /** * Created by Guigui on 25/07/2014. */ public class BiQuadFilter { private static long toFixedPoint(double in) { return (long) (0.5 + in * (1L << 32)); } protected int mX1, mX2; protected int mY1, mY2; protected long mB0, mB1, mB2, mA1, mA2; protected long mB0dif, mB1dif, mB2dif, mA1dif, mA2dif; protected int mInterpolationSteps; public BiQuadFilter() { reset(); setCoefficients(0, 1, 0, 0, 1, 0, 0); } public static short clamp16(int sample) { if (((sample >> 15) ^ (sample >> 31)) != 0) { sample = 0x7FFF ^ (sample >> 31); } return (short) sample; } protected void setCoefficients(int steps, double a0, double a1, double a2, double b0, double b1, double b2) { long A1 = -toFixedPoint(a1 / a0); long A2 = -toFixedPoint(a2 / a0); long B0 = toFixedPoint(b0 / a0); long B1 = toFixedPoint(b1 / a0); long B2 = toFixedPoint(b2 / a0); if (steps == 0) { mA1 = A1; mA2 = A2; mB0 = B0; mB1 = B1; mB2 = B2; mInterpolationSteps = 0; } else { mA1dif = (A1 - mA1) / steps; mA2dif = (A2 - mA2) / steps; mB0dif = (B0 - mB0) / steps; mB1dif = (B1 - mB1) / steps; mB2dif = (B2 - mB2) / steps; mInterpolationSteps = steps; } } public void setHighShelf(int steps, double center_frequency, double sampling_frequency, double gainDb, double slope, double overallGainDb) { double w0 = 2.0 * Math.PI * center_frequency / sampling_frequency; double A = Math.pow(10.0, gainDb / 40.0); double alpha = Math.sin(w0) / 2.0 * Math.sqrt((A + 1.0 / A) * (1.0 / slope - 1.0) + 2.0); double b0 = A * ((A + 1.0) + (A - 1.0) * Math.cos(w0) + 2.0 * Math.sqrt(A) * alpha); double b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * Math.cos(w0)); double b2 = A * ((A + 1.0) + (A - 1.0) * Math.cos(w0) - 2.0 * Math.sqrt(A) * alpha); double a0 = (A + 1.0) - (A - 1.0) * Math.cos(w0) + 2.0 * Math.sqrt(A) * alpha; double a1 = 2.0 * ((A - 1) - (A + 1.0) * Math.cos(w0)); double a2 = (A + 1) - (A - 1.0) * Math.cos(w0) - 2.0 * Math.sqrt(A) * alpha; double overallGain = Math.pow(10.0, overallGainDb / 20.0); b0 *= overallGain; b1 *= overallGain; b2 *= overallGain; setCoefficients(steps, a0, a1, a2, b0, b1, b2); } public void setBandPass(int steps, double center_frequency, double sampling_frequency, double resonance) { double w0 = 2.0 * Math.PI * center_frequency / sampling_frequency; double alpha = Math.sin(w0) / (2.0 * resonance); double b0 = Math.sin(w0) / 2.0; double b1 = 0; double b2 = -Math.sin(w0) / 2.0; double a0 = 1.0 + alpha; double a1 = -2.0 * Math.cos(w0); double a2 = 1.0 - alpha; setCoefficients(steps, a0, a1, a2, b0, b1, b2); } public void setHighPass(int steps, double center_frequency, double sampling_frequency, double resonance) { double w0 = 2.0 * Math.PI * center_frequency / sampling_frequency; double alpha = Math.sin(w0) / (2.0 * resonance); double b0 = (1.0 + Math.cos(w0)) / 2.0; double b1 = -(1.0 + Math.cos(w0)); double b2 = (1.0 + Math.cos(w0)) / 2.0; double a0 = 1.0 + alpha; double a1 = -2.0 * Math.cos(w0); double a2 = 1.0 - alpha; setCoefficients(steps, a0, a1, a2, b0, b1, b2); } public void setLowPass(int steps, double center_frequency, double sampling_frequency, double resonance) { double w0 = 2.0 * Math.PI * center_frequency / sampling_frequency; double alpha = Math.sin(w0) / (2.0 * resonance); double b0 = (1.0 - Math.cos(w0)) / 2.0; double b1 = 1.0 - Math.cos(w0); double b2 = (1.0 - Math.cos(w0)) / 2.0; double a0 = 1.0 + alpha; double a1 = -2.0 * Math.cos(w0); double a2 = 1.0 - alpha; setCoefficients(steps, a0, a1, a2, b0, b1, b2); } public int process(int x0) { long y0 = mB0 * x0 + mB1 * mX1 + mB2 * mX2 + mA1 * mY1 + mA2 * mY2; y0 >>= 32; mY2 = mY1; mY1 = (int) y0; mX2 = mX1; mX1 = x0; /* Interpolate biquad parameters */ if (mInterpolationSteps != 0) { mInterpolationSteps--; mB0 += mB0dif; mB1 += mB1dif; mB2 += mB2dif; mA1 += mA1dif; mA2 += mA2dif; } return (int) y0; } public void reset() { mInterpolationSteps = 0; mA1 = 0; mA2 = 0; mB0 = 0; mB1 = 0; mB2 = 0; mX1 = 0; mX2 = 0; mY1 = 0; mY2 = 0; } }