If you have a problem or need to report a bug please email : support@dsprobotics.com
There are 3 sections to this support area:
DOWNLOADS: access to product manuals, support files and drivers
HELP & INFORMATION: tutorials and example files for learning or finding pre-made modules for your projects
USER FORUMS: meet with other users and exchange ideas, you can also get help and assistance here
NEW REGISTRATIONS - please contact us if you wish to register on the forum
Users are reminded of the forum rules they sign up to which prohibits any activity that violates any laws including posting material covered by copyright
Freely Configurable Filter
22 posts
• Page 1 of 3 • 1, 2, 3
Freely Configurable Filter
This is one of my current projects, a freely configurable filter. The user specifies a transfer curve in the frequency domain by placing control points, which are interpolated to give the desired transfer function. The application calculates FIR filter coefficients and provides a ready-to-use filter. The actual filter characteristic may deviate to some extent from the specification because the filter length is 1024 taps; longer filters have higher latency and use more CPU.
DISCLAIMER: The Ruby code violates all style guides and recommendations. In particular, I am guilty of using for-loops - a lot of them. Read at your own risk! Minors stay away!
ACKNOWLEDGEMNET: My special thanks to Spogg, who solved a Preset Manager problem that had given me a serious headache. I am also grateful for some expert advice from Tulamide concerning graphics optimization.
Please download, use, and give some feedback!
DISCLAIMER: The Ruby code violates all style guides and recommendations. In particular, I am guilty of using for-loops - a lot of them. Read at your own risk! Minors stay away!
ACKNOWLEDGEMNET: My special thanks to Spogg, who solved a Preset Manager problem that had given me a serious headache. I am also grateful for some expert advice from Tulamide concerning graphics optimization.
Please download, use, and give some feedback!
- Attachments
-
- curves2.fsm
- Fixed a bug in Minimum Phase Impulse Response code
- (2.66 MiB) Downloaded 1125 times
-
- InteractiveCurve.png (19.03 KiB) Viewed 36408 times
Last edited by martinvicanek on Sat Nov 21, 2020 5:44 pm, edited 1 time in total.
-
martinvicanek - Posts: 1328
- Joined: Sat Jun 22, 2013 8:28 pm
Re: Freely Configurable Filter
1) The idea itself
Brilliant! Has this been done ever before? A paint-your-own-filter? I don't think it can become any more versatile, or do I miss something?
2) The real deal (DSP)
Once again top quality work. I love how the Impulse Response module works. Certainly gets the most out of green, speedwise. That I don't understand anything of it, is another sign of quality
3) Ruby
Well done. Yes, you ignore a lot, but to make such a complex Ruby code work really is an achievement. However, no code that couldn't be optimized. So here are a few things.
Starting with the smallest, you seem to be unaware of some range features.
I highly recommend to replace the for loops. It isn't difficult, but saves CPU load.
Move all creations of class instances for Pen, Brush, Color and Font to the init method, and use their class methods to change colors or sizes (for example, @myPen.setWidth or @myBrush.setColor. This way you reduce the work the GC has to do, which results in faster execution overall. This is only important in settings, where you draw repeatedly over time, like in your module.
Last, splines. You could have saved a lot of cpu by using my Spline class. I explicitly designed it for use in realtime environments, using
- faster calculations (no expensive polynomial math)
- adaptive (switchable) adjustment of drawing point clouds (= more segments for longer curves, less for shorter)
- anything from linear to cubic through one class
- nodes support mirroring of control points
- methods for mouse control included (detects mouse on node and on control points)
- optional output of interpolation points, independend on drawing settings (!)
- comes with an extensive pictured manual, that describes each method in detail, including usage
With your current skills in Ruby, it would have been a breeze to use the Spline class. Give it a try: http://flowstone.guru/downloads/ruby-for-flowstone-expansion-spline-class/
Brilliant! Has this been done ever before? A paint-your-own-filter? I don't think it can become any more versatile, or do I miss something?
2) The real deal (DSP)
Once again top quality work. I love how the Impulse Response module works. Certainly gets the most out of green, speedwise. That I don't understand anything of it, is another sign of quality
3) Ruby
Well done. Yes, you ignore a lot, but to make such a complex Ruby code work really is an achievement. However, no code that couldn't be optimized. So here are a few things.
Starting with the smallest, you seem to be unaware of some range features.
- Code: Select all
1..12 ## range from 1 to 12
1...12 ## range from 1 to 11
## more precisely, three dots define a range excluding the last value.
##no need for this:
1..n-1
##replace with
1...n
I highly recommend to replace the for loops. It isn't difficult, but saves CPU load.
- Code: Select all
for k in 0..@xLabel.size-1 do
rect = [@x0 - lwh + @w*@xLabelPos[k], @y0 + @h + 0.5, lw, lh]
v.drawString @xLabel[k], font, sf, rect, lBrush
end
- Code: Select all
@xLabel.each_with_index do |label, i|
rect = [@x0 - lwh + @w*@xLabelPos[i], @y0 + @h + 0.5, lw, lh]
v.drawString label, font, sf, rect, lBrush
end
Move all creations of class instances for Pen, Brush, Color and Font to the init method, and use their class methods to change colors or sizes (for example, @myPen.setWidth or @myBrush.setColor. This way you reduce the work the GC has to do, which results in faster execution overall. This is only important in settings, where you draw repeatedly over time, like in your module.
Last, splines. You could have saved a lot of cpu by using my Spline class. I explicitly designed it for use in realtime environments, using
- faster calculations (no expensive polynomial math)
- adaptive (switchable) adjustment of drawing point clouds (= more segments for longer curves, less for shorter)
- anything from linear to cubic through one class
- nodes support mirroring of control points
- methods for mouse control included (detects mouse on node and on control points)
- optional output of interpolation points, independend on drawing settings (!)
- comes with an extensive pictured manual, that describes each method in detail, including usage
With your current skills in Ruby, it would have been a breeze to use the Spline class. Give it a try: http://flowstone.guru/downloads/ruby-for-flowstone-expansion-spline-class/
"There lies the dog buried" (German saying translated literally)
- tulamide
- Posts: 2714
- Joined: Sat Jun 21, 2014 2:48 pm
- Location: Germany
Re: Freely Configurable Filter
Thanks, Tula, some stuff for me to consider in more detail. I know your spline classes for sure, but frankly I just couldn't get anything to work, not even a very basic "hello world" type of thing, sorry. If you say there is a manual I will give it a second try.
I am also aware of TheOm's work, however I figured it was easier to write my own code than to modify his to my needs. In my opinion cubic splines are useless for drawing curves because they always overshoot. How often have I cursed at Photoshop for implementing cubic splines? That's why I have included the smart (monotone) interpolation mode. I know you can do Bezier - that*s OK for parametric curves [x(t),y(t)] but not so much for functions y(x).
Now tell me, why are those "each"-iterators preferrable over for-loops? To me the notation is awkward, when I see |x|
I always associate abs(x) (or x.abs for that matter). I need a hard and fast advantage to switch. And then, how can I control excecution order?
Again, thanks for your hints, much appreciated!
I am also aware of TheOm's work, however I figured it was easier to write my own code than to modify his to my needs. In my opinion cubic splines are useless for drawing curves because they always overshoot. How often have I cursed at Photoshop for implementing cubic splines? That's why I have included the smart (monotone) interpolation mode. I know you can do Bezier - that*s OK for parametric curves [x(t),y(t)] but not so much for functions y(x).
Now tell me, why are those "each"-iterators preferrable over for-loops? To me the notation is awkward, when I see |x|
I always associate abs(x) (or x.abs for that matter). I need a hard and fast advantage to switch. And then, how can I control excecution order?
Again, thanks for your hints, much appreciated!
-
martinvicanek - Posts: 1328
- Joined: Sat Jun 22, 2013 8:28 pm
Re: Freely Configurable Filter
I know what you mean. Splines can be difficult for Y(x) functions. TheOms editor is perfect for those. However, you can get splines over fixed x-values with the Spline class (for example by switching off auto-resolution and instead set a resultion of n, which will evenly divide the spline distance on the x-axis). But I admit it was more about speed (I used the Splines once to visualize frequencies, so I can assure you that class is fast), than difficulties in translating the values, that drived me to mention the class.
The each iterators are a fixed component of Ruby's core (enumerator class). They are as fast as C ececution is. 'For loops' can't take advantage of internal optimizations and so are just as fast as Ruby is (interpreted). The same goes for the range functionality I pointed out. Using the three dots saves a few cycles per iteration (n-1 is calculated per iteration, not once). By drawing like 20 times per second that is already a lot.
And what do you mean by "control execution order"? It is the same as with your for loops. You should read more about iteration in Ruby, as it can be crucial to optimise speed.
General enumerator info: https://ruby-doc.org/core-1.9.3/Enumerator.html
Arrays implement enumerators and have their own methods built upon enumerator, for example ::map https://ruby-doc.org/core-1.9.3/Array.html#method-i-map
The each iterators are a fixed component of Ruby's core (enumerator class). They are as fast as C ececution is. 'For loops' can't take advantage of internal optimizations and so are just as fast as Ruby is (interpreted). The same goes for the range functionality I pointed out. Using the three dots saves a few cycles per iteration (n-1 is calculated per iteration, not once). By drawing like 20 times per second that is already a lot.
And what do you mean by "control execution order"? It is the same as with your for loops. You should read more about iteration in Ruby, as it can be crucial to optimise speed.
General enumerator info: https://ruby-doc.org/core-1.9.3/Enumerator.html
Arrays implement enumerators and have their own methods built upon enumerator, for example ::map https://ruby-doc.org/core-1.9.3/Array.html#method-i-map
"There lies the dog buried" (German saying translated literally)
- tulamide
- Posts: 2714
- Joined: Sat Jun 21, 2014 2:48 pm
- Location: Germany
Re: Freely Configurable Filter
Man ... this is so cool, MartinV.
- RJHollins
- Posts: 1571
- Joined: Thu Mar 08, 2012 7:58 pm
Re: Freely Configurable Filter
Absolutely fantastic Martin!
You just draw the filter characteristics you want, and I totally love it.
I’m wondering if this could be used to accurately match a spectral profile for mastering somehow. Just thinking out loud.
Cheers
Spogg
You just draw the filter characteristics you want, and I totally love it.
I’m wondering if this could be used to accurately match a spectral profile for mastering somehow. Just thinking out loud.
Cheers
Spogg
-
Spogg - Posts: 3358
- Joined: Thu Nov 20, 2014 4:24 pm
- Location: Birmingham, England
Re: Freely Configurable Filter
I'm especially fascinated by the minimum phase response mode. I always knew that it should be possible to calculate minimum phase response for given magnitude curve and I've been hunting for such algorithm for years now... Do you by any chance have some references to what you've done there? I can see some cepstrum log/exp sorcery going on there but I can't quite figure it out...
- KG_is_back
- Posts: 1196
- Joined: Tue Oct 22, 2013 5:43 pm
- Location: Slovakia
Re: Freely Configurable Filter
Spogg wrote:I’m wondering if this could be used to accurately match a spectral profile for mastering somehow. Spogg
Like this?
viewtopic.php?f=2&t=3972&start=50#p22927
-
martinvicanek - Posts: 1328
- Joined: Sat Jun 22, 2013 8:28 pm
Re: Freely Configurable Filter
KG_is_back wrote:[...] minimum phase response mode.[...] Do you by any chance have some references?
Julius O. Smith is a good source:
https://www.dsprelated.com/freebooks/sa ... esign.html
Here is a concise recipe:
1. Given a (real valued) frequency magnitude response X[k], k = 0..N-1 calculate the cepstrum y[n]
y[n] = IFFT{ log|X[k]| }
2. Flip all negative quefrencies to positive (for causality)
for n = 1 to N/2-1 { y[n] = y[n] + y[N-n] }
for n = N/2+1 to N-1 { y[n] = 0 }
It is a good idea to taper the cepstrum to avoid a step at n = N/2, for instance
for n = 0 to N/2 { y[n] = y[n]*(1 - 4n^2/N^2) }
3. Transform back to frequency domain
Z[k] = FFT{ y[n] }
and undo log by taking the (now complex) exponential:
W[k] = exp( Z[k] ) = exp( Re Z[k] )*( cos( Im Z[k] ) + i*sin( Im Z[k] ) )
4. Convert to time domain to obtain the impulse response IR[k]:
IR[n] = IFFT{ W[k] }
It is a good idea to taper the IR at n = N-1, for instance
IR[n] = IR[n]*(1 + cos(pi*n/N))/2
There you go, ready for convolution.
-
martinvicanek - Posts: 1328
- Joined: Sat Jun 22, 2013 8:28 pm
Re: Freely Configurable Filter
WoW what more can be said! As always Martin, your projects are truly amazing. Very cool indeed.
Later then, BobF.....
Later then, BobF.....
- BobF
- Posts: 598
- Joined: Mon Apr 20, 2015 9:54 pm
22 posts
• Page 1 of 3 • 1, 2, 3
Who is online
Users browsing this forum: No registered users and 10 guests