Oversampling in VMD
Oversampling in VMD
i always thought of oversampling as a standout feature of my R_Ware modules, but i am open to share.
here's an IIR-based oversampling class for use in VMD. there's a usage example vmod in there as well.
it's MIT licensed, so you can use it privately and commercially.
https://github.com/NeverKnewTheName/R_OpenLib
the up- and downsampling filters are biquad fitlers that have carefully chosen resonance values for maximum steepness. if you want to know more about stacking resonances have a look at this amazing blog: https://www.earlevel.com/main/2016/09/2 ... g-filters/
this is the start of me open sourcing my dsp library. but for now i'll keep the high-performance, linear-phase polyphase FIR oversamplers exclusive to R_Ware modules. stay tuned for future updates on this repo though.
be aware that oversampling is not the answer to all aliasing problems. there are other ways to anti-alias procedures as well. i'll share more in the future.
Let me know if you like this project, if you find any issues, if you have any request, etc.
here's an IIR-based oversampling class for use in VMD. there's a usage example vmod in there as well.
it's MIT licensed, so you can use it privately and commercially.
https://github.com/NeverKnewTheName/R_OpenLib
the up- and downsampling filters are biquad fitlers that have carefully chosen resonance values for maximum steepness. if you want to know more about stacking resonances have a look at this amazing blog: https://www.earlevel.com/main/2016/09/2 ... g-filters/
this is the start of me open sourcing my dsp library. but for now i'll keep the high-performance, linear-phase polyphase FIR oversamplers exclusive to R_Ware modules. stay tuned for future updates on this repo though.
be aware that oversampling is not the answer to all aliasing problems. there are other ways to anti-alias procedures as well. i'll share more in the future.
Let me know if you like this project, if you find any issues, if you have any request, etc.
-
- Posts: 69
- Joined: Thu Jun 04, 2020 2:08 am
Re: Oversampling in VMD
Such endless generosity! Thanks for all you do, Chris!
JK
JK
Re: Oversampling in VMD
Hi Chris,
Very nice of you to post this but I'm struggling to understand the working of the main process() method.
I'm a little worn out (coping with flooding) so might be missing something blindingly obvious but I don't understand how information flows in the loop. How is os[ 0 ] at the end of the method affected by anything going on in the zero-stuffed parts of the array?
Very nice of you to post this but I'm struggling to understand the working of the main process() method.
Code: Select all
public double process( double value, R_IOversampledProcessor processor )
{
double[] os = new double[m_osFactor];
os[0] = value; // first value is valid, others are zero-stuffed
//////// OVERSAMPLING
for( int i = 0; i < m_osFactor; ++i )
{
os[i] = m_upSampler.process( os[i] );
os[i] = processor.process( m_osFactor * os[i] );
os[i] = m_downSampler.process( os[i] );
}
//////// OVERSAMPLING
return os[0];
}
Re: Oversampling in VMD
os is an array that keeps track of all oversampled values. initially it is filled with 0s (from initializing). the first index is set to the input value from the parameter list.ColinP wrote: ↑Wed Jan 11, 2023 7:28 pm Hi Chris,
Very nice of you to post this but I'm struggling to understand the working of the main process() method.
I'm a little worn out (coping with flooding) so might be missing something blindingly obvious but I don't understand how information flows in the loop. How is os[ 0 ] at the end of the method affected by anything going on in the zero-stuffed parts of the array?Code: Select all
public double process( double value, R_IOversampledProcessor processor ) { double[] os = new double[m_osFactor]; os[0] = value; // first value is valid, others are zero-stuffed //////// OVERSAMPLING for( int i = 0; i < m_osFactor; ++i ) { os[i] = m_upSampler.process( os[i] ); os[i] = processor.process( m_osFactor * os[i] ); os[i] = m_downSampler.process( os[i] ); } //////// OVERSAMPLING return os[0]; }
so the array now consists of the actual input and lots of 0 for the zero stuffing. each array element, the actual value and the stuffing 0s, are then put into the upsampler to produce the actual sampling values to feed into the processing function. the array os keeps track of these values.
after processing the whole array needs to be put through the downsampler one by one. the first array element now holds the actual value. we can discard all other values that resulted from the zero stuffing. these are only needed for the up- and down-sampling filters.
so for 2x oversampling it would look like this
Code: Select all
os[0] = value
os[1] = 0
os[0] = m_upSampler.process( os[0] );
os[0] = processor.process( m_osFactor * os[0] );
os[0] = m_downSampler.process( os[0] );
os[1] = m_upSampler.process( os[1] );
os[1] = processor.process( m_osFactor * os[1] );
os[1] = m_downSampler.process( os[1] );
value = os[0];
The zero stuffing is needed for the upsampling and downsampling filters. filters have 'memory'. you are basically tricking the filter into thinking it runs at a higher sample rate. and to accommodate for that you need to feed it more values to get back to the actual frequency. e.g. 20kHz at 48kHz sampling rate are now 40kHz at 96kHz sampling rate. by putting twice the values through you get back to 20kHz. adding 0s reflects the whole spectrum at nyquist. the filter is then removing that part alongside any frequency that would have reflected anyways.
hope this helps!
Re: Oversampling in VMD
Thanks Chris.
I agree that what the code is doing (with m_osFactor = 2) is the following...
But isn't this equivalent to...
What I don't understand is how anything in os[ 1 ] impacts on os[ 0 ].
I agree that what the code is doing (with m_osFactor = 2) is the following...
Code: Select all
os[0] = value
os[1] = 0
os[0] = m_upSampler.process( os[0] );
os[0] = processor.process( m_osFactor * os[0] );
os[0] = m_downSampler.process( os[0] );
os[1] = m_upSampler.process( os[1] );
os[1] = processor.process( m_osFactor * os[1] );
os[1] = m_downSampler.process( os[1] );
value = os[0];
Code: Select all
return m_downSampler.process( processor.process( m_osFactor * m_upSampler.process( value ) ) );
Re: Oversampling in VMD
Think of the filters as interpolators. the upsampler turns 1 sample into X samples and the downsampler turns X samples into 1 sample with X being the oversampling factor.
so picture this at 48kHz samplerate your samples look like this:
you get a value for every sample (V represents a sample here).
when you want to oversample 2x you need 2 samples for every sample you had at 48kHz:
what value does the x have? it's literally 0. between the sampling points there are no values. so that's what we're giving the upsampling filter to work with. you can think of a lowpass filter like an interpolating filter. it smooths out the values you put in. and if you feed a succession of values and 0s it will turn these 0s into in-between-values.
in theory you can use any interpolator to get the in-between values. but since we need to filter the frequencies above the nyquist frequency anyway we can use the IIR filter to do the upsampling and the filtering in one go.
so picture this at 48kHz samplerate your samples look like this:
Code: Select all
V V V V V V V V ...
when you want to oversample 2x you need 2 samples for every sample you had at 48kHz:
Code: Select all
VxVxVxVxVxVxVxVx...
in theory you can use any interpolator to get the in-between values. but since we need to filter the frequencies above the nyquist frequency anyway we can use the IIR filter to do the upsampling and the filtering in one go.
Re: Oversampling in VMD
I figured out eventually that the information flows via the state of the m_biquadCoeffs array inside the filters.
Re: Oversampling in VMD
Can't thank you enough for this, Chris. It's exactly what I've been seeking for quite some time, now. What a fantastic, generous gesture.
I'm currently investigating how it can be retrofitted to some of the non-linear Dome Music Technologies audio modules. Of course, any modifications I make to the core library will be shared with the community in the same spirit as the original.
I'm currently investigating how it can be retrofitted to some of the non-linear Dome Music Technologies audio modules. Of course, any modifications I make to the core library will be shared with the community in the same spirit as the original.
______________________
Dome Music Technologies
Dome Music Technologies
Re: Oversampling in VMD
that's what i meant by filter 'memory'. each biquad in the stack remembers two states. these are processed past values.
to elaborate on why this works as an interpolator:
the perfect lowpass filter has an infinitely steep cutoff. in the frequency domain this is represented as a box. translating this box into the time domain results in a sinc impulse. the sinc impulse catches each sample perfectly and 'ripples' in-between the sample points. if you overlay each sample with a sinc you get a theoretical perfect reproduction of the signal. but implementing perfect sincs is not possible as they ring out infinitely. so we need to window them. that's a tradeoff to make it work. the result is ripple in the frequency response and less steepness (depending on the type of window you chose). yet it is still a lowpass. my FIR oversampling filters use windowed sincs, but in practice any lowpass works (with varying quality). the steeper the cutoff the better ofc. that's why the stacked resonance lowpasses i use in R_OpenLib work quite well. in comparison to their FIR counterparts they are not linear-phase, but therefor a lot cheaper to compute. everything has its ups and downs.