SynthMaker

Butterworth filter

Archive · 2005 37 old posts

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

platinumears ·

Here's an old SynC Modular favorite I just ported:

Tarrabia filter

(I dropped it into a simple synth for easy testing)

Based on the 'biquad, tweaked butterworth' posted by Patrice Tarrabia: http://www.musicdsp.org/showone.php?id=38

I attempted to add gain compensation for the resonance parameter, but that could probably be improved.. any improvements or optimisations would be welcome! 🙂

jorge ·

Thanks platinumears, I was looking forward to try it but couldnt open it as it must have an ASIOout enabled component and failed to open on my laptop. That's a bug we need to fix but for now I think it would be more user friendly with a DirectSoundOut with Primary sound driver selected or even none selected.

platinumears ·

Here's a question for the devs: is it more efficient to implement the filter kernel with math and 'delay by one sample' modules as I did in the example above, or is it better to do it in code like this:

polyin in; polyin a1; polyin b1; polyin b2; polyout out; float in1; float in2; float out1; float out2; out=((in+in1*2.0+in2)*a1)-(out1*b1)-(out2*b2); in2=in1; in1=in; out2=out1; out1=out;

.. or does it make no difference? Is there any way to optimise this code at all?

unkargherth ·

Mmmm... very good work !! ,platinum ears. Nice Multimode filter. Very clean to have separated coeff calculation and filter kernel

I supose, but not sure, it's more efficient to do it in code module. This way you get rid off all those links that although very low, they should have some cpu comsumption

I'm guessing here. Probably jorge could give a more reasoned answer

platinumears ·

jorge wrote: Thanks platinumears, I was looking forward to try it but couldnt open it as it must have an ASIOout enabled component and failed to open on my laptop. That's a bug we need to fix but for now I think it would be more user friendly with a DirectSoundOut with Primary sound driver selected or even none selected.

You can call me Dan if you like! 😉 I updated the file..

jorge ·

platinumears wrote: Here's a question for the devs: is it more efficient to implement the filter kernel with math and 'delay by one sample' modules as I did in the example above, or is it better to do it in code like this:

polyin in; polyin a1; polyin b1; polyin b2; polyout out; float in1; float in2; float out1; float out2; out=((in+in1*2.0+in2)*a1)-(out1*b1)-(out2*b2); in2=in1; in1=in; out2=out1; out1=out;

.. or does it make no difference? Is there any way to optimise this code at all?

It's more efficient in the code as it will user SSE internal registers rather than variables stored in memory. The compiled code should be very efficient, you can look at the assembler coming out of the code component by connecting it to a data component. You can even copy and paste that code inside an ASM code component and do some very low-level optimizing. In this case I dont think there would be much you could do to improve.

platinumears ·

jorge wrote: You can even copy and paste that code inside an ASM code component and do some very low-level optimizing.

Whoah!! c++ still makes my brain hurt! :hihi: I was more thinking 'have I made any stupid mistakes?'..

jorge ·

unkargherth wrote: I supose, but not sure, it's more efficient to do it in code module. This way you get rid off all those links that although very low, they should have some cpu comsumption

I'm guessing here. Probably jorge could give a more reasoned answer

Yeah, you're right, although they'd still be quite efficient, each poly output connector can be thought of a variable stored in memory. If you use the 1 sample delays each value will be passed through a memory address rather than using internal SSE registers.

platinumears ·

I think maybe I forgot to mention: Synthmaker Rocks!!! 😀

platinumears ·

I updated it again to use the code versions of the kernel. Same link. I might try to code the coefficients next.. 🙂

Dan

jorge ·

platinumears wrote: Whoah!! c++ still makes my brain hurt! :hihi: I was more thinking 'have I made any stupid mistakes?'..

🙂 no, I think you're doing well. You probably realised already that it's much easier to type code inside the code component than creating the equivalent schematic.

platinumears ·

jorge wrote: :) no, I think you're doing well. You probably realised already that it's much easier to type code inside the code component than creating the equivalent schematic.

unless you are blindly copying a SynC Modular schematic.. 😉

Shifrin ·

This is nice Dan, cheers!

Shif.

beno ·

Hey Dan. Welcome aboard. I told you Synth Maker was great! Ben

platinumears ·

beno wrote: Hey Dan. Welcome aboard. I told you Synth Maker was great! Ben

I believed you, just haven't had the time till now.. exams went well I hope?

beno ·

Yup, thanks. Ben

platinumears ·

I've updated it to use the 'time info' module instead of 'setings'.. same link.

Dan 🙂

unkargherth ·

Mmmmmh.. there's something i don't fully understand.

.-What are those manipulations on freq value coming out from Cuoff knob exactly do?

.-Why you're doing it?

Without fully understanding it , i FEEL (but not sure) that they could be simplified.....

EDIT. Forget the questions. Correct me if my below aseverations are false

