Advertisement

Can someone help me with code for a low pass filter

Started by December 10, 2024 10:19 AM
9 comments, last by Fedelinn 1 week, 6 days ago

Hi, Im making a synthesizer, and I need a filter, and I dont know how to code one.

I need a little help, can any one help me?

Here is my synth in action - there is no filters or eq running, its just purely using distortion and some simple code drawn wave forms.

youtube video→> (Just plug into url string.)

/watch?v=4rUsaQ0ntIQ&t=2s

In which language your synthesizer is coded, I mean python or c++?

Our project- spend bill gates money

Advertisement

c++! but doesnt matter tho cause i can convert it. a 2nd order filter would be appreciated alot thanks.

okay so here is a low-pass filter in C++ that you can integrate into your synthesizer. Hope it works for you.

#include <cmath>

class LowPassFilter {
public:
    LowPassFilter(float sampleRate, float cutoffFreq) 
        : sampleRate(sampleRate), cutoffFreq(cutoffFreq), prevInput(0.0f), prevOutput(0.0f) {
        calculateCoefficients();
    }

    void setCutoffFrequency(float cutoffFreq) {
        this->cutoffFreq = cutoffFreq;
        calculateCoefficients();
    }

    float process(float input) {
        // Apply the filter to a single sample
        float output = a0 * input + a1 * prevInput - b1 * prevOutput;
        prevInput = input;
        prevOutput = output;
        return output;
    }

private:
    float sampleRate;
    float cutoffFreq;
    float a0, a1, b1;
    float prevInput;
    float prevOutput;

    void calculateCoefficients() {
        float omega = 2.0f * M_PI * cutoffFreq / sampleRate;
        float alpha = omega / (omega + 1.0f);
        a0 = alpha;
        a1 = alpha;
        b1 = 1.0f - alpha;
    }
};


here is how to use:


#include <iostream>
#include <vector>

int main() {
    // Parameters
    float sampleRate = 44100.0f; // Hz
    float cutoffFreq = 1000.0f;

    // Create the filter
    LowPassFilter lpf(sampleRate, cutoffFreq);

    // Example input buffer (replace with your synth samples)
    std::vector<float> inputSamples = {0.5f, 0.4f, 0.3f, 0.2f, 0.1f};
    std::vector<float> outputSamples;

    // Process the samples
    for (float sample : inputSamples) {
        outputSamples.push_back(lpf.process(sample));
    }

    // Print the filtered output
    std::cout << "Filtered output: ";
    for (float sample : outputSamples) {
        std::cout << sample << " ";
    }
    std::cout << std::endl;

    return 0;
}

Our project- spend bill gates money

THANKS! ill post back and tell how goes!

I converted it to these two functions, quasimoto-c style, but unfortunately I am just passing through without affecting the sound, so are u positive this filter works? I wonder what ive stuffed up…


void calculate_coefficients(float cutoffFreq, float sampleRate, float& a0, float& a1, float& b1)
{
float omega = 2.0f * M_PI * cutoffFreq / sampleRate;
float alpha = omega / (omega + 1.0f);
a0 = alpha;
a1 = alpha;
b1 = 1.0f - alpha;
}


float process(float input, float& prevInput, float& prevOutput, float a0, float a1, float b1)
{
float output = a0 * input + a1 * prevInput - b1 * prevOutput;
prevInput = input;
prevOutput = output;
return output;
}

And then in the synthesizer sample render function

//SYNTH (sample value in sond)


float ca0, ca1, cb1;
static float pi=0, po=0;

calculate_coefficients(500, 44100, ca0, ca1, cb1);
sond = process(sond, pi, po, ca0, ca1, cb1);

//continue SYNTH

I was wondering too, if its possible to get a 2nd order filter?

Advertisement

I think there are two issues that could cause your filter to pass through without affecting the sound.

1. In your code, calculate_coefficients() is called within the sample render function for every sample, which recomputes the filter coefficients on every run. To fix this you need to move calculate_coefficients() outside the sample loop and call it only when necessary.

