A Collection of Useful C++ Classes for Signal Processing

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

It looks like an issue with your <complex> header. I am not sure why that would be causing a problem. Not only does it compile for me under Visual Studio 2008, but I am also cross-compiling it with g++ under MinGW (which is much more strict).

Is anyone else having this problem? Or can anyone shed an insight into what the problem is now?

Post

my c++ experience is platform-finite (dsp in an sdk only). i have no experience and little knowledge regarding the conventional distribution of resources.

i'm looking for code for an elliptic/cauer lowpass, bandpass, anything elliptic/cauer, because i think it will give me the phase response i'm looking for. unfortunately, sourceforge suddenly seems to require that i update my browser in order to use it as a resource. i can't tell you how i feel about that :lol:

does your package contain code, or is the distribution of the algorithm limited, eg. the classes are contained in a .dll or something?
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

xoxos wrote:does your package contain code, or is the distribution of the algorithm limited, eg. the classes are contained in a .dll or something?
It is a single .h header file containing all the source code.

I just finished rewriting the classes, and there are only a couple of filters actually implemented as concrete cascades. But all the response types are there. For elliptic you can make your own class from the building blocks I have provided. For example:

Code: Select all

template<int order, int channels>
struct EllipticBandPass : public EllipticBp<order>, public CascadeFilter<order, channels>
{
	EllipticBandPass() : CascadeFilter<order, channels>( this ) { }
	void Setup( CalcT centerFreq, CalcT normWidth )
	{
		Spec spec;
		spec.order=order;
		spec.centerFreq=centerFreq;
		spec.normWidth=normWidth;
		spec.sampleRate=1;
		EllipticBp<order>::Setup( spec );
	}
};
I'm still working on it so it will be in better shape in a couple of weeks. The elliptics are not particularly efficient, and they take up a ton of intermediate storage for finding the roots. I will optimize it after I have cleaned up all the APIs and finalized all the analog prototypes.

The code is distributed under the MIT License which means UNLIMITED COMMERCIAL USE, i.e. all-you-can-eat at the DSP Buffet.

Post

i'm looking at the phase response for trumpet bell modeling. not sure if it's an effective technique.

thanks for all the chat on this too, it's jogged my comprehension.

this kitchen has a history of honourable chefs.
you come and go, you come and go. amitabha neither a follower nor a leader be tagore "where roads are made i lose my way" where there is certainty, consideration is absent.

Post

I have released version 0.8.4 of this library. It is located here:
http://sourceforge.net/projects/dspfilterscpp/

The changes:

- Rewrote entire class hierarchy

- Templatized classes have been pushed farther down the derivation hierarchy

- Code for non templatized classes has been moved into a .cpp file.

- Low-pass analog prototypes for Butterworth, Chebyshev, Inverse Chebyshev, and Elliptic responses are each represented by their own class.

- A Butterworth low-shelf analog prototype is also provided. (Can anyone point me to the Chebyshevs and Elliptic shelves?)

- Low pass to low pass, Low pass to high pass, low pass to band pass, and low pass to band stop transformations are each encapsulated and represented by their own class.

- A Layout of poles and zeros is represented by its own class. This allows the computation of the analog prototype to be saved and re-used for speed.

- The set of all possible filter parameters is encapsulated in a single structure and passed to all classes. This allows specifications to be cached and re-used, or compared against for changes.

- Filter order can now be specified at run-time. Storage classes allow specification of a 'maxorder' (i.e. provide sufficient state storage for order from 1 up to maxorder).

- As in the original design, there is no dynamic memory allocation (i.e. calls to new/delete).

- Each concept of IIR filtering is mapped cleanly to one corresponding class in the library.

- Top down programming design allows the entire process of designing and realizing a digital filter to take place in the body of a single function (this allows for any type of optimization at any level).

- Functional programming style, no side effects from function calls and elimination of most state variables.

- A small lightweight class is provided for determining if processor specific optimizations are available (MSVC only)

- Processing template definitions moved to the .cpp file, and the explicit template instantiation model is used, with float and double available (you can add more at the bottom of the source file if needed).

- Some bug fixes to utility functions, and a few trivial utility functions added.

The Elliptic prototype implementation is fairly rough there are hard coded limits on the order, and it consumes a lot of memory (something like 12 kilobytes) even if the order is low. I plan on fixing this. There are also plenty of optimizations that can be performed, like moving constant expressions out of loops, re-using the poles of the analog prototypes, partial recomputation when only a subset of filter parameters change, etc... I will get to that shortly.

For now, everything in there should work. These filters have been tested:

BiquadLowPass
BiquadHighPass
BiquadBandPass1
BiquadBandPass2
BiquadBandStop
BiquadAllPass
BiquadLowShelf
BiquadHighShelf
BiquadPeak

ButterLowPass
ButterHighPass
ButterBandPass
ButterBandStop
ButterLowShelf
ButterHighShelf
ButterPeak

ChebyILowPass
ChebyIHighPass
ChebyIBandPass
ChebyIBandStop

ChebyIILowPass
ChebyIIHighPass
ChebyIIBandPass
ChebyIIBandStop

EllipticLowPass
EllipticHighPass
EllipticBandPass
EllipticBandStop

None of this would have been possible without the insights and help from the members here as well as the contributions upon which portions of the library were built. Thanks!

Post

Just want to note that I am compiling it under MinGw using g++ without errors.

Post

:party:

Only error in compilation was the definition of Int64. Meeloo's suggestion makes sense, but this is very minor. Other than that it compiled without error in XCode.

I tested a few filters and they seem to work. I hear a lot of crackling when changing frequency on ButterLowPass and ChebyILowPass, but I have to put these filters through the paces more thoroughly before making any more comments.

Nice work, beautiful stuff. I'll be trying to figure out what you've done for a very long time!

Usage question:

Say I want a stereo ButterLowPass with max order 30, but to set the order to 4 and freq to 1k at runtime: Do I understand correctly about the usage if I want to be able to change order at runtime?

Code: Select all

Dsp::ButterLowPass<30,2> butterLowPass;

Dsp::Spec spec;
spec.order=4;
spec.cutoffFreq=1000.f / sampleRate;
spec.sampleRate=1;

butterLowPass.ButterLp::Setup(spec);
butterLowPass.Process(nFrames, interleavedBuffer);

Post

asomers wrote:Say I want a stereo ButterLowPass with max order 30, but to set the order to 4 and freq to 1k at runtime: Do I understand correctly about the usage if I want to be able to change order at runtime?

Code: Select all

Dsp::ButterLowPass<30,2> butterLowPass;

Dsp::Spec spec;
spec.order=4;
spec.cutoffFreq=1000.f / sampleRate;
spec.sampleRate=1;

butterLowPass.ButterLp::Setup(spec);
butterLowPass.Process(nFrames, interleavedBuffer);
Yes that is exactly right. Also note you could use:

Code: Select all

spec.cutoffFreq=1000.f;
spec.sampleRate=sampleRate;

Post

I don't hear crackling when changing the frequency but I do hear zippering, especially when going from high frequency to low frequency in a very short time interval (tested with a ButterLowPass of order 8 ). I'm using Direct Form I. This is a consequence of the realization form and that the history information contains leftover spectral energy from the previous state. I've tried all sorts of tricks to fix it including munging the history array on parameter changes but nothing seems to work. I am hoping that the lattice / ladder form implementation (currently missing, anyone have any links I can read?) will fix it.

Sorry about the obtuse method of using the spec. i.e. having to prefix the call to Setup() with the filter type (i.e. ::ButterLp::Setup()). I will find a way around that.

Keep in mind this is still beta (0.8.4). It is being worked on. The major interfaces won't be changing much though, and the class hierarchy is very near its final form.

Last night I got the Chebyshev I Low shelf prototype mostly working (just having some trouble with the ripple specification). I'll have the Chebyshev type II soon. I have the formulas for elliptic shelf but they are pretty daunting. For fun I will try implementing Bessel type responses completely on my own that should be interesting.

There are some changes I can make to the archticture of representing roots that will allow for very uniform treatment of prototypes and their transformations, this will shrink the code a good bit.

And there are still tons of optimizations left, I am saving that for when I have all the filter types done (still need ChebyIILowShelf, ChebyIIHighShelf, ChebyIIPeaking, EllipticLowShelf, EllipticHighShelf, EllipticPeaking, all Bessel).

Post

Updated to 0.8.5

After much study I was able to rewrite the low pass and low shelf analog prototypes to generate poles and zeroes entirely in the s-domain. This was as per Martin's suggestion of allowing positive and negative infinity as representations for the roots. Thanks to this feature, it was possible to completely generalize the construction of digital filters. It works with the following template:

Code: Select all

template<class Proto, class Trans, int maxorder, int channels>
struct Filter : ...
Where Proto is the analog prototype. Currently Butter, ButterShelf, ChebyI, ChebyIShelf, ChebyII, ChebyIIShelf, and Elliptic are defined.

Trans is the transformation, one of LowPass, HighPass, BandPass, or BandStop.

This means that the addition of new filters is as easy as designing the analog prototype in terms of poles and zeroes (allowing infinity and negative infinity as defined values), and then adding a few lines to instantiate templates. For example:

Code: Select all

	template<int order, int channels>
	struct BesselBandStop : Filter<Bessel, BandStop, 2*order, channels>
	{ /*...*/ };
I am happy with this interface so the class hiearchy is unlikley to change from now on. There is some fine-tuning that needs to be done with filter parameter specification. There are still lots of optimizations, so I will continue to work on this.

There is no redudant code or repeated filter formulas anywhere. Each algorithm is neatly encapsulated into a single class and maps directly to IIR concepts. A top down, functional programming model allows the building blocks to be re-assembled in different ways and allowing for full optimizations. And best of all, the library allocates no memory.

New filters added:

ChebyILowShelf
ChebyIHighSelf
ChebyIEq
ChebyIILowShelf
ChebyIIHighSelf
ChebyIIEq

Summary:

Code: Select all

- Added the ChebyIShelf prototype
- Renamed ButterPeak to ButterEq
- Added ChebyILowShelf, ChebyIHighShelf, ChebyIEq filters
- Added ChebyIILowSHelf, ChebyIIHighShelf, ChebyIIEq
- Fixed a bug with Cascade::Clear() crashing when getting called before stages are initialized
- Rewrote Design() for ChebyII to work entirely in s-plane, compute zeros, and use simplified formula
- Added methods to transforms to operate on an entire Layout
- Removed the hack for skipping the bilinear transform on Chebyshev Type II zeros
- Generalized construction of all Chebyshev Type II filters
- Added some bilbiographical annotations
- Added Root type for representation of positive and negative infinity
- Generalized all transformations with added support for infinite roots
- Generalized construction of all Butterworth filters
- Generalized construction of all Chebyshev Type I filters
- Generalized construction of all Elliptic filters
- Embedded normalization information into the analog prototypes
- Modified transformations to also transform the normalization frequency

Post

What is the proper fix for Int64 ?

Post

meeloo wrote:
thevinn wrote:What is the typename of the 64 bit integer on mac?
Here is what we use for all posix platforms in libnui:

Code: Select all

#include <sys/types.h>
#include <ctype.h>

typedef int8_t    int8;
typedef int16_t   int16;
typedef int32_t   int32;
typedef int64_t   int64;
typedef u_int8_t  uint8;
typedef u_int16_t uint16;
typedef u_int32_t uint32;
typedef u_int64_t uint64;
Cheers

Post

PROJECT HAS BEEN MOVED
Here is the official location:

http://code.google.com/p/dspfilterscpp/

Google has an easier to use interface for uploading files and managing projects so I switched. It is also faster.

I have updated the version to 0.8.6. New in this release is the source code for a Juce test application that exercises all of the available filters. You can see the brick wall, response, phase, and pole/zero plot. Parameters can be adjusted in real time including order, prototype, and kind of filter.

If you want to play right away I made a windows .exe binary available for download. Or you can build it yourself from the sources (however, you will need to get the JUCE amalgamation source and header directly from the official site).

Code for the test app is MIT-licensed, and includes the Layout class I developed for dynamically adjusting the location of child items in a window when the parent resizes.

As always, feedback and/or constructive criticism is greatly appreciated. Thanks to everyone who has been helping me muddle through this!

Here's a screenshot of the test app:

Image

Post

Looking good thevinn, you're on a roll :shock:

**Edit - the demo binary isn't working here, I get an error message saying the application is configured incorrectly and may need reinstalling..

Post

Caco wrote:**Edit - the demo binary isn't working here, I get an error message saying the application is configured incorrectly and may need reinstalling..
UGH, I linked it with "Multithreaded DLL". I will relink it and upload it again...sorry!!!

Okay I re-uploaded a new one, v.0.8.6.1 please let me know if it works.

Thanks!

Post Reply

Return to “DSP and Plugin Development”