.- You're converting range from exponential 0..1 to more or less linera 0..14080 Hz ( stability limit?) .- Later, on filter coeffs you divide this by sample rate, so you get a value in range of 0..042

There's a simple ways to do it. Multiply knob out by 127 and then use Pitch2Freq module. You get Linera control of frequency. Later you could multiply this by 2*14080/SR to limit max freq to this.

Give me some time and i post it ( if you don't find it previously)

platinumears ·

unkargherth wrote: .-What are those manipulations on freq value coming out from Cuoff knob exactly do?.

First I scale the 0 - 1 range from the knob to 0 - 96 (is there a better way to do this?) then convert it from a pitch scale to a frequency factor with the 'dp2ff' module ('degrees pitch to frequency factor': ported from SynC Modular again!) before multiplying it by a base frequency (55Hz in this case)

Its basically just to convert the knob range to a log scale.. I'm sure it can be optimised!

Dan

platinumears ·

unkargherth wrote: There's a simple ways to do it. Multiply knob out by 127 and then use Pitch2Freq module. You get Linera control of frequency. Later you could multiply this by 2*14080/SR to limit max freq to this.

that makes sense.. thanks! 🙂

platinumears ·

So.. the pitch to frequency module outputs fractions of nyquist rather than absolute frequencies.. have I got that right? Does it take account of samplerate at all?

unkargherth ·

Absolute frequencies aren't used thought SM. Yo always use freq in range 0..1 that maps from 0..Nyquist

Whatt Pitch 2 freq does is to map a LINEAR scale in range 0..127 ( wich corresponds to MIDI Note num) to an Exponential scale above ( 0..1)

So if you want alinear knob for the cutoff, multiply knob out by 127 and feed in Pitch2Freq module. Then Forget every Freq/(0.5*SR) inside the filter

platinumears ·

Ok, thanks.

I've been trying to implement the coeffs as code, but I'm slightly confused by the tan function.. my maths sucks, so maybe you can explain why this tan function (ported from SynC!) works as I expected:

polyin in; polyout out; float in2; float in3; in2=in*in; in3=in2*in; out=in+(in3*in2*0.13333333)+(in3*0.333333);

but this one doesn't (the cutoff frequency ends up much higher):

polyin in; polyout out; out=tan1(in);

:?:

unkargherth ·

Tan1() func isn't behave extactly as Tan()

Tan1 Expect Input avlues between 0 and 1 instead of 0...3.141592653 (same for sin1 and cos1) so, if you're porting code . simply do

y=tan1(x/3.141592635)

instead of

y=tan1(x/3.141592635)

Simple as that...

platinumears ·

Aha, that works! I'm enjoying myself here.. 😀

Tom7777 ·

Thanks platinumears, also welcome to the forum 🙂

platinumears ·

Cheers Tom. Think I'll be spending a lot of time here actually.. 🙂

I updated the file again: same link: it now correctly conforms to the SM Nyquist frequency input convention, and now runs almost entirely in code components.. perhaps one of you can see a way to optimise my coefficients code?

polyin freq; polyin res; polyout a1; polyout b1; polyout b2; float c; float c2; freq=freq*0.5; res=1.0-res*0.9; c=1.0/(tan1(freq)); c2=c*c; a1=1.0/(1+res*c+c2); b1=2.0*(1.0-c2)*a1; b2=(1.0-res*c+c2)*a1;

Also, I couldn't seem to get the parameter range clipping to work in code, so this still uses math modules.. any clues here would be great! 🙂

Dan.

stefan ·

clipping: a = (a >= ceiling) & ceiling+ (a < 1) & a; a = (a > floor) & a;

clips a at the boundaries floor and ceiling. should work to do it like this as well: a = min(ceiling, a); a = max(floor, a);

platinumears ·

stefancrs wrote: clipping: a = (a >= ceiling) & ceiling+ (a < 1) & a; a = (a > floor) & a;

I don't understand that at all.. 🙁

stefancrs wrote: clips a at the boundaries floor and ceiling. should work to do it like this as well: a = min(ceiling, a); a = max(floor, a);

i understand that 🙂 but it doesn't seem to work 🙁

polyin freq; polyin res; polyout a1; polyout b1; polyout b2; float c; float c2;

freq=min(0.49,freq);

freq=freq*0.5; res=1.0-res*0.9; c=1.0/(tan1(freq)); c2=c*c; a1=1.0/(1+res*c+c2); b1=2.0*(1.0-c2)*a1; b2=(1.0-res*c+c2)*a1;

what have I done wrong?

stefan ·

platinumears wrote: stefancrs wrote: clipping: a = (a >= ceiling) & ceiling+ (a < 1) & a; a = (a > floor) & a;

I don't understand that at all.. 🙁

stefancrs wrote: clips a at the boundaries floor and ceiling. should work to do it like this as well: a = min(ceiling, a); a = max(floor, a);

i understand that 🙂 but it doesn't seem to work 🙁

polyin freq; polyin res; polyout a1; polyout b1; polyout b2; float c; float c2;

freq=min(0.49,freq);

freq=freq*0.5; res=1.0-res*0.9; c=1.0/(tan1(freq)); c2=c*c; a1=1.0/(1+res*c+c2); b1=2.0*(1.0-c2)*a1; b2=(1.0-res*c+c2)*a1;

what have I done wrong?

Depends on what you try to do. This will make sure freq doesn't go above 0.49. (unless the min() function has bugged out)

platinumears ·

stefancrs wrote: This will make sure freq doesn't go above 0.49.

Thats what I'm trying to do! I'll try it again with the latest SM version I can find (when I get home from work that is..)

Any chance you could explain what exactly the '&' symbol does in your first example?

Thanks 😉 Dan.

stefan ·

platinumears wrote: stefancrs wrote: This will make sure freq doesn't go above 0.49.

Thats what I'm trying to do! I'll try it again with the latest SM version I can find (when I get home from work that is..)

Any chance you could explain what exactly the '&' symbol does in your first example?

Thanks 😉 Dan.

As you may now, SSE and hence SM works on four channels simultaneously. When doing a comparison, say for instance: a >= 1.0 we will in fact compare all four values in a with 1.0. The result is a boolean four values. We use the & to do a logic AND with these values. So when we do for instance: b = (a >= 1.0) & 3.0; We will, for each channel that is more than or equal to 1.0 set b to 3.0.

Did I explain it clear enough? I know it's a bit cumbersome to get your head around these things. Logic AND operations and shit 🙂

jorge ·

stefancrs wrote: So when we do for instance: b = (a >= 1.0) & 3.0; We will, for each channel that is more than or equal to 1.0 set b to 3.0.

I'll add a bit to that,

b = ( a >= 1.0 ) & 3.0; is the same as:

if ( a >= 1.0 ) b = 3.0; else b= 0.0;

but because these are SSE variable, b is actually b0, b1, b2,b3 and a is a0,a1,a2,a3. So the code "b=(a>=1.0)&3.0" is actually the following:

if ( a0 >= 1.0 ) b0 = 3.0; else b0 = 0.0; if ( a1 >= 1.0 ) b1 = 3.0; else b1 = 0.0; if ( a2 >= 1.0 ) b2 = 3.0; else b2 = 0.0; if ( a3 >= 1.0 ) b3 = 3.0; else b3 = 0.0;

so if a = 0.1, 0.5, 1.5, 0.7, the result would be b=0.0,0.0,3.0,0.0

I hope I didnt confuse things

unkargherth ·

platinumears wrote: i understand that 🙂 but it doesn't seem to work 🙁

polyin freq; polyin res; polyout a1; polyout b1; polyout b2; float c; float c2;

freq=min(0.49,freq);

freq=freq*0.5; res=1.0-res*0.9; c=1.0/(tan1(freq)); c2=c*c; a1=1.0/(1+res*c+c2); b1=2.0*(1.0-c2)*a1; b2=(1.0-res*c+c2)*a1;

what have I done wrong?

Well can explain why it occurs, but i get sometimes problems when trying to modify input values

Try the following

polyin freq; polyin res; polyout a1; polyout b1; polyout b2; float c; float c2; float f; f=min(0.49,freq);

f=f*0.5; res=1.0-res*0.9; c=1.0/(tan1(f)); c2=c*c; a1=1.0/(1+res*c+c2); b1=2.0*(1.0-c2)*a1; b2=(1.0-res*c+c2)*a1;

platinumears ·

unkargherth wrote: Try the following

That worked! 😀

jorge wrote: I hope I didnt confuse things

I think I follow.. 😉 would these four channels be used for extra voices then? If so, is there any way to utilise them in a monophonic module? (perhaps processing L & R channels at the same time?)

jorge ·

platinumears wrote: I think I follow.. 😉 would these four channels be used for extra voices then? If so, is there any way to utilise them in a monophonic module? (perhaps processing L & R channels at the same time?)

In a Poly section of the schematic each channel is used for each new note you play, you dont need to worry about allocation as the engine takes care of that. The 2nd 3rd and 4th note you play should take nearly no extra CPU at all. The 5th note will start a new sound process with another 4 channels.

In a Mono section you can use the Pack and Unpack components in several ways to use the extra power. You could use them to process two stereo channels simultaneously, or with a filter you could run the code 4 times to create a steeper response.

So if you create a Mono effect and dont use any of these techniques, you can expect to be able to lower it's CPU useage 4 times.

platinumears ·

jorge wrote: In a Mono section you can use the Pack and Unpack components

That really did confuse me.. until I found the hidden 'advanced' components!

I was going to make a mono version too, but perhaps I need to investigate these pack and unpack thingies first!

Thanks for the help (I updated the file again).

Dan. 🙂

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.