Oversampling to get rid of aliasing

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

What do you mean by "not great at higher frequencies" and "not very flexible" ?

FIR filters are the best in both situations.

There is no reason to use a minimum phase FIR other than the fact it reduces latency. You can use an equal phase FIR if you want to delay the output by half the table length. With minimum phase the delay is usually only a few samples. In Xhip for example it is zero for blep and one for blamp.

Technically it is 1/os for the blep impulse but simply dropping the first sample of the blep impulse creates such a small discontinuity that it is far less than the stop-band level of the filter anyway and so has no considerable consequence.

As far as efficiency, in Xhip I can generate tens of thousands of ramp waveforms using a single core. This is about an order of magnitude greater than what a wavetable would be capable of and with less aliasing too! If you have any doubts about the method, try Xhip yourself. Also download the code I linked and write a simple oscillator to test. The same FIR filter can be applied to anti-alias anything at all, modulation signals in an effects plugin for example, whatever you like.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Well you have to recompute your blep more often at higher frequencies, right?

And by not very flexible it's quite obvious, you can only make a few waveforms with bleps. Additively with individual sines you can do anything and have it change in real time.
Developer of Photosounder (a spectral editor/synth), SplineEQ and Spiral

Post

Since the table only contains five samples it means you can generate up to rate / 5, or about 9000hz before the expense is equal to a wavetable with linear interpolation without including cache considerations. Such a wavetable would alias like crazy.

Below 9000hz the FIR oscillator becomes twice as efficient every octave below. By the time you are at 4500hz (the highest musical note) it is twice as efficient.

You can make any waveform imaginable with FIR filters like blep.

http://sourceforge.net/projects/protracker/

Download protracker and play some modules. Do you hear any aliasing? No. Do you consider these PCM samples "limited" ?
Last edited by aciddose on Fri Jul 31, 2015 12:34 am, edited 1 time in total.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote:You can make any waveform imaginable with FIR filters like blep.
Wait, how would you do that? Let's say you have a completely arbitrary waveform, how does that work if you change the frequency like with FM synthesis?
Developer of Photosounder (a spectral editor/synth), SplineEQ and Spiral

Post

If you change the frequency like with FM synthesis?

You should download the Xhip alpha: http://xhip.net/alpha/

https://soundcloud.com/xhip/xmod
https://soundcloud.com/xhip/thruzero
https://soundcloud.com/xhip/pcm
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Short version is:

What you are doing is convolving the FIR filter with discontinuities in the "abstract" waveform before it is sampled. Any order is possible, although Xhip only implements 0th (blep) 1st (blamp) and 2nd (splamp?) and nothing there currently uses 2nd order, that would be useful only for 2nd order curved waveforms that haven't yet been released as part of the alpha. (More a Xhip 2 thing.) 2nd order and higher are also used to anti-alias sines (for sync of sine), although the sine option in Xhip is currently naive because it is far cheaper.

If you want a fully anti-aliased sine to use for xmod, load a sample of a sine. Try to use a minimal number of samples like 8 or 16 or CPU use will be very high for higher notes. Ideally such a waveform would use the higher order FIR filters and there would be a "mipmap" of the wave vector tables. Each time the frequency doubles you need half as many points, so it is just like a wavetable only far more accurate and far less expensive.

You can insert the impulses (blep, etc) at any fractional position. They are band-limited "wavelets" essentially. No matter how many you add at which phase or which amplitude the sum of them all is band-limited.

Think of this like no matter how many 1000hz sines you add at various phases or amplitudes, the sum of them will always be some amplitude of 1000hz only.

Due to this fact you can build up the waveform from its discontinuities and then integrate the result, producing a perfectly anti-aliased waveform, any shape you can imagine limited to the order of impulses you have.

The special thing about BLEP is that rather than insert windowed sinc wavelets and then integrate, the wavelets themselves are integrated ahead of time which saves that step.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

