SynthMaker

Equalizer

Archive · 2005 26 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

jorge ·

I tried to do an equalizer a couple of weeks ago, didnt quite get it finished and now I'm too busy with other stuff. I thought I'd post it anyway just in case someone wants to finish it. You can at least learn ( if you dont know already ) how to use two poly code components to process 8 mono channels simultaneously using the pack and unpack components. It could also be 1 poly code component to process two stereo channels simultaneously.

[old link]

Nu Audio Science ·

Niiiiiiiiiiiiiiice

Tom7777 ·

cool 🙂

unkargherth ·

Nice.. a Zoelzer Peaking combi Biquad !!!!

As far as i know teh standard Biquad lowpass is a Zoeltzer Biquad to. I've got an alpha version of Zoeltzer high pass. we shoudl be try to develop de Shelving ones and also bandpass and notch ones. The we have to FULL fledged Filter sets ( RBJ Biquads, thanks to Shiffrin) and Zoelzer ones

I know only avery little set of VST's that implements both, so could be a nice plus for SM

Shifrin ·

Ooh this looks interesting jorge! Gonna have a good look at it!

Thanks very much, like Unk said would be great to have a full set of Zoelzer filters to add to RBJ 🙂

Shif.

lalo ·

super-cool jorge 😀

rl ·

the eq10.osm opens a couple of questions:

I was wondering in the past how I could do filter coefficient calculations in the code component with minium cpu load - only recalculate the coefficients if parameters like cutoff, resonance, slope,.... change. Seeing the example code I assume the coefficient calculation is done at sample rate :-(

Is my assumption right that the so-called Lowpass Filter (2P2Z) is a generic 2nd order biquad? What's the transfer function (I'm asking because filter lectures often mix coefficient signs - esp. neg/pos signs of b-coefficients). Is there any difference in using this module to using a custom code module? e.g.:

polyout out; polyin in; polyin a0; polyin a1; polyin a2; polyin b1; polyin b2;

float in1, in2; float out1, out2;

out=a0*in + a1*in1 + a2*in2 - b1*out1 - b2*out2; in2=in1; in1=in; out2=out1; out1=out;

unkargherth ·

rl wrote: the eq10.osm opens a couple of questions:

I was wondering in the past how I could do filter coefficient calculations in the code component with minium cpu load - only recalculate the coefficients if parameters like cutoff, resonance, slope,.... change. Seeing the example code I assume the coefficient calculation is done at sample rate :-(

Not completely true. You can calculate a0,a1,a2,b1,b2 in one code module ( as they do not need the current sample to get calculated) and pass the 5 coeffs to the filter Engine as a polyins. You only need to calculate them Inside filter engine if you plan to modulate them at audio rates

rl wrote: Is my assumption right that the so-called Lowpass Filter (2P2Z) is a generic 2nd order biquad? What's the transfer function (I'm asking because filter lectures often mix coefficient signs - esp. neg/pos signs of b-coefficients). Is there any difference in using this module to using a custom code module? e.g.:

polyout out; polyin in; polyin a0; polyin a1; polyin a2; polyin b1; polyin b2;

float in1, in2; float out1, out2;

out=a0*in + a1*in1 + a2*in2 - b1*out1 - b2*out2; in2=in1; in1=in; out2=out1; out1=out;

Is a generic biquad, but code above it's only true if you pre-divided all coeffs by the missing b0

In theory this means That any calculation giving the correct coeffs should give the appropiate result. All kind of math tricks you could use that end setting poles and zeros in correct points in z-plane should be ok. But my personla opinion is "Not count on this"

for reference, you could find the standard 2P2Z calculations in musicdsp.org archive, under "Zoelzer biquad filters"

jorge ·

rl wrote: Is my assumption right that the so-called Lowpass Filter (2P2Z) is a generic 2nd order biquad? What's the transfer function (I'm asking because filter lectures often mix coefficient signs - esp. neg/pos signs of b-coefficients).

Here is a schematic for comparing two implementations of the same filter:

[old link] You could use a similar technique for comparing with a code component version of it. I think looking at the biquad schematic above will probably answer your question about the coefficients.

jorge ·

rl wrote: the eq10.osm opens a couple of questions:

