How do I make filters with sharp cutoff corners and steep slopes?

I know little to nothing about what I am doing, but I seem to be onto something, no thanks to any examples on the internet… I hope someone scouring Google or the forums for examples of how to use designIIRHighpassHighOrderButterworthMethod will find this useful.

While this seems to work so far, I have no idea if it correct or efficient, or if it will explode with memory leaks. For that reason maybe it is not a great example to follow.

Attached is a new screenshot comparing to the Pro-Q2; now they match. In the second screenshot, I moved the Pro-Q2 to the left a bit to show them separately.

Phase performance is another conversation; my filter suffers greatly in comparison.

I would greatly appreciate a critique of my code.

private:

//hpf
//each L/R pair is 12dB/oct
double hpfCutoffFrequency;
dsp::IIR::Filter<float> hpfSignalLeft1;
dsp::IIR::Filter<float> hpfSignalLeft2;
dsp::IIR::Filter<float> hpfSignalLeft3;
dsp::IIR::Filter<float> hpfSignalRight1;
dsp::IIR::Filter<float> hpfSignalRight2;
dsp::IIR::Filter<float> hpfSignalRight3;

//lpf
//each L/R pair is 12dB/oct
double lpfCutoffFrequency;
dsp::IIR::Filter<float> lpfSignalLeft1;
dsp::IIR::Filter<float> lpfSignalLeft2;
dsp::IIR::Filter<float> lpfSignalLeft3;
dsp::IIR::Filter<float> lpfSignalRight1;
dsp::IIR::Filter<float> lpfSignalRight2;
dsp::IIR::Filter<float> lpfSignalRight3;

ReferenceCountedArray<dsp::IIR::Coefficients<float>> hpfSignalLeftCoefficientsArray;
ReferenceCountedArray<dsp::IIR::Coefficients<float>> hpfSignalRightCoefficientsArray;
ReferenceCountedArray<dsp::IIR::Coefficients<float>> lpfSignalLeftCoefficientsArray;
ReferenceCountedArray<dsp::IIR::Coefficients<float>> lpfSignalRightCoefficientsArray;

in the constructor:

hpfCutoffFrequency = 250.0; //Hz
lpfCutoffFrequency = 2500.0; //Hz

prepareToPlay:

//each L/R pair is 12dB/oct
hpfSignalLeft1.reset();
hpfSignalLeft2.reset();
hpfSignalLeft3.reset();
hpfSignalRight1.reset();
hpfSignalRight2.reset();
hpfSignalRight3.reset();

hpfSignalLeftCoefficientsArray = dsp::FilterDesign<float>::designIIRHighpassHighOrderButterworthMethod (hpfCutoffFrequency, sampleRate, 6);
hpfSignalRightCoefficientsArray = dsp::FilterDesign<float>::designIIRHighpassHighOrderButterworthMethod (hpfCutoffFrequency, sampleRate, 6);

//each L/R pair is 12dB/oct
hpfSignalLeft1.coefficients = hpfSignalLeftCoefficientsArray.getObjectPointer(0);
hpfSignalLeft2.coefficients = hpfSignalLeftCoefficientsArray.getObjectPointer(1);
hpfSignalLeft3.coefficients = hpfSignalLeftCoefficientsArray.getObjectPointer(2);
hpfSignalRight1.coefficients = hpfSignalRightCoefficientsArray.getObjectPointer(0);
hpfSignalRight2.coefficients = hpfSignalRightCoefficientsArray.getObjectPointer(1);
hpfSignalRight3.coefficients = hpfSignalRightCoefficientsArray.getObjectPointer(2);




//each L/R pair is 12dB/oct
lpfSignalLeft1.reset();
lpfSignalLeft2.reset();
lpfSignalLeft3.reset();
lpfSignalRight1.reset();
lpfSignalRight2.reset();
lpfSignalRight3.reset();

lpfSignalLeftCoefficientsArray = dsp::FilterDesign<float>::designIIRLowpassHighOrderButterworthMethod (lpfCutoffFrequency, sampleRate, 6);
lpfSignalRightCoefficientsArray = dsp::FilterDesign<float>::designIIRLowpassHighOrderButterworthMethod (lpfCutoffFrequency, sampleRate, 6);

//each L/R pair is 12dB/oct
lpfSignalLeft1.coefficients = lpfSignalLeftCoefficientsArray.getObjectPointer(0);
lpfSignalLeft2.coefficients = lpfSignalLeftCoefficientsArray.getObjectPointer(1);
lpfSignalLeft3.coefficients = lpfSignalLeftCoefficientsArray.getObjectPointer(2);
lpfSignalRight1.coefficients = lpfSignalRightCoefficientsArray.getObjectPointer(0);
lpfSignalRight2.coefficients = lpfSignalRightCoefficientsArray.getObjectPointer(1);
lpfSignalRight3.coefficients = lpfSignalRightCoefficientsArray.getObjectPointer(2);

processBlock:

//do the highpass filtering in series to get 36dB/octave slope
//do the lowpass filtering in series to get 36dB/octave slope
if (channel == 0) {
	channelData[sample] = hpfSignalLeft1.processSample(channelData[sample]);
	hpfSignalLeft1.snapToZero();
	channelData[sample] = hpfSignalLeft2.processSample(channelData[sample]);
	hpfSignalLeft2.snapToZero();
	channelData[sample] = hpfSignalLeft3.processSample(channelData[sample]);
	hpfSignalLeft3.snapToZero();

	channelData[sample] = lpfSignalLeft1.processSample(channelData[sample]);
	lpfSignalLeft1.snapToZero();
	channelData[sample] = lpfSignalLeft2.processSample(channelData[sample]);
	lpfSignalLeft2.snapToZero();
	channelData[sample] = lpfSignalLeft3.processSample(channelData[sample]);
	lpfSignalLeft3.snapToZero();
}

if (channel == 1) {
	channelData[sample] = hpfSignalRight1.processSample(channelData[sample]);
	hpfSignalRight1.snapToZero();
	channelData[sample] = hpfSignalRight2.processSample(channelData[sample]);
	hpfSignalRight2.snapToZero();
	channelData[sample] = hpfSignalRight3.processSample(channelData[sample]);
	hpfSignalRight3.snapToZero();

	channelData[sample] = lpfSignalRight1.processSample(channelData[sample]);
	lpfSignalRight1.snapToZero();
	channelData[sample] = lpfSignalRight2.processSample(channelData[sample]);
	lpfSignalRight2.snapToZero();
	channelData[sample] = lpfSignalRight3.processSample(channelData[sample]);
	lpfSignalRight3.snapToZero();
}

Regards,

Fred

2 Likes