Anti-aliasing through oversampling
-
- KVRer
- Topic Starter
- 1 posts since 28 Aug, 2015
I'm coding my first DSP project, a virtual analog synth, just for fun and for building familiarity with realtime audio programming.
I've got some nonlinear elements (in particular a distortion) which alias significantly. I understand that I should upsample, perform the distortion, then downsample. What are the best techniques for doing upsampling and downsampling in this context, where I want to prioritize simplicity, low latency and low CPU usage?
The information about resampling that I have found on the web seems to focus on FIR filters with sinc kernels with very long tails -- which may be great for non-realtime samplerate conversion, but afaics is not so useful for realtime processing.
I've got some nonlinear elements (in particular a distortion) which alias significantly. I understand that I should upsample, perform the distortion, then downsample. What are the best techniques for doing upsampling and downsampling in this context, where I want to prioritize simplicity, low latency and low CPU usage?
The information about resampling that I have found on the web seems to focus on FIR filters with sinc kernels with very long tails -- which may be great for non-realtime samplerate conversion, but afaics is not so useful for realtime processing.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
No real solution except indeed FIR, processing in high frequency (which uselly is the most costly), then filtering and finally downsampling.
I've given here several times the paper I used for ATK SD1, and it is "simple" (not as simple as the low pass filter, but still simple), as well as cheap for CPU power.
I've given here several times the paper I used for ATK SD1, and it is "simple" (not as simple as the low pass filter, but still simple), as well as cheap for CPU power.
-
Smashed Transistors Smashed Transistors https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=339459
- KVRist
- 142 posts since 10 Oct, 2014
Here is some decimator code, those are optimized FIRs
You can use decimator9, the Calc method takes two input samples and provide one output sample.
https://github.com/2DaT/Obxd/blob/maste ... ecimator.h
Nota: this code is based on the good old french book "Traitement Numérique du Signal" by Maurice Bellanger.
You can use decimator9, the Calc method takes two input samples and provide one output sample.
https://github.com/2DaT/Obxd/blob/maste ... ecimator.h
Nota: this code is based on the good old french book "Traitement Numérique du Signal" by Maurice Bellanger.
-
Music Engineer Music Engineer https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=15959
- KVRAF
- 4292 posts since 8 Mar, 2004 from Berlin, Germany
i usually use elliptic filters for up- and downsampling. they give the most bang for the buck. they are not linear phase though, but i don't care very much about that.
-
- KVRist
- 53 posts since 4 Sep, 2014
The method that I have recently discovered is using half-band filters. Dirt cheap and can be cascaded for higher degrees of oversampling, e.g. 8x is 2x then 2x then 2x. Beats the hell out of the linear phase FIR I was using before.
- KVRAF
- 3008 posts since 17 Apr, 2010 from Croatia
In my attempts I have used adaptive oversampling, based on note frequency against sampling frequency and with a cap on 8x or 16x. You have to be a little careful on sweeps, but my theremin test turned out beautifully with little to no aliasing on sine, saw and squares up to bat distractions!
-
- KVRer
- 8 posts since 14 Dec, 2009
Here's a decimator implementation that works great. Articles linked to in the src are a good read, too.
https://gist.github.com/kbob/045978eb044be88fe568
https://gist.github.com/kbob/045978eb044be88fe568
-
GospelMusicians GospelMusicians https://www.kvraudio.com/forum/memberlist.php?mode=viewprofile&u=258795
- KVRist
- 210 posts since 14 Jun, 2011 from Orlando
Hey guys...Sorry to bring this post back up, but very interested in this decimator concept. If I"m understanding this right, you do the following:pendejo wrote:Here's a decimator implementation that works great. Articles linked to in the src are a good read, too.
https://gist.github.com/kbob/045978eb044be88fe568
1. Use pre-rendered oversampling to reduce aliasing. Oversampling will create more harmonics and frequencies to mask the aliasing.
2. Then you use a decimator live, as it is lower CPU than oversampling?
3. Proceed forward with your linear interpolation if using wavetables?
GospelMusicians.com - #1 Site for Gospel Musicians.
NeoSoulKeys.com - One of the Most Authentic, Realistic, and buttery EP
NeoSoulKeys.com - One of the Most Authentic, Realistic, and buttery EP
-
- KVRist
- 53 posts since 4 Sep, 2014
1. Run the synth (generate your waveforms) at a higher samplerate.
2. Perform nonlinear function (waveshaping, distortion, compression, etc).
3. Filter out the higher frequencies.
4. Decimate to project samplerate.
So whether it's polyBLEP or interpolating your wavetables, do it at that oversampled rate, then after your nonlinear processes, then filter, then throw away the unneeded samples. Often the final two steps are incorporated into the same process.
2. Perform nonlinear function (waveshaping, distortion, compression, etc).
3. Filter out the higher frequencies.
4. Decimate to project samplerate.
So whether it's polyBLEP or interpolating your wavetables, do it at that oversampled rate, then after your nonlinear processes, then filter, then throw away the unneeded samples. Often the final two steps are incorporated into the same process.
-
- KVRist
- 53 posts since 4 Sep, 2014
In other words, if I'm running at 8x oversampled then my oscillator will be generating 8 samples instead of one. Which is expected, since you are running 8x faster than the project samplerate. Presumably your oscillators are bandlimited and aren't aliasing on their own. Interpolating wavetables or something quasi-bandlimited like polyBLEP would both work, for example.
Okay, got your 8 samples, now distort them or whatever else happens. Then on to filtering. The decimators mentioned above are good examples of this. The goal of filtering is to eliminate the top 7/8ths of the frequency spectrum, because when you throw away your unneeded samples anything in that region will fold back and alias, which is exactly what you don't want.
One way to do it would be with an IIR filter. This is presumably what Music Engineer mentioned earlier. It's going to be less computationally expensive, but it will skew phase. Sometimes preserving phase is important, sometimes it isn't. Maybe for a synth it wouldn't be. Usually you want to preserve phase, so you use some kind of a symmetric FIR lowpass filter instead. Tons of different ways to do it. One way is to use a sinc filter with a Blackmann window, that's what pendejo suggested. Smashed Transistors suggests using a 17 point halfband filter, which is a result that I've gone with that I've found to be very effective. In the example above, you would need to cascade three halfband filters (8x->4x, 4x->2x, 2x->1x). Another option is to do an L-th band filter, which is less efficient but would go from 8x to 1x in one swoop. I'm experimenting with a 31-point 4-th band filter (meaning it would go from 4x to 1x in one pass) right now, actually, but to do an 8-th band filter it would take even more points to get it to work well enough to prevent any folding over. Halfband filters are really efficient because almost half of the coefficients are zero. That's a big reason why you see oversampling in multiples of 2...
Okay, to sum. Normally we do this - take our sample, zero stuff, filter, process, filter, throw away all but one sample. You can do the first three steps at the same time by running your oscillator at that higher samplerate, and you can do some consolidation in the algorithm to do the last two steps at the same time.
And that, as they say, is that.
Okay, got your 8 samples, now distort them or whatever else happens. Then on to filtering. The decimators mentioned above are good examples of this. The goal of filtering is to eliminate the top 7/8ths of the frequency spectrum, because when you throw away your unneeded samples anything in that region will fold back and alias, which is exactly what you don't want.
One way to do it would be with an IIR filter. This is presumably what Music Engineer mentioned earlier. It's going to be less computationally expensive, but it will skew phase. Sometimes preserving phase is important, sometimes it isn't. Maybe for a synth it wouldn't be. Usually you want to preserve phase, so you use some kind of a symmetric FIR lowpass filter instead. Tons of different ways to do it. One way is to use a sinc filter with a Blackmann window, that's what pendejo suggested. Smashed Transistors suggests using a 17 point halfband filter, which is a result that I've gone with that I've found to be very effective. In the example above, you would need to cascade three halfband filters (8x->4x, 4x->2x, 2x->1x). Another option is to do an L-th band filter, which is less efficient but would go from 8x to 1x in one swoop. I'm experimenting with a 31-point 4-th band filter (meaning it would go from 4x to 1x in one pass) right now, actually, but to do an 8-th band filter it would take even more points to get it to work well enough to prevent any folding over. Halfband filters are really efficient because almost half of the coefficients are zero. That's a big reason why you see oversampling in multiples of 2...
Okay, to sum. Normally we do this - take our sample, zero stuff, filter, process, filter, throw away all but one sample. You can do the first three steps at the same time by running your oscillator at that higher samplerate, and you can do some consolidation in the algorithm to do the last two steps at the same time.
And that, as they say, is that.
-
- KVRer
- 4 posts since 27 Dec, 2015
I tried following the advice in this discussion for my synthesizer, but I'm not certain that I've done everything correctly. I've tried this with an FIR filter, and now with a PolyPhase filter, and in both cases, I am losing a lot of amplitude. Is this normal? My best guess is that all the zeros that I inserted during the upsampling stage have something to do with it. And I suppose I could just amplify the results to compensate for the loss of amplitude.
Any thoughts?
BTW I'm oversampling 8x, but am currently doing so AFTER the oscillators.
Any thoughts?
BTW I'm oversampling 8x, but am currently doing so AFTER the oscillators.
-
- KVRist
- 53 posts since 4 Sep, 2014
Yes, when you insert zeroes you want to compensate level. Multiply your signal by L. So a halfband filter (L=2) you would want to multiply the input by 2 OR multiply all of the coefficients by 2 to "pre-bake" the gain in. In my particular case the coefficients are local to both the upsampler and downsampler so the DC gain is 1 and I multiply the input by 2.
Filter before you downsample or you could alias.
Filter before you downsample or you could alias.