I was wondering in the past how I could do filter coefficient calculations in the code component with minium cpu load - only recalculate the coefficients if parameters like cutoff, resonance, slope,.... change. Seeing the example code I assume the coefficient calculation is done at sample rate :-(

If your coefficients only change due to GUI interaction and dont need updating after, just use green float components for the coefficients section, that way the coefficients will only be calculated once and wont use any CPU after. If you want the coefficients to update but at a slow rate, you can use the hop function like:

hop ( 4 ) { // calculate coefficients here // will only run for every 4th sample } // filter sample rate processing here

rl ·

Thanks for your answers.

I know the math for coeff. calculations. My question was for the most efficient way to do them. I could draw a schematic with all the maths on green float data as jorge suggested (calculations only on data change), but writing a couple of code-lines is much faster for me. (Typing the calculation in a code module took me a minute, drawing the same in a schematic at least ten minutes)

If I write a code module that does only coefficient calculations and pass the coeffs to a 2P2Z, these calculations are done at sample rate, right?

This example should explain why I'm struggling here:

I would simply like to express (as in good old C)

polyin cf; polyin res; float t0, t1, t2; float old_cf; float old_res; float cf_res_changed;

cf_res_changed = (cf != old_cf) || (res != old_res);

if ( cf_res_changed ) { t0 = sin1 (cf*...); t1 = 1- t0;

a0 = ... a1 = ... .... }

since there is no if statement, I'm trying this way...

polyin cf; polyin res; float t0, t1, t2; float old_cf; float old_res; float cf_res_changed;

// there is no "equals" and "not equals" // if cf or res changed cf_res_changed > 0 cf_res_changed= 1.0 - ( ( cf>=old_cf ) & ( cf <= old_cf ) ) & 1 + 1.0 - ( ( res>=old_res ) & ( res <= old_res ) ) & 1

t0 = ( cf_res_changed <= 0 ) & t0 + ( cf_res_changed > 0 ) & sin1(cf*...) ....... t1 = ( cf_res_changed <= 0 ) & t1 + ( cf_res_changed > 0 ) & 1 - t0 ... a0 = ( cf_res_changed <= 0 ) & a0 + ( cf_res_changed > 0 ) & <some math expression to calculate a0> a1 = ( cf_res_changed <= 0 ) & a1 + ( cf_res_changed > 0 ) & <some math expression to calculate a1> ....

old_cf = cf; old_res = res;

... resulting in some code clutter. And I have the feeling that it isn't that efficient.

The hop method (thanks for the tip) isn't really a solution. I want to save as max CPU as possible, but if values change the calculation should be done immediately and as fast as possible.

Any suggestions welcome.

jorge ·

rl wrote: I could draw a schematic with all the maths on green float data as jorge suggested (calculations only on data change), but writing a couple of code-lines is much faster for me. (Typing the calculation in a code module took me a minute, drawing the same in a schematic at least ten minutes)

Yeah, I agree, we need a new Float code component.

rl wrote: If I write a code module that does only coefficient calculations and pass the coeffs to a 2P2Z, these calculations are done at sample rate, right?

Yeah, that's correct.

rl wrote: The hop method (thanks for the tip) isn't really a solution. I want to save as max CPU as possible, but if values change the calculation should be done immediately and as fast as possible.

Yeah, not a solution for you but useful if you wanted for example to control cutoff with an LFO.

rl wrote: Any suggestions welcome.

I suggest you do it at sample rate while you wait for a Float code component to be implemented. I think even at sample rate it might be efficient.

jorge ·

rl wrote: since there is no if statement, I'm trying this way...

polyin cf; polyin res; float t0, t1, t2; float old_cf; float old_res; float cf_res_changed;

// there is no "equals" and "not equals" // if cf or res changed cf_res_changed > 0 cf_res_changed= 1.0 - ( ( cf>=old_cf ) & ( cf <= old_cf ) ) & 1 + 1.0 - ( ( res>=old_res ) & ( res <= old_res ) ) & 1

t0 = ( cf_res_changed <= 0 ) & t0 + ( cf_res_changed > 0 ) & sin1(cf*...) ....... t1 = ( cf_res_changed <= 0 ) & t1 + ( cf_res_changed > 0 ) & 1 - t0 ... a0 = ( cf_res_changed <= 0 ) & a0 + ( cf_res_changed > 0 ) & <some math expression to calculate a0> a1 = ( cf_res_changed <= 0 ) & a1 + ( cf_res_changed > 0 ) & <some math expression to calculate a1> ....

old_cf = cf; old_res = res;

... resulting in some code clutter. And I have the feeling that it isn't that efficient.

That way of coding is more efficient than using if statements as there are not CPU branch predictions that can potentially go wrong. That's one of the advantages of not having "if" statements, it forces users to code for maximum SSE efficiency resulting in compiled code that I'd expect to be faster than if it was compiled with C++. The high level SM language is actually very close to SSE machine code eventhough it doesnt feel like it.

rl ·

jorge wrote: I suggest you do it at sample rate while you wait for a Float code component to be implemented. I think even at sample rate it might be efficient.

will do, thx....

jorge ·

rl, I forgot that there is already a hack that allows you to have float code that runs only when there is a change in input value, here's an example:

[old link]

The typed code is compiled and stored inside the analyser. When the input float value changes, it sends a trigger to the analyser causing it to run the code and update the output graph. What we would really need is a PolyToFloat component but a graph with size=1 is the same as a float.

lalo ·

yeah jorge 🙂

nice workaround 🙂

lalo

rl ·

interesting stuff, coming closer the secrets of SM each day.......

oddson ·

I'm wondering what Jorge meant when, in introducing this, he indicated it wasn't finished.

Are we talking something functional or cosmetic?

ake ·

Maybe you already knows this

http://www.musicdsp.org/files/EQ-Coefficients.pdf

Åke

rullyastronout ·

hi Jorge is that posibble from stream to fft and then get back to stream

jorge ·

rullyastronout wrote: hi Jorge is that posibble from stream to fft and then get back to stream

Not at the moment, hopefully soon. Often using FFTs is not the best way to process sound as it can have high CPU usage and low resolution at low frequencies.

ernald charles ·

Hey, I know this is an old post I'm resurfacing.. but just trying to understand a couple things about the filter design.. I see that Jorge has used the Zoelzer biquad equations (leaving Q factor = 1). However, I don't understand his equation for the variable "K" He has: K=freq/11025;

but on this site http://www.musicdsp.org/showone.php?id=37 it has "K" as: K=tan(omega/2) where omega = 2pi*f/fs (f - center freq, fs - sample freq)

Can someone clarify this for me.. it's driving me up a wall.. 😕 Thanks!

exonerate ·

ernald charles wrote: Hey, I know this is an old post I'm resurfacing.. but just trying to understand a couple things about the filter design.. I see that Jorge has used the Zoelzer biquad equations (leaving Q factor = 1). However, I don't understand his equation for the variable "K" He has: K=freq/11025;

but on this site http://www.musicdsp.org/showone.php?id=37 it has "K" as: K=tan(omega/2) where omega = 2pi*f/fs (f - center freq, fs - sample freq)

Can someone clarify this for me.. it's driving me up a wall.. 😕 Thanks!

Well it just basically means it's not sample rate independent, unless of course there's some sample rate scaling on the "freq" variable prior to entering the code component (I've not check if that's the case).

Cheers 🙂

Exo

ernald charles ·

Hey thanks for the response No there's no prior scaling.. But I guess that 11025 was his sample rate for this code? Why didnt he use the standard 44100? How does this affect the sound of the EQ?

Thanks again!

exonerate ·

ernald charles wrote: Hey thanks for the response No there's no prior scaling.. But I guess that 11025 was his sample rate for this code? Why didnt he use the standard 44100? How does this affect the sound of the EQ?

Thanks again!

Well I'm not sure, since omega is divide by 2. It's possible he's running a sample rate of 22050.

But what is most likely is that he just put in a value which made the frequency response sound about right.

I often do this when writing code I'll bung in a few values just so I can here everything working and then work out the exact details later. So I wouldn't worry to much about the reason for it.

The effect it will have though is on the frequency response. If you look at the frequency response of the eq in an analyser the frequencies should be off, for example 440hz in the eq won't correspond to 440hz in the analyser.

Cheers 😉

Exo

ernald charles ·

okay cool, thanks i understand. I prefer to always know the theory before i code something though, i just have to understand it before i use it.. my engineering background wouldn't let me have it any other way, lol 😈 Thanks again though, I'll go through and figure it out!

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.