package jass.generators;
/** Reson filter.
@author Kees van den Doel (kvdoel@cs.ubc.ca)
*/
public class ResonFilter implements Filter {
static final double cosh(double x) {
return (Math.exp(x) + Math.exp(-x))/2;
}
static final double sinh(double x) {
return (Math.exp(x) - Math.exp(-x))/2;
}
/** Sampling rate in Hertz. */
protected float srate;
/** State of filter. */
private float yt_1, yt_2;
/** Cached value. */
private float c_i;
/** The transfer function of a reson filter is H(z) = 1/(1-twoRCosTheta/z + R2/z*z). */
private float R2;
/** The transfer function of a reson filter is H(z) = 1/(1-twoRCosTheta/z + R2/z*z). */
private float twoRCosTheta;
/** Reson filter gain. */
private float ampR;
/** Create and initialize.
@param srate sampling rate in Hertz.
*/
public ResonFilter(float srate) {
this.srate = srate;
reset();
}
/** Set the reson coefficients and gain. Cache c_i.
@param f resonance frequency in Hertz.
@param d damping in radians/s.
@param a gain.
*/
public void setResonCoeff(float f, float d, float a) {
float tmp_r = (float)(Math.exp(-d/srate));
R2 = tmp_r*tmp_r;
if(f > 0) {
twoRCosTheta = (float)(2*Math.cos(2*Math.PI*f/srate)*tmp_r);
c_i = (float)(Math.sin(2*Math.PI*f/srate)*tmp_r);
} else {
twoRCosTheta = (float)(cosh(2*Math.PI*f/srate)*tmp_r);
//c_i = (float)(sinh(-2*Math.PI*f/srate)*tmp_r);
c_i = 1;
}
setGain(a);
}
/** Set gain.
@param a gain.
*/
public void setGain(float a) {
ampR = a * c_i;
}
/** Reset state.
*/
public void reset() {
yt_1 = yt_2 = 0;
}
/** Proces input (may be same as output).
@param output user provided buffer for returned result.
@param input user provided input buffer.
@param nsamples number of samples written to output buffer.
@param inputOffset where to start in circular buffer input.
*/
public void filter(float [] output, float[] input, int nsamples, int inputOffset) {
float ynew=0;
if(inputOffset == 0) {
for(int k=0;k<nsamples;k++) {
ynew = twoRCosTheta * yt_1 - R2 * yt_2 + ampR * input[k];
yt_2 = yt_1;
yt_1 = ynew;
output[k] = ynew;
}
// System.out.println(R2+" "+ynew);
} else {
int inputLen = input.length;
int ii = inputOffset;
for(int k=0;k<nsamples;k++) {
ynew = twoRCosTheta * yt_1 - R2 * yt_2 + ampR * input[ii];
yt_2 = yt_1;
yt_1 = ynew;
output[k] = ynew;
if(ii == inputLen - 1) {
ii = 0;
} else {
ii++;
}
}
}
}
/** Proces a single sample. Use thgis to use ResonFilter in stand-alone mode (i.e., not
in a patch.
@return returned result.
@param input user provided input sample
*/
public float filter1Sample(float input) {
float ynew=0;
ynew = twoRCosTheta * yt_1 - R2 * yt_2 + ampR * input;
yt_2 = yt_1;
yt_1 = ynew;
return ynew;
}
}