package jp.sourceforge.ocmml.android; import java.nio.DoubleBuffer; public class Filter { public static final int LPF_QUALITY = 1; public static final int LPF_FAST = 2; public static final int NONE = 0; public static final int HPF_FAST = -2; public static final int HPF_QUALITY = -1; public void reset() { mT1 = mT2 = mB0 = mB1 = mB2 = mB3 = mB4 = 0; } public void getSample(DoubleBuffer samples, int start, int end) { double k = getKeyValue(mKey); mFb = 0; switch (mType) { case HPF_FAST: for (int i = start; i < end; i++) { mCut = Channel.getFrequencyFromIndex((int)(mFrequency + mAmount * mEnvelope.getNextAmplitudeLinear())) * k; updateValueForFastFilter(samples.get(i)); samples.put(i, mInput - mB4); } break; case HPF_QUALITY: if (mAmount > 0.0001 || mAmount < -0.0001) { for (int i = start; i < end; i++) { mCut = Channel.getFrequencyFromIndex((int)(mFrequency + mAmount * mEnvelope.getNextAmplitudeLinear())) * k; updateCutAndFb(); updateSamplesForHPFQuality(samples, i, mCut, mFb); } } else { mCut = Channel.getFrequencyFromIndex((int)(mFrequency + mAmount * mEnvelope.getNextAmplitudeLinear())) * k; updateCutAndFb(); for (int i = start; i < end; i++) updateSamplesForHPFQuality(samples, i, mCut, mFb); } break; case LPF_QUALITY: mFb = 0; if (mAmount > 0.0001 || mAmount < -0.0001) { for (int i = start; i < end; i++) { mCut = Channel.getFrequencyFromIndex((int)(mFrequency + mAmount * mEnvelope.getNextAmplitudeLinear())) * k; updateCutAndFb(); updateSamplesForLPFQuality(samples, i, mCut, mFb); } } else { mCut = Channel.getFrequencyFromIndex((int)(mFrequency + mAmount * mEnvelope.getNextAmplitudeLinear())) * k; updateCutAndFb(); for (int i = start; i < end; i++) updateSamplesForLPFQuality(samples, i, mCut, mFb); } break; case LPF_FAST: for (int i = start; i < end; i++) { mCut = Channel.getFrequencyFromIndex((int)(mFrequency + mAmount * mEnvelope.getNextAmplitudeLinear())) * k; updateValueForFastFilter(samples.get(i)); samples.put(i, mB4); } break; default: break; } } public int getSwitch() { return mType; } public void setSwitch(int value) { reset(); mType = value; } public Envelope getEnvelope() { return mEnvelope; } public void setEnvelope(Envelope value) { mEnvelope = value; } public double getFrequency() { return mFrequency; } public void setFrequency(double value) { mFrequency = value; } public double getAmount() { return mAmount; } public void setAmount(double value) { mAmount = value; } public double getResonance() { return mResonance; } public void setResonance(double value) { mResonance = value; } public double getKey() { return mKey; } public void setKey(double value) { mKey = value; } private void updateCutValue() { if (mCut < 1.0 / 127.0) mCut = 0; mCut = Math.min(mCut, 1.0 - 0.0001); } private void updateCutAndFb() { updateCutValue(); mFb = mResonance + mResonance / (1.0 - mCut); } private double getKeyValue(double key) { return key * (2.0 * Math.PI / (Sample.RATE * Sample.FREQUENCY_BASE)); } private void updateSamplesForHPFQuality(DoubleBuffer samples, int index, double cut, double fb) { double input = samples.get(index); mB0 = mB0 + cut * (input - mB0 + fb * (mB0 - mB1)); mB1 = mB1 + cut * (mB0 - mB1); samples.put(index, input - mB0); } private void updateSamplesForLPFQuality(DoubleBuffer samples, int index, double cut, double fb) { mB0 = mB0 + cut * (samples.get(index) - mB0 + fb * (mB0 - mB1)); mB1 = mB1 + cut * (mB0 - mB1); samples.put(index, mB1); } private void updateValueForFastFilter(double sample) { updateCutValue(); double q = 1.0 - mCut; double p = mCut + 0.8 * mCut * q; double f = p + p - 1.0; q = mResonance * (1.0 + 0.5 * q * (1.0 - q + 5.6 * q * q)); mInput = sample; mInput -= q * mB4; mT1 = mB1; mB1 = (mInput + mB0) * p - mB1 * f; mT2 = mB2; mB2 = (mB1 + mT1) * p - mB2 * f; mT1 = mB3; mB3 = (mB2 + mT2) * p - mB3 * f; mB4 = (mB3 + mT1) * p - mB4 * f; mB4 = mB4 - mB4 * mB4 * mB4 * 0.16667; mB0 = mInput; } private int mType; private Envelope mEnvelope; private double mFrequency; private double mAmount; private double mResonance; private double mKey; private double mCut; private double mInput; private double mFb; private double mT1; private double mT2; private double mB0; private double mB1; private double mB2; private double mB3; private double mB4; }