I’m looking to apply a low pass filter to some audio sources, but we cannot use the built in Audio Low Pass Filter, since we want to be able to apply the low pass to specific channels. So it looks like the best option would be to write a custom low pass filter in OnAudioFilterRead that directly applies the output to the data.
I’m very new to audio programming, and I’m looking for a resource to help with this. Low pass filters take in a cutoff frequency and use that to attenuate values above the frequency (leaving those below unaltered), but I’m not sure how to properly convert the PCM amplitude data that is passed into OnAudioFilterRead into frequencies (I assume it involves sampling adjacent amplitudes?). Wondering if anyone knows how the built in Audio Low Pass is implemented (the decompiled component only has external calls :()
Thanks for any help, and feel free to correct any incorrect assumptions I’ve made above!
I ran into a similar issue.
Thank you for the rewritten code you provided.
I made myself two functions HighPassFilter() and LowPassFilter(), which can be used when working with AudioClip.GetData()
When we have AudioClip and we make changes, then at one stage we need to remove the low frequencies, in this case we can call the HighPassFilter() function and pass it the parameters of your sound with all the data:
[HideInInspector]
private float c, a1, a2, a3, b1, b2;
public void HighPassFilter (float[] waveData, int channels, int audioSampleFrequency, int cutoffFrequency) {
c = Mathf.Tan (Mathf.PI * cutoffFrequency / audioSampleFrequency);
a1 = 1f / (1f + lowpassResonanceQ * c + c * c);
a2 = -2 * a1;
a3 = a1;
b1 = 2f * (c * c - 1f) * a1;
b2 = (1f - lowpassResonanceQ * c + c * c) * a1;
inputHistory[1] = 0;
inputHistory[0] = 0;
outputHistory[2] = 0;
outputHistory[1] = 0;
outputHistory[0] = 0;
//for 2-channel audio first 4 floats would be L[0], R[0], L[1], R[1]
for (int i = channels - 1; i < waveData.Length; i += channels) {
waveData[i] = AddInput (waveData[i]);
}
if (channels == 1) {
return;
}
for (int i = channels - 2; i < waveData.Length; i += channels) {
waveData[i] = AddInput (waveData[i]);
}
}
public void LowPassFilter (float[] waveData, int channels, int audioSampleFrequency, int cutoffFrequency) {
c = 1f / (float)Mathf.Tan (Mathf.PI * cutoffFrequency / audioSampleFrequency);
a1 = 1f / (1f + lowpassResonanceQ * c + c * c);
a2 = 2f * a1;
a3 = a1;
b1 = 2f * (1f - c * c) * a1;
b2 = (1f - lowpassResonanceQ * c + c * c) * a1;
inputHistory[1] = 0;
inputHistory[0] = 0;
outputHistory[2] = 0;
outputHistory[1] = 0;
outputHistory[0] = 0;
//for 2-channel audio first 4 floats would be L[0], R[0], L[1], R[1]
for (int i = channels - 1; i < waveData.Length; i += channels) {
waveData[i] = AddInput (waveData[i]);
}
if (channels == 1) {
return;
}
for (int i = channels - 2; i < waveData.Length; i += channels) {
waveData[i] = AddInput (waveData[i]);
}
}
[HideInInspector]
private float[] inputHistory = new float[2];
[HideInInspector]
private float[] outputHistory = new float[3];
private float AddInput (float newInput) {
float newOutput = a1 * newInput + a2 * inputHistory[0] + a3 * inputHistory[1] - b1 * outputHistory[0] - b2 * outputHistory[1];
inputHistory[1] = inputHistory[0];
inputHistory[0] = newInput;
outputHistory[2] = outputHistory[1];
outputHistory[1] = outputHistory[0];
outputHistory[0] = newOutput;
return outputHistory[0];
}