And 2nd is; the provided coefficients are for a simple first order low pass filter. If the cutoff frequency is set too high (for eg. close to the Nyquist frequency) the effect may be subtle especially if the input signal doesn't contain many high frequencies.

so here is corrected one:

Coefficient Calculation Function

void calculate_coefficients(float cutoffFreq, float sampleRate, float& a0, float& a1, float& b1) {
    float omega = 2.0f * M_PI * cutoffFreq / sampleRate;
    float alpha = omega / (omega + 1.0f);
    a0 = alpha;
    a1 = alpha;
    b1 = 1.0f - alpha;
}

Filter Processing Function

float process(float input, float& prevInput, float& prevOutput, float a0, float a1, float b1) {
    float output = a0 * input + a1 * prevInput - b1 * prevOutput;
    prevInput = input;
    prevOutput = output;
    return output;
}

Synthesizer Integration

// outside the sample render loop
float ca0, ca1, cb1;
static float prevInput = 0.0f, prevOutput = 0.0f;

// calculate coefficients once, or when cutoff frequency changes
calculate_coefficients(500.0f, 44100.0f, ca0, ca1, cb1);

// in the sample render loop
sond = process(sond, prevInput, prevOutput, ca0, ca1, cb1);

And to implement a second order low pass filter, we use the biquad filter formula. here is how;

Coefficient Calculation for 2nd Order

void calculate_biquad_coefficients(float cutoffFreq, float sampleRate, float Q, 
                                   float& a0, float& a1, float& a2, float& b1, float& b2) {
    float omega = 2.0f * M_PI * cutoffFreq / sampleRate;
    float alpha = sin(omega) / (2.0f * Q);

    float cos_omega = cos(omega);
    float norm = 1.0f / (1.0f + alpha);

    a0 = (1.0f - cos_omega) / 2.0f * norm;
    a1 = (1.0f - cos_omega) * norm;
    a2 = a0;
    b1 = -2.0f * cos_omega * norm;
    b2 = (1.0f - alpha) * norm;
}

Filter Processing for 2nd Order

float process_biquad(float input, float& prevInput1, float& prevInput2, 
                     float& prevOutput1, float& prevOutput2, 
                     float a0, float a1, float a2, float b1, float b2) {
    float output = a0 * input + a1 * prevInput1 + a2 * prevInput2
                   - b1 * prevOutput1 - b2 * prevOutput2;

    prevInput2 = prevInput1;
    prevInput1 = input;
    prevOutput2 = prevOutput1;
    prevOutput1 = output;

    return output;
}

Using the Biquad Filter

// outside the sample render loop
float a0, a1, a2, b1, b2;
static float prevInput1 = 0.0f, prevInput2 = 0.0f;
static float prevOutput1 = 0.0f, prevOutput2 = 0.0f;

// calculate coefficients once or when cutoff frequency changes
calculate_biquad_coefficients(500.0f, 44100.0f, 0.707f, a0, a1, a2, b1, b2);

// in the sample render loop
sond = process_biquad(sond, prevInput1, prevInput2, prevOutput1, prevOutput2, a0, a1, a2, b1, b2);

hope it work as expected…

Our project- spend bill gates money

Thanks!! Ill be back to show what happened to me!

Yeh it worked thanks!


Thanks so much, I was hunting yesterday as well, thought - why dont try a forum, so then i remembered gamedev and u were here!!

And it seems to have fixed the bug I had on the 1 pole leaky integrator, it was causing some bad feedback to happen, and I figured I needed the 2nd order, so Its in now thanks.

Ill be writing a 6 band parametric eq with it! its cool its got a q factor as well, its really good! So I just have to not lose it like I did the cook torrence shader I had and when I lost the fresenel component it wasnt on the internet anymore! so I was stuffed, so I have to make sure I dont lose this filter this time!!!

Thanks so much! Much appreciated I need to pay you back sometime.

It was cool how u put it in the form I needed for me, it just pasted straight in excellently! 🙂

You're welcome yo! Great to hear it worked for you.

Our project- spend bill gates money

Advertisement