Confused as to Why My Filter Isn't Filtering


#1

Hi everyone,

So I’m currently creating a plugin to generate white noise and filter it to produce a recursive resonator. I’ve managed to generate noise but having trouble with the filtering operation as when I call my filtering method it seems to not affect it and when I run the plugin in the debugger only the white noise is audible.

It seems to compile fine but isn’t doing anything. Here is the different sections of my code required to use the filter: (I decided to build these all within the PluginProcessor.cpp)

void KrotosResonatorAudioProcessor::Iirnotch(double f, double r) {
    buffer1 = 0;
    buffer2 = 0;
    output_acc = 0.0;
    
    b0 = 1;
    b1 = -2*cos(2*M_PI*f);
    b2 = 1;
    a0 = 1;
    a1 = -2*r*cos(2*M_PI*f);
    a2 = r*r;
    
}

double KrotosResonatorAudioProcessor::myFilter(double data) {
    double input_acc;
    double output_acc;
    
    input_acc = data;
    input_acc = input_acc - (a1*buffer1);
    input_acc = input_acc - (a2*buffer2);
    
    //accumulator for the FIR part
    output_acc = input_acc*b0;
    output_acc = output_acc + (b1*buffer1);
    output_acc = output_acc + (b2*buffer2);
    
    buffer2 = buffer1;
    buffer1 = input_acc;
    
    return output_acc;
    
}

I set the IIR coefficients within the contructor, so that they are set as soon as the plugin is run:

KrotosResonatorAudioProcessor::KrotosResonatorAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
{
    random = new Random();
    Iirnotch(f, r);
}

This is where I call the filtering operation ( within processBlock):

void KrotosResonatorAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    
    //std::cout << "Herroooo";
    
    buffer.clear();
    
    //MidiBuffer processedMidi;
    //int time;
    //MidiMessage m;
    
    for(int chan=0; chan<buffer.getNumChannels(); chan++)
    {
        float * const float_buffer = buffer.getWritePointer(chan, 0);
        for(int i = 0;i<buffer.getNumSamples();i++)
        {
            float_buffer[i] = random->nextFloat();
            float_buffer[i] = myFilter(float_buffer[i]);
        }
    
    }
 }

If anyone can spot where I’m going wrong here and point me in the right direction, that would be a massive help! oh and a bunch of things have been set in the header file for example:

double myFilter(double data);
void Iirnotch(double f, double r);

double buffer1 = 0;
double buffer2 = 0;
float output_acc = 0.0;
double f = 2000/44100;
float r = 0.999;

double b0;
float b1;
double b2;
double a0;
float a1;
float a2;

#2

Why is float_buffer a const?


#3

I took it from one of the juce tutorials for white noise generation and didnt realise that it probably shouldn’t be const. I changed it to float instead just there but doesn’t make any difference to the issue.


#4

Looks like you’re running all the current channels of audio through the same filter. If you only process data for channel 0 it should work.

If you want to handle multiple channels, then you need to implement multiple buffers to store the filter state.


#5

This is one of several common mistakes, it would be really good to have a FAQ or WIKI we could just point the people to…

It could really be community driven, there are so many experienced users happy to help…
Together with other insights like host specific behaviour etc…


#6

It’s fine that way, the pointer is const not the data. You can modify the audio but you can’t change the pointer to point to another array.


#7

I’ve managed to get it filtering now but unfortunately getting discontinuities (crackling) when running through 2 channels. Andrew_J I’m trying to follow your advice by creating multiple buffers but it hasn’t resolved the problem. I’ll try some more trial and error to see if i’m just overlooking something.


#8

How did you implement that? The filter state is in your case a0, a1, a2 and b0, b1, b2.
You need that separate for each channel (like @Andrew_J said, just don’t confuse buffer and state).
Your myFilter method changes the same state for both channels, which makes the filtered data jump after each buffer.


#9

Your filter structure does not implement the filter you think it does. Rewriting your code in a difference equation yields:

q = x[n] - a1 q[n-1] - a2 q[n-2]

y[n] = b0 q[n] + b1 q[n-1] + b2 q[n-2]

where q[n] is what you’re calling “input_accum.”

Notice that q[n] doesn’t depend on y[n], you’re not feeding back the output to implement the IIR filter that you want.

If you meant to implement a T-DFII filter structure, it should look like this:

float tdf2Biquad(float x)
{
    float y = b0 * x + q_z2;
    q_z2 = b1 * x - a1 * y + q_z1;
    q_z1 = b2 * x - a2 * y;
    return y;
}

Where q_z1, q_z2 are essentially the same thing you’re calling “buffer1"and 'buffer2”.


#10

@Holy_City Cheers for the pointers there. That is a much more improved result thanks very much!

I’d like to report that I’ve now got it running well enough by filtering for a mono output. I realised there were some mistakes in my code for the filter implementation including reinitialising my input_acc and output_acc every time the method is called. I have also redesigned the filter to receive buffer arrays rather than individual samples and running through these samples within the filtering function. It is also now a void function which takes an array name and pointer to its size. My coefficients have also changed which are producing a much better result as a narrow bandpass to create the resonator.

Thanks everyone for your tips and advice! Got there in the end! :slight_smile: