A Collection of Useful C++ Classes for Signal Processing

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

Post

xoxos wrote:nescient
Thanks, xoxos!

I learned a new word today!

Post

thevinn wrote:
asomers wrote:Some way 'patch' another audio signal to the filter cutoff (or other parameters), somehow avoiding per-sample coefficient calcuations.
Yeah you and me both. I was going to try interpolation of coefficients between either the starting and ending point, or through the use of "key frames" (i.e. recalculate some of the coefficients along the way but not every sample).

I get the feeling I'm in over my head though. I remember reading some stuff about keeping a filter stable through parameter changes but I don't recall where it was.
It could have been this: http://www.dafx.ca/proceedings/papers/p_057.pdf

I recall a teacher of mine telling me that you can interpolate biquad coeffs with guaranteed stability, but that's a pretty general statement and I haven't investigated further.

Post

I've used exponential smoothing of biquad coefficients in the past. However, I think this was a mistake. Linear interpolation guarantees stability, but exponential smoothing may not.

If you want the highest quality sweeps, you could perform full coefficient calculation at a block rate (i.e. every 16, 32 or 64 samples), and then linear interpolation at the sample rate. But this might be overkill for many applications.

Sean Costello

Post

valhallasound wrote:If you want the highest quality sweeps, you could perform full coefficient calculation at a block rate (i.e. every 16, 32 or 64 samples), and then linear interpolation at the sample rate. But this might be overkill for many applications.
Funny that you mention that, but I was thinking the same thing! Except that instead of linear interpolation of the coefficients, perhaps using polar coordinates and interpolating the poles?

Post

asomers wrote:It could have been this: http://www.dafx.ca/proceedings/papers/p_057.pdf
That's not it, but it looks really useful and a great starting point.

I was referring to this article:

http://www.native-instruments.com/filea ... pology.pdf

Which seemed helpful until I read it a few times and realized, that I don't understand it at all.

Post

thevinn wrote:
valhallasound wrote:If you want the highest quality sweeps, you could perform full coefficient calculation at a block rate (i.e. every 16, 32 or 64 samples), and then linear interpolation at the sample rate. But this might be overkill for many applications.
Funny that you mention that, but I was thinking the same thing! Except that instead of linear interpolation of the coefficients, perhaps using polar coordinates and interpolating the poles?
Interpolating the poles seems like it would be a smoother sweep, but it would add to the cost.

If the time variation is being derived from a relatively slow signal, like an LFO or a user parameter that is automated, you may want to smooth the actual frequency and Q parameters with a 1-pole filter that has a fixed time constant, like 50 msec or so. Calculate the filter coefficients at the block rate, based on the smoothed parameters, and then use linear interpolation at the sample rate to reduce noise.

Sean Costello

Post

I'm about 20% of the way through a rewrite of this library and I have to warn you all I found a ton of bugs...avoid this version like the plague!

Post

So...in the process of rewriting the library I found a lot of bugs. The original class design was a bit confusing as well. I'm in the middle of rewriting and I have uploaded a preliminary alpha set of sources. Lots of filters are missing but the basic architecture is there.

Smooth parameter changes is implemented, and works great with biquads.

The new demo plays sound and supports parameter changes. A lot of functionality is missing but all of the biquads work, unlike before where they were totally absent.

Here is a pre-built Windows demo:

http://dspfilterscpp.googlecode.com/fil ... oWin32.zip

Sources for everything:

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

If anyone wants to help me, for example, with a Macintosh or Linux make setup, that would be great. I would also love Android or iPhone make system, since Juce supports all those platforms, it should not be any problem whatsoever to port the demo to those devices. Some changes to the window might be needed though.

Post

asomers wrote:I recall a teacher of mine telling me that you can interpolate biquad coeffs with guaranteed stability, but that's a pretty general statement and I haven't investigated further.
Perhaps the result is stable, but it is definitely not music to the ears. My Biquad implementation now has routines for interpolating coefficients, poles, and general filter parameters.

The coefficient interpolation sounded the worst. Granted, it was better than no interpolation. But big changes produced artifacts, zippering, the usual stuff.

Pole/zero interpolation was definitely a step up. Less excess energy fluctuations but still a chirp or bloop depending on the magnitude of the change.

Of course, interpolation of the filter parameters (cutoff frequency for example) worked the best. In fact it sounds perfect. The only objectionable sounds come when you screw around, like going from Q=0.25 to Q=20 but that has to do with the filter and not the interpolation.

Per-sample interpolation of filter parameters is fine for a biquad but a higher order elliptic? Probably not a good idea. Since interpolation of coefficients and pole/zeros sounds reasonable for small changes, ultimately I would like to use that for a few samples, and do the full filter recalculation every so often, as was suggested previously.

Post

I'm toying around with an example iPhone app and can't quite grasp how to use the dspfilterscpp rewrite. I did see a old post using the previous version (templates and all). Digging around in the sample app, I see AudioOutput.cpp calling FilteringAudioSource.cpp setFilter(Filter*). After that, it's getting a little confusing to this nighttime coder.

Can someone give a quick example of setting up and using a RBJ LowPass?

I'll be glad to post code when I get something working properly with my RemoteIO callback.

Post

Yeah I should have posted an example. Anyway, I added the file "Documentation.cpp" to the sources and I added another template SimpleFilter. So here is the documentation:

Code: Select all

// This is the only include you need
#include "DspFilters/Dsp.h"

static void UsageExamples ()
{
  // create a two channel audio buffer
  int numSamples = 2000;
  float* audioData[2];
  audioData[0] = new float[numSamples];
  audioData[1] = new float[numSamples];

  // create a 2-channel RBJ Low Pass with parameter smoothing
  // and apply it to the audio data
  {
    // "1024" is the number of samples over which to fade parameter changes
    Dsp::Filter* f = new Dsp::SmoothedFilterDesign
      <Dsp::RBJ::Design::LowPass, 2> (1024);
    Dsp::Parameters params;
    params[0] = 44100; // sample rate
    params[1] = 4000; // cutoff frequency
    params[2] = 1.25; // Q
    f->setParameters (params);
    f->process (numSamples, audioData);
  }
 
  // set up a 2-channel RBJ High Pass with parameter smoothing,
  // but bypass virtual function overhead
  {
    // the difference here is that we don't go through a pointer.
    Dsp::SmoothedFilterDesign <Dsp::RBJ::Design::LowPass, 2> f (1024);
    Dsp::Parameters params;
    params[0] = 44100; // sample rate
    params[1] = 4000; // cutoff frequency
    params[2] = 1.25; // Q
    f.setParameters (params);
    f.process (numSamples, audioData);
  }

  // create a 2-channel Butterworth Band Pass of order 4,
  // with parameter smoothing and apply it to the audio data.
  // Output samples are generated using Direct Form II realization.
  {
    Dsp::Filter* f = new Dsp::SmoothedFilterDesign
      <Dsp::Butterworth::Design::BandPass <4>, 2, Dsp::DirectFormII> (1024);
    Dsp::Parameters params;
    params[0] = 44100; // sample rate
    params[1] = 4; // order
    params[2] = 4000; // center frequency
    params[3] = 880; // band width
    f->setParameters (params);
    f->process (numSamples, audioData);
  }
 
  // create a 2-channel Inverse Chebyshev Low Shelf of order 5
  // and passband ripple 0.1dB, without parameter smoothing and apply it.
  {
    Dsp::Filter* f = new Dsp::FilterDesign
      <Dsp::ChebyshevII::Design::LowShelf <5>, 2>;
    Dsp::Parameters params;
    params[0] = 44100; // sample rate
    params[1] = 5; // order
    params[2] = 4000; // corner frequency
    params[3] = 6; // shelf gain
    params[4] = 0.1; // passband ripple
    f->setParameters (params);
    f->process (numSamples, audioData);
  }
 
  // create an abstract Butterworth High Pass of order 4.
  // This one can't process channels, it can only be used for analysis
  // (i.e. extract poles and zeros).
  {
    Dsp::Filter* f = new Dsp::FilterDesign
      <Dsp::Butterworth::Design::HighPass <4> >;
    Dsp::Parameters params;
    params[0] = 44100; // sample rate
    params[1] = 4; // order
    params[2] = 4000; // cutoff frequency
    f->setParameters (params);
    // this will cause a runtime assertion
    f->process (numSamples, audioData);
  }

  // Use the simple filter API to create a Chebyshev Band Stop of order 3
  // and 1dB ripple in the passband. The simle API has a smaller
  // footprint, but no introspection or smoothing.
  {
    Dsp::SimpleFilter <Dsp::ChebyshevI::BandStop <3>, 2> f;
    f.setup (3,    // order
             44100,// sample rate
             4000, // center frequency
             880,  // band width
             1);   // ripple dB
    f.process (numSamples, audioData);
  }
}

Post

asomers wrote:That's great news. After working with the code for a day I realized some hinderances. I wanted to create an interface though which I could specify the filter type and order. I would think the most straightforward way is a polymorphic filter class that does not use templates for the filter order. Maybe templates could still be useful for precision....Bottom line, I hope this is being developed to operate in real-time, i.e. not only can the filter settings vary in real time but the filter type and order can be changed with relative ease, as well.
I did everything you asked. Yeah it was about a year and a half later but better late than never?
Last edited by thevinn on Wed Feb 16, 2011 2:43 am, edited 1 time in total.

Post

asomers wrote:Have you considered breaking out some of the redundant stuff into separate source files? Having everything in two files is pretty cumbersome... Of course I could do this on my own but if you're concerned about readability...
Did that too

Post

DaveHoskins wrote:When sending zeros or very low values it needs to normalise the filter. I had 6% CPU with audio and when stopped (in FL studio) it shot to just over 50%.
Yes, I discovered this in my own application as well. This is fully addressed in the new version, check out the class DenormalPrevention, which is used automatically by DirectFormI and DirectFormII.

Post

antto wrote:i'm interested in the bessel-lowpass filter
i know a bessel filter has the *best* phase-response of them all, and is suitable for AA-filtering where the phase is important to be preserved
i've already used a bessel filter (generated with a an applet (mkfilter)) and it worked quite well, but after that, i can't really *change* the filter in any way now i need another bessel filter but not for AA-filtering, so the filter coefficients have to be calculated on init, the applet i used won't work in this case
Well it took a year but the Bessel support has been fixed up and is checked in. You should be able to manipulate the filter settings in real time with no problem.

Post Reply

Return to “DSP and Plugin Development”