IIRFilters Just Seem to Mute the audio


#1

I've been trying to implement some filters in my VST Plugin but they just seem to mute the signal.

Below is the code I used to implement it in the prepareToPlay() function.

m_kickCoeff.makePeakFilter(sampleRate,m_kFreqValue,(m_kFreqValue*m_kWidthValue)/100,2);
    m_kickFilter.setCoefficients(m_kickCoeff);

And below is the processBlock() function.

void HitDetectorAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)

{
    
    for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
        buffer.clear (i, 0, buffer.getNumSamples());
    
    for (int channel = 0; channel < getNumInputChannels(); ++channel)
    {
        float* channelData = buffer.getWritePointer (channel);
        m_kickFilter.processSamples(channelData, buffer.getNumSamples());
    }

    
}

m_kFreqValue is an integer with a value ranging from 20-20000 (100 default) , and m_kWidthValue is an integer ranging from 0 to 100 (10 default).

Does anyone have any idea what I'm doing wrong?


#2

makePeakFilter is a static method, so it doesn't alter the m_kickCoeff variable.

Try instead:

m_kickCoeff = IIRCoefficients::makePeakFilter(sampleRate,m_kFreqValue,(m_kFreqValue*m_kWidthValue)/100,2);

Good luck.


#3

Thanks, but unfortunately it hasn't made any difference. I'm sure the "IIRCoefficients::" part is irrelevant as I declared m_kickCoeff as:

IIRCoefficients m_kickCoeff;

in the header.


#4

I'm sure the "IIRCoefficients::" part is irrelevant

It's not, because a static method has no access to member variables. So calling makePeakFilter does not set any coefficients. You can check that using the debugger or print out the coefficients before and after the makePeakFilter call, if you doubt that.

Instead the makePeakFilter method returns a new IIRCoefficients instance with the required coefficients. You see that in the source code:

https://github.com/julianstorer/JUCE/blob/master/modules/juce_audio_basics/effects/juce_IIRFilter.cpp#L142

The change is not the IIRCoefficients:: namespace, but to set the return value of the static method to m_kickCoeff.


m_kickCoeff = IIRCoefficients::makePeakFilter(sampleRate,m_kFreqValue,(m_kFreqValue*m_kWidthValue)/100,2);

The bold part is the important change.

Good luck

N.B. from the docs of the IIRCoefficients:

IIRCoefficients::IIRCoefficients ( )

Creates a null set of coefficients (which will produce silence).

 


#5

... and the big (but common) mistake is using the same filter object for multiple channels. You need an array of IIRCoefficients objects and use a different one for each channel.


#6

I’m having the same problem (can’t hear any output) what’s wrong with my code?

[code]

void LpfilterAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
setLeftCoeffs = IIRCoefficients::makeLowPass(sampleRate, cutoffFrequency);
setRightCoeffs = IIRCoefficients::makeLowPass(sampleRate, cutoffFrequency);

lowPassFilterL.setCoefficients(setLeftCoeffs);
    lowPassFilterR.setCoefficients(setRightCoeffs);

}

void LpfilterAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{

float* channelDataLeft = buffer.getWritePointer(0);
    float* channelDataRight = buffer.getWritePointer(1);

    int totalNumSamples = buffer.getNumSamples();

    lowPassFilterL.processSamples(channelDataLeft, totalNumSamples);
    lowPassFilterR.processSamples(channelDataRight, totalNumSamples);

} [/code]


#7

Hmm, I figured out why it was muted. The filter is only being modified/set when prepareToPlay is called. How do I manipulate the cutoff frequency while audio is actually playing? I have set up a slider to control my cutoffFrequency member variable in AudioProcessor. I can only hear the cutoff change after prepareToPlay has been called… I tried calling setCoefficients in processBlock but that didn’t seem to work either. I’ve also tried calling it in sliderValueChanged which does not seem to work again.


#8

Are you also calling setCoefficients on the filter? You don’t need to store the coefficients extra, you can call directly:
lowPassFilterL.setCoefficients (IIRCoefficients::makeLowPass (sampleRate, cutoffFrequency));
Only changing your setLeftCoeffs variable doesn’t change the filter…


#9

When I call directly like that, firstly I get screaming feedback (I am clearing the buffer in processBlock to attempt to avoid this), then when I force a call to prepareToPlay after changing the cutoff slider I get the same behaviour as previously described. Should I be calling setCoefficients in processBlock? I’m only calling setCoefficients in prepareToPlay currently…


#10

Tried calling in processBlock, now it actually works but I still get crazy feedback when I first instantiate my plugin and play audio.


#11

OK, I fixed it by storing the coeffs in setLeftCoeffs in prepareToPlay and calling setCoefficients directly on the filter in processBlock. Seems to be ok now.


#12

I was having the same problem, this solved it for me too. I don’t get it why…
This isn’t working in process block:

LPCoef1.makeLowPass(getSampleRate(), 200);
LP1.setCoefficients(LPCoef1)

But this works:

LP1.setCoefficients(IIRCoefficients::makeLowPass(getSampleRate(), 200));


#13

Because IIRCoefficients::makeLowPass() is a static member. It cannot change the instance (i.e. set coefficients inside the instance), even if you are calling it with an instance, see e.g.

http://en.cppreference.com/w/cpp/language/static
Static member functions:
Static member functions are not associated with any object. When called, they have no this pointer.


#14

I modified my code significantly since this was posted. I figured I only need to set the coefficients when something changes, so I created a processor.setFilterProperties() method and set the coefficients for the filter here. This method is called by the editor in sliderValueChanged() when I change the slider.

void MyAudioProcessor::setFilterProperties()
{
    switch (filterType)
    {
	case shelf:
	    myFilter.setCoefficients(IIRCoefficients::makeLowShelf(sampleRate, cutoffFreq.getNextValue(), resonance.getNextValue(), gainLevel.getNextValue()));
	    break;
	case lowPass:
	    myFilter.setCoefficients(IIRCoefficients::makeLowPass(sampleRate, cutoffFreq.getNextValue()));
	    break;
	case highPass:
	    myFilter.setCoefficients(IIRCoefficients::makeHighPass(sampleRate, cutoffFreq.getNextValue()));
            break;
	case peak:
	    myFilter.setCoefficients(IIRCoefficients::makePeakFilter(sampleRate, cutoffFreq.getNextValue(), resonance.getNextValue(), gainLevel.getNextValue()));
	    break;
    }
}

So now prepareToPlay() looks something like this:

 void MyAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
 {
     myFilter.reset();
 }

processBlock() looks something like this:

void MyAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    // In case we have more outputs than inputs, this code clears any output
    // channels that didn't contain input data.   
	for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
		buffer.clear(i, 0, buffer.getNumSamples());
	
	for (int i = 0; i < numChannels; i++)
	{
	     myFilter.processSamples(buffer.getWritePointer(channel), buffer.getNumSamples());
	}	
}

This worked for me. I’ve extended it to a multi-band EQ plug-in.