package com.nerdscentral.audio.pitch.algorithm; import com.nerdscentral.audio.core.SFConstants; /* * RBJ Filters from C++ version by arguru[AT]smartelectronix[DOT]com based on eq filter cookbook by Robert Bristow-Johnson * <rbj@audioimagination.com> This code is believed to be public domain and license free after best efforts to establish its * licensing. */ public class SFRBJFilter { // filter coeffs double b0a0, b1a0, b2a0, a1a0, a2a0; // in/out history double ou1, ou2, in1, in2; public SFRBJFilter() { // reset filter coeffs b0a0 = b1a0 = b2a0 = a1a0 = a2a0 = 0.0; // reset in/out history ou1 = ou2 = in1 = in2 = 0.0f; } public double filter(double in0) { // filter final double yn = b0a0 * in0 + b1a0 * in1 + b2a0 * in2 - a1a0 * ou1 - a2a0 * ou2; // push in/out buffers in2 = in1; in1 = in0; ou2 = ou1; ou1 = yn; // return output return yn; } public double limitedFilter(double in0) { // filter double yn = b0a0 * in0 + b1a0 * in1 + b2a0 * in2 - a1a0 * ou1 - a2a0 * ou2; double ay = yn < 0 ? -yn : yn; if(ay > 1.0) { yn = yn < 0 ? -1.0 : 1.0; } // push in/out buffers in2 = in1; in1 = in0; ou2 = ou1; ou1 = yn; // return output return yn; } public enum FilterType { LOWPASS, HIGHPASS, BANDPASS_SKIRT, BANDPASS_PEAK, NOTCH, ALLPASS, PEAK, LOWSHELF, HIGHSHELF } public void calc_filter_coeffs(final FilterType type, final double frequency, final double q, final double db_gain) { boolean q_is_bandwidth; final double sample_rate = SFConstants.SAMPLE_RATE; switch (type) { case ALLPASS: case HIGHPASS: case LOWPASS: case LOWSHELF: case HIGHSHELF: q_is_bandwidth = false; break; default: q_is_bandwidth = true; break; } // System.out.println("Q Is Bandwidth " + q_is_bandwidth); // temp pi final double temp_pi = 3.1415926535897932384626433832795; // temp coef vars double alpha, a0 = 0, a1 = 0, a2 = 0, b0 = 0, b1 = 0, b2 = 0; // peaking, lowshelf and hishelf if (type == FilterType.PEAK || type == FilterType.HIGHSHELF || type == FilterType.LOWSHELF) { final double A = Math.pow(10.0, (db_gain / 40.0)); final double omega = 2.0 * temp_pi * frequency / sample_rate; final double tsin = Math.sin(omega); final double tcos = Math.cos(omega); if (type == FilterType.PEAK) alpha = tsin * Math.sinh(Math.log(2.0) / 2.0 * q * omega / tsin); else alpha = tsin / 2.0 * Math.sqrt((A + 1 / A) * (1 / q - 1) + 2); final double beta = Math.sqrt(A) / q; // peaking if (type == FilterType.PEAK) { b0 = (1.0 + alpha * A); b1 = (-2.0 * tcos); b2 = (1.0 - alpha * A); a0 = (1.0 + alpha / A); a1 = (-2.0 * tcos); a2 = (1.0 - alpha / A); } // lowshelf if (type == FilterType.LOWSHELF) { b0 = (A * ((A + 1.0) - (A - 1.0) * tcos + beta * tsin)); b1 = (2.0 * A * ((A - 1.0) - (A + 1.0) * tcos)); b2 = (A * ((A + 1.0) - (A - 1.0) * tcos - beta * tsin)); a0 = ((A + 1.0) + (A - 1.0) * tcos + beta * tsin); a1 = (-2.0 * ((A - 1.0) + (A + 1.0) * tcos)); a2 = ((A + 1.0) + (A - 1.0) * tcos - beta * tsin); } // hishelf if (type == FilterType.HIGHSHELF) { b0 = (A * ((A + 1.0) + (A - 1.0) * tcos + beta * tsin)); b1 = (-2.0 * A * ((A - 1.0) + (A + 1.0) * tcos)); b2 = (A * ((A + 1.0) + (A - 1.0) * tcos - beta * tsin)); a0 = ((A + 1.0) - (A - 1.0) * tcos + beta * tsin); a1 = (2.0 * ((A - 1.0) - (A + 1.0) * tcos)); a2 = ((A + 1.0) - (A - 1.0) * tcos - beta * tsin); } } else { // other filters final double omega = 2.0 * temp_pi * frequency / sample_rate; final double tsin = Math.sin(omega); final double tcos = Math.cos(omega); if (q_is_bandwidth) alpha = tsin * Math.sinh(Math.log(2.0) / 2.0 * q * omega / tsin); else alpha = tsin / (2.0 * q); // lowpass if (type == FilterType.LOWPASS) { b0 = (1.0 - tcos) / 2.0; b1 = 1.0 - tcos; b2 = (1.0 - tcos) / 2.0; a0 = 1.0 + alpha; a1 = -2.0 * tcos; a2 = 1.0 - alpha; } // hipass if (type == FilterType.HIGHPASS) { b0 = (1.0 + tcos) / 2.0; b1 = -(1.0 + tcos); b2 = (1.0 + tcos) / 2.0; a0 = 1.0 + alpha; a1 = -2.0 * tcos; a2 = 1.0 - alpha; } // bandpass csg if (type == FilterType.BANDPASS_SKIRT) { b0 = tsin / 2.0; b1 = 0.0; b2 = -tsin / 2; a0 = 1.0 + alpha; a1 = -2.0 * tcos; a2 = 1.0 - alpha; } // bandpass czpg if (type == FilterType.BANDPASS_PEAK) { b0 = alpha; b1 = 0.0; b2 = -alpha; a0 = 1.0 + alpha; a1 = -2.0 * tcos; a2 = 1.0 - alpha; } // notch if (type == FilterType.NOTCH) { b0 = 1.0; b1 = -2.0 * tcos; b2 = 1.0; a0 = 1.0 + alpha; a1 = -2.0 * tcos; a2 = 1.0 - alpha; } // allpass if (type == FilterType.ALLPASS) { b0 = 1.0 - alpha; b1 = -2.0 * tcos; b2 = 1.0 + alpha; a0 = 1.0 + alpha; a1 = -2.0 * tcos; a2 = 1.0 - alpha; } } // set filter coeffs b0a0 = (b0 / a0); b1a0 = (b1 / a0); b2a0 = (b2 / a0); a1a0 = (a1 / a0); a2a0 = (a2 / a0); } }