/* * 21.04.2004 Original verion. davagin@udm.ru. * ----------------------------------------------------------------------- This * program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * ---------------------------------------------------------------------- */ package call.jeq; /** * Generic wrapper around IIR algorithm. Author: Dmitry Vaguine Date: 02.05.2004 * Time: 12:00:29 */ public class IIR extends IIRBase { /** * Max number of channels supported */ public final static int EQ_MAX_CHANNELS = 2; /** * Max bands supported by the code */ public final static int EQ_MAX_BANDS = 31; /** * Supported sample rates */ public final static float EQ_11025_RATE = 11025; public final static float EQ_22050_RATE = 22050; public final static float EQ_44100_RATE = 44100; public final static float EQ_48000_RATE = 48000; /** * Supported number of bands */ public final static int EQ_10_BANDS = 10; public final static int EQ_15_BANDS = 15; public final static int EQ_25_BANDS = 25; public final static int EQ_31_BANDS = 31; /* * Indexes for the history arrays These have to be kept between calls to * this function hence they are static */ private int i; private int j; private int k; /* History for two filters */ private XYData[][] dataHistory = new XYData[EQ_MAX_BANDS][EQ_MAX_CHANNELS]; private XYData[][] dataHistory2 = new XYData[EQ_MAX_BANDS][EQ_MAX_CHANNELS]; /* Coefficients */ private IIRCoefficients[] iircf; /* Equalizer config */ private IIRControls eqcfg; /* rate */ private float rate; /* channels */ private int channels; /* bands */ private int bands; /** * Constructs equalizer with given config * * @param bands * is the number of bands to be used * @param rate * is the sample rate of equalizer * @param channels * is the number of channels */ public IIR(int bands, float rate, int channels) { this.rate = rate; this.channels = channels; this.bands = bands; this.eqcfg = new IIRControls(bands, channels); if (!isParamsSupported(bands, rate, channels)) throw new IllegalArgumentException("Unsupported parameters"); initIIR(); } /** * Returns Controls of equalizer * * @return Controls of equalizer */ public IIRControls getControls() { return eqcfg; } /** * This is special method for checking of supported parameters of equalizer * * @param bands * is the number of bands * @param rate * is the sample rate of data * @param channels * is the number of channels * @return true if parameters are supported */ public static boolean isParamsSupported(int bands, float rate, int channels) { if (rate != EQ_11025_RATE && rate != EQ_22050_RATE && rate != EQ_44100_RATE && rate != EQ_48000_RATE) return false; switch (bands) { case EQ_10_BANDS: case EQ_15_BANDS: case EQ_25_BANDS: case EQ_31_BANDS: break; default: return false; } switch (channels) { case 1: case 2: break; default: return false; } return (rate != EQ_11025_RATE && rate != EQ_22050_RATE) || bands == EQ_10_BANDS; } /* Init the filters */ private void initIIR() { setFilters(); for (int ii = 0; ii < EQ_MAX_BANDS; ii++) for (int jj = 0; jj < EQ_MAX_CHANNELS; jj++) { dataHistory[ii][jj] = new XYData(); dataHistory2[ii][jj] = new XYData(); } i = 0; j = 2; k = 1; } private void setFilters() { if (rate == EQ_11025_RATE) iircf = iir_cf10_11k_11025; else if (rate == EQ_22050_RATE) iircf = iir_cf10_22k_22050; else if (rate == EQ_44100_RATE) { switch (bands) { case 31: iircf = iir_cf31_44100; break; case 25: iircf = iir_cf25_44100; break; case 15: iircf = iir_cf15_44100; break; default: iircf = iir_cf10_44100; break; } } else if (rate == EQ_48000_RATE) { switch (bands) { case 31: iircf = iir_cf31_48000; break; case 25: iircf = iir_cf25_48000; break; case 15: iircf = iir_cf15_48000; break; default: iircf = iir_cf10_48000; break; } } } /** * Clear filter history. */ public void cleanHistory() { /* Zero the history arrays */ for (int ii = 0; ii < EQ_MAX_BANDS; ii++) for (int jj = 0; jj < EQ_MAX_CHANNELS; jj++) { dataHistory[ii][jj].zero(); dataHistory2[ii][jj].zero(); } i = 0; j = 2; k = 1; } /** * Main filtering method. * * @param data * - data to be filtered * @param length * - length of data in buffer */ public void iir(int[] data, int length) { int index, band, channel; float eqpreamp[] = eqcfg.getPreamp(); float eqbands[][] = eqcfg.getBands(); double pcm, out; /** * IIR filter equation is y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] * - beta*y[n-2]) * * NOTE: The 2 factor was introduced in the coefficients to save a * multiplication * * This algorithm cascades two filters to get nice filtering at the * expense of extra CPU cycles */ IIRCoefficients tempcf; XYData tempd; for (index = 0; index < length; index += channels) { /* For each channel */ for (channel = 0; channel < channels; channel++) { /* Preamp gain */ pcm = data[index + channel] * eqpreamp[channel]; out = 0f; /* For each band */ for (band = 0; band < bands; band++) { /* Store Xi(n) */ tempd = dataHistory[band][channel]; tempd.x[i] = pcm; /* Calculate and store Yi(n) */ tempcf = iircf[band]; tempd.y[i] = ( /* = alpha * [x(n)-x(n-2)] */ tempcf.alpha * (pcm - tempd.x[k]) /* + gamma * y(n-1) */ + tempcf.gamma * tempd.y[j] /* - beta * y(n-2) */ - tempcf.beta * tempd.y[k]); /* * The multiplication by 2.0 was 'moved' into the * coefficients to save CPU cycles here */ /* Apply the gain */ out += (tempd.y[i] * eqbands[band][channel]); // * 2.0; } /* For each band */ /* * Volume stuff Scale down original PCM sample and add it to the * filters output. This substitutes the multiplication by 0.25 * Go back to use the floating point multiplication before the * conversion to give more dynamic range */ out += (pcm * 0.25); /* Normalize the output */ out *= 4; /* Round and convert to integer */ data[index + channel] = (int) out; } /* For each channel */ i++; j++; k++; /* Wrap around the indexes */ if (i == 3) i = 0; else if (j == 3) j = 0; else k = 0; }/* For each pair of samples */ } }