/*
* 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 */
}
}