package AudioFilters; /** * N-Order IIR Filter * Assumes inputs are normalized to [-1, 1] * * Based on the difference equation from https://en.wikipedia.org/wiki/Infinite_impulse_response */ public class IIRFilter { private final int order; private final double[] coeffsA; private final double[] coeffsB; private final double[] historyX; private final double[] historyY; /** * Construct an IIR Filter * * @param order the filter's order * @throws IllegalArgumentException if order is zero or less */ public IIRFilter(int order) throws IllegalArgumentException { if (order < 1) { throw new IllegalArgumentException("order must be greater than zero"); } this.order = order; coeffsA = new double[order+1]; coeffsB = new double[order+1]; // Sane defaults coeffsA[0] = 1.0; coeffsB[0] = 1.0; historyX = new double[order]; historyY = new double[order]; } /** * Set coefficients * @param aCoeffs Denominator coefficients * @param bCoeffs Numerator coefficients * @throws IllegalArgumentException if {@code aCoeffs} or {@code bCoeffs} is not of size {@code order}, * or if {@code aCoeffs[0]} is 0.0 */ public void setCoeffs(double[] aCoeffs, double[] bCoeffs) throws IllegalArgumentException { if (aCoeffs.length != order) { throw new IllegalArgumentException("aCoeffs must be of size " + order + ", got " + aCoeffs.length); } if (aCoeffs[0] == 0.0) { throw new IllegalArgumentException("aCoeffs.get(0) must not be zero"); } if (bCoeffs.length != order) { throw new IllegalArgumentException("bCoeffs must be of size " + order + ", got " + bCoeffs.length); } for (int i = 0; i <= order; i++) { coeffsA[i] = aCoeffs[i]; coeffsB[i] = bCoeffs[i]; } } /** * Process a single sample * * @param sample the sample to process * @return the processed sample */ public double process(double sample) { double result = 0.0; // Process for (int i = 1; i <= order; i++) { result += (coeffsB[i] * historyX[i-1] - coeffsA[i] * historyY[i-1]); } result = (result + coeffsB[0] * sample) / coeffsA[0]; // Feedback for (int i = order-1; i > 0; i--) { historyX[i] = historyX[i-1]; historyY[i] = historyY[i-1]; } historyX[0] = sample; historyY[0] = result; return result; } }