earlevel wrote:(2) So, to reduce the sample rate to half, you need to first remove content at or above a quarter of the sample rate (96k->48k, you'd first filter everything 24k and higher). (3) Throw away excess samples. Yep. Because you filtered in step 2, the signal is now "oversampled" by 2x—it has more samples than needed to convey the information, by a factor of 2. Toss every other sample.
Ok, after finding a decent LP filter and applying the oversampling -> filter -> downsampling method described by earlevel to my naive sawtooth oscillator. I can definitely confirm at least 40% to 50% reduction in aliasing. I can see this clearly with a spectrum analyzer.

I suspect that if I do a sharper cut filter, I can eliminate much more aliasing. Not sure though.
www.solostuff.net
Advice is heavy. So don’t send it like a mountain.

Post

No you can't. The harmonics fall off by 1/n. This means that if you play a tone at just below nyquist the first alias will be reduced by the filter but the second will not, because it is in your pass-band already.

For example:
sample rate = 48000 * 2 = 96000, nyquist = 48000
hz = 23000 (in band)
1st = 46000 (in band)
2nd = 69000 - 48000 = 21000 above band
48000 - 21000 = alias at 27000, level = 1/3
3rd = 92000 - 48000 = 44000 above band
48000 - 44000 = alias at 2000, level = 1/4

So, for the alias at 27000hz, we'll ignore this since it's out the audible range and will be killed by the decimation filter anyway.

2000hz however is in the pass-band! Its unfiltered level is 1/4 or -12db.

It's easy to mess up this math, but I think it's correct.

The only way to get further anti-aliasing from oversampling is to increase the multiplier. To get the same quality as the minblep implementation I linked you, for free, where you need to do near zero effort to implement it and where the efficiency is more than double that of any even remotely comparable anti-aliasing filter you need to over-sample by something like 32 times or more. (Actually, doesn't -80db require 8192 times over-sample?)

Each time you double the multiplier you get 6db (twice) more cut.

If you double the length of the FIR "minblep" filter you can get ten times as much cut. (-100db rather than -80db.) Doubling the FIR length doubles the slope and this makes it possible to adjust the window to allow much lower stop-band levels.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose, makes sense. Highly pitched sawtooth would quickly falloff X2 nyquist and get mirrored back, didn't think of this!!. But the thing that still makes me contemplate is that most people can't hear anything above 16Khz or so. And that is a very high pitch that most musicians don't use. I will have to rethink what is more valuable to me, CPU or sound. For a unison sound, or for stacking poly, I think that most people won't even care about 1/4 or lower aliasing, thats assuming that they can hear it. In fact, people with analog hardware (including my self) deal with noise/hum that is worse than this.

But your right, if I have to increase the multiplier by more than X4. Then I won't do it. Too much for little.

I will definitely try minblep, and see how it performes CPU wise. Thanks for that tip. May be I will do two types of oscillators. dirty and clean :wink:
www.solostuff.net
Advice is heavy. So don’t send it like a mountain.

Post

A FIR filter like minblep is more efficient than 2x over-sample.

You have to consider that when you play the tone at nyquist with a real anti-aliasing filter like blep, the aliasing is absolutely identical as at any other frequency. This is because the filter naturally adapts, the higher frequency means you put in more impulses.

With a fixed decimation filter at 2x over-sample it isn't adaptive like that. The filter at nyquist is not nearly as strong as at 1hz. It's just as expensive, but becomes far less effective at higher frequencies.

A real anti-aliasing filter becomes more expensive at higher frequencies but is far less expensive over-all. It also maintains the same effectiveness at all frequencies. It is even equally effective at frequencies above nyquist. It remains exactly as effective at every possible frequency. This is why you can do "FM" as in the soundcloud examples I linked without aliasing. The only aliasing is due to naive sampling of the modulator (as opposed to computing the integral) and the "side-bands" generated due to frequency modulation. The carrier however is always anti-aliased.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote:You can make any waveform imaginable with FIR filters like blep.
I don't think you really mean "imaginable" here, do you? I imagine a waveform with 1st harmonic, and 50% at 2nd and 5th harmonics...
My audio DSP blog: earlevel.com

Post

Sure, why do you think you can't do that with FIR filters?

Since such a waveform contains no discontinuities a filter isn't even really required.

http://www.wolframalpha.com/input/?i=pl ... 8x*6*pi%29

That would be this, correct?

Such a waveform (really a sum of partials) should be constructed using additive synthesis.

Applying a FIR filter to discontinuities requires an abstract waveform with nth order discontinuities. Or in other words one not defined by a finite number of partials, but rather infinite partials.

So let's define "waveform" as "waveform with nth order discontinuities".
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote:Sure, why do you think you can't do that with FIR filters?
I didn't say that. I quoted your "...with FIR filters like blep". I don't think you're going to get to the very simple example I gave with an FIR filter like blep. But maybe you meant "...with FIR filters (of which blep is an example)".

But now that you mention it, I'm not even sure what you mean by "with FIR filters" (stop). For instance, what are you talking about filtering? Sorry, I'm buried in work and don't have time to read the whole thread, and dig into source code you linked to in various posts. Anyway, answer if you want—I was just curious about what you meant by that statement specifically.
My audio DSP blog: earlevel.com

Post

I'm talking about filtering nth order discontinuities.

If you have a waveform without discontinuities a FIR filter can't be used to anti-alias it.

As I said, any waveform with a discontinuity will have an infinite number of harmonics.

If your waveform is a combination of a finite number of harmonics (like you gave as an example) it can't be anti-aliased with FIR filters because there is nothing to apply the filter to. It actually could, but sin() is infinite order meaning your FIR would be nothing but very faint noise (or zero) assuming you had an infinite amount of time to infinitely integrate it.

Its application would also be far more expensive and undefined... Where do you insert the impulse? All the phases are identical in sin() so how do you decide the offset of the FIR?

As far as waveforms that are built up of zero order (pulses), first order (triangle, ramps that change direction), second order (simple spline shapes) and similar however they are entirely practical to anti-alias with a FIR filter.

For example:

Code: Select all

template <typename T>
struct discont_t
{
T phase;
T level; // zero order
T delta; // first order
T poly; // second order
T cubic; // third order
};
The table contains the phase at which a discontinuity occurs, and the amount of change in different orders.

You could also use an array if you have many orders and a for loop to apply them.

Code: Select all

template <typename T>
struct start_t
{
 T level;
 T delta;
 T poly;
 T cubic;
};

template <typename T, int LENGTH>
struct waveform_t
{
 const char *name;
 start_t<T> start;
 discont_t<T> step[LENGTH];
};
The waveform type can contain the list of discontinuities (changes) in the waveform as well as other stuff like a name. What you want to include in there depends on your own implementation.

Now let's build a square wave, ramp and triangle wave.

Code: Select all

waveform_t<float, 2> pulse = 
{ "pulse", { -1.0f, 0.0f, 0.0f, 0.0f },
{ 0.5f, 2.0f, 0.0f, 0.0f, 0.0f },
{ 1.0f, -2.0f, 0.0f, 0.0f, 0.0f },
};

waveform_t<float, 1> ramp = 
{ "ramp", { -1.0f, 2.0f, 0.0f, 0.0f },
{ 1.0f, -2.0f, 0.0f, 0.0f, 0.0f },
};

waveform_t<float, 2> triangle = 
{ "triangle", { 1.0f, -2.0f, 0.0f, 0.0f },
{ 0.5f, 0.0f, 4.0f, 0.0f, 0.0f },
{ 1.0f, 0.0f, -4.0f, 0.0f, 0.0f },
};
So you should see we can define complex waveforms using a table like this because the waveforms are defined by their discontinuities.

The oscillator code itself can loop through this table, detecting when the phase has crossed the point at which a discontinuity occurs and insert the impulses (FIR filter) at the fractional position at which it occurred.

You can also jump to any phase position (sync) at any time and anti-alias the change by looking up the start condition and end condition from the table, then inserting the impulses to filter the resulting discontinuity.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Also, depending on your implementation you may find it easier to store the actual values in the table rather than changes.

Storing changes complicates a waveform change, since you need to run through the table to get the actual value at each step.

It also needs to go into another temp table that has real values for further changes and to reset the summed changes each step. This is needed if you have fractional values that don't have an exact representation in float, because error can accumulate.

For these basic waveforms you don't need to worry so much, but just keep in mind this optimization makes the oscillator implementation slightly more complex.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post Reply

Return to “DSP and Plugin Development”