A Collection of Useful C++ Classes for Signal Processing
-
- KVRian
- 1091 posts since 28 May, 2010 from Finland
BTW, regarding this http://www.kvraudio.com/forum/viewtopic ... 0#p6188078:
Dsp::SmoothedFilterDesign seems to produce a filter that does smooth real-time transitions. The last parameter "(1024)" is the transition length.
e.g.
Dsp::Filter * filt = new Dsp::SmoothedFilterDesign<Dsp::Bessel::Design::BandPass <1>, 2, Dsp::DirectFormII>(1024);
Dsp::SmoothedFilterDesign seems to produce a filter that does smooth real-time transitions. The last parameter "(1024)" is the transition length.
e.g.
Dsp::Filter * filt = new Dsp::SmoothedFilterDesign<Dsp::Bessel::Design::BandPass <1>, 2, Dsp::DirectFormII>(1024);
-
- KVRAF
- 3080 posts since 17 Apr, 2005 from S.E. TN
Hi Fluky. I don't know the lib and don't know if it will process a single sample at a time. It would be most reasonable if the lib could do so.Fluky wrote:Can you use the DSP::Filter::process function for numSamples = 1?
In real-time processing this is often the case that the samples are being read through one at a time, so can they be filtered one by one?
Or what would be the way to do filtering in real-time?
In what passes for "real time" processing in ordinary current computers, the audio is delivered in buffers. Sometimes 32 samples or less, sometimes 1024 or greater.
Though there is no guarantee how someone would write a library, it is possible to write multisample processing loops such that it is faster to process n samples in a tight loop with one call, rather than calling a 1 sample process for n times in a row.
In many cases it can be beneficial to do each stage of processing in blocks the same size as whatever is the audio buffer size, because it can be made faster. If you do 4 things to the audio, first do thing 1 on the entire buffer, then do thing 2 on an entire buffer, etc.
Sometimes this might require some temp buffers, just depending on what you wish to accomplish.
In very complicated cases maybe it would be less brain work to write the code so it does thing 1 thru thing 4 one sample at a time. But that one sample at a time method might be slower and offer fewer opportunities for speed optimization.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
Passes for real time?
The definition of real time processing is that it can be deterministically end in a certain time frame: https://en.wikipedia.org/wiki/Real-time_computing
The fact that it is done by buffers of size > 1 has nothing to do with this.
The main benefit is when using a modular library. This means that there are some virtual functions somewhere, and using a bigger buffer means that the overhead of calling these virtual function will be split accross several samples. Better than having several virtual calls per samples.
The definition of real time processing is that it can be deterministically end in a certain time frame: https://en.wikipedia.org/wiki/Real-time_computing
The fact that it is done by buffers of size > 1 has nothing to do with this.
The main benefit is when using a modular library. This means that there are some virtual functions somewhere, and using a bigger buffer means that the overhead of calling these virtual function will be split accross several samples. Better than having several virtual calls per samples.
-
- KVRian
- 1091 posts since 28 May, 2010 from Finland
Is there a scalable notch filter? A notch whose "depth" can be adjusted? Or a way to implement one?
Chebyshev II?
Also are the band-stop filters inverses of the band-passes or are the algos truly different?
If different, then is there are way to invert a band-stop filter to get a band-pass of the same shape?
Chebyshev II?
Also are the band-stop filters inverses of the band-passes or are the algos truly different?
If different, then is there are way to invert a band-stop filter to get a band-pass of the same shape?
-
- KVRian
- 1091 posts since 28 May, 2010 from Finland
How to know the parameters (Dsp::Params) passable to any particular filter design and their order?
Also how to pass negative gain parameter (e.g. -24 in Butterworth BandShelf)?
Code: Select all
That is, how to know:
Given some:
Dsp::Filter * f = new Dsp::SmoothedFilterDesign<Dsp::Bessel::Design::BandPass <1>, 2, Dsp::DirectFormII>(1024);
Then:
Dsp::Params params;
params[0] = ; // What
params[1] = ; // Are
params[2] = ; // These
params[3] = ; // ?
//Is there more?
f->setParams(params);
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
I have to say that I don't know directly how to go from a band pass to a band stop. At least for the general order. For a second order, it is possible to see an transformationbetween a band pass and a band stop. Usually transform go from low pass to XXX.
-
- KVRian
- 1091 posts since 28 May, 2010 from Finland
Dsp::Filter * f = new Dsp::SmoothedFilterDesign<Dsp::Bessel::Design::BandShelf <1>, 2, Dsp::DirectFormII>(1024);
Produces error:
error C2039: 'getKind' : is not a member of 'Dsp::Butterworth::BandShelf<1>
What's wrong?
Produces error:
error C2039: 'getKind' : is not a member of 'Dsp::Butterworth::BandShelf<1>
What's wrong?
-
- KVRAF
- 3080 posts since 17 Apr, 2005 from S.E. TN
Thanks Miles. I "mostly retired" full time programming a couple years ago, and was never the sharpest tool in the shed.Miles1981 wrote:Passes for real time?
The definition of real time processing is that it can be deterministically end in a certain time frame: https://en.wikipedia.org/wiki/Real-time_computing
The fact that it is done by buffers of size > 1 has nothing to do with this.
The main benefit is when using a modular library. This means that there are some virtual functions somewhere, and using a bigger buffer means that the overhead of calling these virtual function will be split accross several samples. Better than having several virtual calls per samples.
Yes saving cpu cycles in function calling overhead. In some cases saving init time as well, "getting ready to work" depending on the task and method.
In 32 bit code, a favorite strategy I used a lot for things simple enough such as IIR filters-- Write fpu asm, load up the fpu stack with coeffs and state variables, load up all the loop control and such in integer registers, then rip thru a buffer with no memory access at all except for sample read and sample write.
In fact, over the years wrote so many utility functions like that (they work fine on both intel mac and pc), that if I ever get off my butt and do any 64 bit programming, it will be a PITA to adapt them. Have read that one can still use the fpu in 64 bit but apparently few people do so. Probably have to rewrite in higher level language or learn sse and rewrite in that.
Last edited by JCJR on Mon Jul 20, 2015 9:07 pm, edited 2 times in total.
-
- KVRAF
- 3080 posts since 17 Apr, 2005 from S.E. TN
Duplicate message deleted
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
Yes, everything changed, and the FPU is not a real FPU anymore, so you have to change everything. Or indeed rely on a higher level language (which is what I do, although it's not as fast as custom tailored code :/).
-
- KVRian
- 1091 posts since 28 May, 2010 from Finland
Help.Fluky wrote:Dsp::Filter * f = new Dsp::SmoothedFilterDesign<Dsp::Bessel::Design::BandShelf <1>, 2, Dsp::DirectFormII>(1024);
Produces error:
error C2039: 'getKind' : is not a member of 'Dsp::Butterworth::BandShelf<1>
What's wrong?
-
- KVRer
- 22 posts since 20 Feb, 2013 from So Cal
@Fluky I was never able to get any of the Dsp::SmoothedFilterDesign examples to compile and stuck with Dsp::FilterDesign which was all I needed. Perhaps it was the version I was using or the author changed the setup. However, if you can get his demo to build, you can probably look there for usage examples.
The params[] vary by filter. For example, a Butterworth LPF needs the sample rate, order, and cutoff freq, and those are the first and only 3 params used when you call yourFilter->process(). Different filters and types may use similar or different params, so you need to look at the coded as to how to set up each of them.
I don't know of any real-time system that wants to process 1 sample at a time. Typically, you have an output rate to meet (e.g. 48000Hz) and you will need to supply a fixed amount of samples at a specific periodic rate. Usually, you get a signal telling you that the hardware is ready for another buffer block of samples. The hardware will have a fixed number of internal buffer blocks set up in a ring that will allow you time to process your audio. The total size of the hardware buffers determine your latency. The size of an individual buffer determines the time you have to process your audio. As an example, if you have a system running at 48 kHz, it may use a buffer size of 256 samples, which would mean you have ~5 milliseconds to process and supply the next block. If it uses 4 internal buffers, that gives you ~20 milliseconds of latency from the time you output a block to when it's heard.
Actually, I just remembered a system that processed 1 sample at a time. Back in the Stone Age, you made sound on PC's by toggling the internal speaker in real time, same as the old Apple ][. Fortunately, those days are a distant memory.
The params[] vary by filter. For example, a Butterworth LPF needs the sample rate, order, and cutoff freq, and those are the first and only 3 params used when you call yourFilter->process(). Different filters and types may use similar or different params, so you need to look at the coded as to how to set up each of them.
I don't know of any real-time system that wants to process 1 sample at a time. Typically, you have an output rate to meet (e.g. 48000Hz) and you will need to supply a fixed amount of samples at a specific periodic rate. Usually, you get a signal telling you that the hardware is ready for another buffer block of samples. The hardware will have a fixed number of internal buffer blocks set up in a ring that will allow you time to process your audio. The total size of the hardware buffers determine your latency. The size of an individual buffer determines the time you have to process your audio. As an example, if you have a system running at 48 kHz, it may use a buffer size of 256 samples, which would mean you have ~5 milliseconds to process and supply the next block. If it uses 4 internal buffers, that gives you ~20 milliseconds of latency from the time you output a block to when it's heard.
Actually, I just remembered a system that processed 1 sample at a time. Back in the Stone Age, you made sound on PC's by toggling the internal speaker in real time, same as the old Apple ][. Fortunately, those days are a distant memory.
-
- KVRian
- 1091 posts since 28 May, 2010 from Finland
I've had some other Dsp::SmoothedFilterDesign working, but this one produces an error. Being a beginner in C++ understanding the code is slightly difficult, because to me it seems "correctish". I can't spot where the error even occurs as there's no line numbers or anything in the error message. getKind() seems to be defined, but I don't know what causes it to be not defined.ChocoBilly wrote:@Fluky I was never able to get any of the Dsp::SmoothedFilterDesign examples to compile and stuck with Dsp::FilterDesign which was all I needed. Perhaps it was the version I was using or the author changed the setup. However, if you can get his demo to build, you can probably look there for usage examples.
My whole project is now sort of dependent on this one particular filter, because I cannot do with other filter types than smooth-transition bandshelf.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
The main issue is because the library is a little bit overdesigned, and some templates should have restrictions that are not clearly explained...
-
- KVRian
- 1265 posts since 9 Sep, 2005 from Oulu, Finland
I'd say not just a little bit...Miles1981 wrote:The main issue is because the library is a little bit overdesigned, and some templates should have restrictions that are not clearly explained...
And of course now that Vinnie Falco seems to have abandoned it, nobody will be able to update/fix it. The code in the library is so overcomplicated I hardly ever look at the insides at all. It's hard enough to just try using the library.
I sometimes enjoy tinkering with overcomplicated C++ structures in my own code, but I don't particularly enjoy trying to figure out what other people have done in their code...