Page 3 of 6
Re: oversampling?
Posted: Sat Dec 16, 2023 9:26 pm
by utdgrant
Ah, there were quite a few insightful messages posted between my replies. Excellent food for thought, guys!
Re: oversampling?
Posted: Sun Dec 17, 2023 3:41 am
by UrbanCyborg
In light of Chris' announcement, I have to retract what I said earlier about his open library not containing his polyphase FIR code, because now, it does!
In regard to latency issues, yes, that is one of the big trade-offs with FIRs, but I don't think it's an insuperable obstacle, because you can always delay other components to match the up- and down-sampling latency. Martin even has a pair of modules to do that:
https://store.cherryaudio.com/modules/sample-delay
https://store.cherryaudio.com/modules/poly-sample-delay
Of course, there will always be patches where
any latency is unacceptable, but most of the time that doesn't happen, I think.
Another point is that the amount of latency depends, at least partially, on the size of the filter's sample window; bigger window, better quality, but longer latency. Make it long enough, and you start to emulate an IIR, anyway (ignoring pole/zero placement and filter topology). When I gave my earlier brief response, I was, of course, simplifying things in the interests of avoiding lecture mode (and having taught at University, I can really extend a lecture
). I didn't think anyone wanted me to deliver a lecture on McClellan-Parks optimal linear-phase filter design. Besides, I think Chris probably has a better understanding of it than I do, anyway. Way to go, Chris!
Reid
Re: oversampling?
Posted: Sun Dec 17, 2023 11:55 am
by ColinP
Being a generalist I have a little bit of knowledge about a lot of things so am often wrong. But I enjoy learning so discussions like this are really useful.
So I'll run through my thought processes as to why I think fractional access to a buffer using lerping should not be considered as performing low-pass filtering and also why I believe it can introduce aliasing.
First let's be clear about what we mean by linear interpolation or lerping as it's known in slang, at least by games programmers.
Lerping is a simple blending function that is normally implemented as A + ( B - A ) * f although in a perhaps "purer" form A * ( 1 - f ) + B * f.
Where A and B are simple values or tuples and f is a blending factor in the range [0, 1] although often [0, 1).
Informally it can be thought of as a straight-line cross-fade between two values A and B. The result is A when f is 0 , B when f is 1 and at various linear intermediate points otherwise.
Now context. I'm looking at this in the context of my granular synth. At the core of this is a model of a length of magnetic tape with hundreds of flying playback heads that can move along the tape while magically never colliding.
Each playback head corresponds to a grain and its velocity is a function of the grain's pitch parameter, its direction a function of the sign of the grain's size parameter and its starting position on the tape a function of the grain's offset parameter.
While the tape is represented by a buffer of discrete sample values the position of each playback head is not restricted to integer indices in the buffer. So we have a floating point position which can be split into an integer and a fractional part. The integer part indexes the base sample while the fractional part is used as f in a lerp from the base sample to the next sample in the buffer.
However, it's important to always remember that the lerping is just a crude approximation. I'll return to this shortly.
On the question of low-pass filtering - because A is buffer[ floor( position ) ] and B is buffer[ floor( position ) + 1 ) it's tempting to think of the system as a crude FIR low-pass filter but I think this is a bizarre way to look at it as the coefficients change depending on the value of f and if f is 0 or 1 then the output is identical to the raw sample values. So unless one considers that lerping isn't really lerping if f = 0 or f = 1 then how is the system functioning as a low-pass filter? From a system POV there's nothing peculiar about integer positions along the tape, sometimes the positions will have fractional parts sometimes they won't.
So a simpler way to think about what's happening is that we are just cross-fading between sample values rather than doing any low-pass filtering. There isn't any alteration of the frequency response when the positions have integer values and an outside observer would not be able to tell whether the positions were integer or fractional (ignoring the errors that I think cause aliasing).
Moving on to how I think aliasing can occur. Let's imagine the buffer contains a low-frequency sinewave. Here the bandlimited change between samples is pretty much a straight line and lerping does an excellent job of approximating intermediate values. A fractional position will result in a lerped sample value that is almost identical to the bandlimited analog signal at that position.
But as we increase the frequency of the sine wave the linear approximation becomes less and less accurate. As we approach Nyqist then a bandlimited sample at some intermediate position between the two buffer samples may well be impossible to return using lerping because that value is outside the range A to B. So the lerping produces an imaginary sample that can't possibly represent the correct value. In other words the result is no longer bandlimited and aliasing may occur.
No doubt I've stumbled at some point in this train of thought but at the moment I don't see where.
Re: oversampling?
Posted: Sun Dec 17, 2023 5:26 pm
by utdgrant
ColinP wrote: ↑Sun Dec 17, 2023 11:55 am
So unless one considers that lerping isn't really lerping if f = 0 or f = 1 then how is the system functioning as a low-pass filter?
Short answer:
It isn't lerping if f==0.0 or f==1.0. There will be no low-pass filtering.
If 0.0 < f < 1.0, there will be a degree of low-pass filtering, with worst case being experienced at f==0.5. The low-pass response is not a typical dB/oct curve, though. It dips asymptotically towards -inf dB as you approach Nyquist.
Re: oversampling?
Posted: Sun Dec 17, 2023 6:54 pm
by utdgrant
Two things occured to me as I was eating my evening meal:
1. Comb Filtering, not Classic Low-Pass
When f==0.5, you're effectively getting a comb filter response, with a single notch. This notch is situated
exactly at the Nyquist frequency. This explains the non-standard 'low-pass' curve.
- FractionalDelayRollOff.jpg (43.62 KiB) Viewed 57436 times
Now, as f tends towards 0.0 or 1.0, that notch quickly becomes less (EDIT:
more) shallow, until the entire frequency response becomes flat again at the f==0.0 or f==1.0 values.
A consequence of this is that if you vary f in real-time, you will get amplitude modulation of higher frequencies (Starting around 10 kHz, becoming more extreme as you approach 24 kHz). Fortunately, all my fractional-delay modules use LFOs to change the delay length, so the rate of AM shouldn't be too noticeable, especially when combined with the inate (desired) comb-filtering effects of chorus/ensemble.
The one exception to this rule (for my modules, at least) is when you drive Zeit with a
Time-Stream Integrator to perform pitch-shifting. In that application, f can be different from one replay sample to the next, causing potential audio-frequency AM distortion.
2. Variable-Rate Sample Replay Does Not Employ Fixed Values of f
In the case of playing back a sample buffer at different pitches, the buffer index increment will almost always be some non-integer amount (unless replaying at exactly the recording pitch). This means that f will have a different value on every single replayed sample, and the comb filter response will also fluctuate from sample-to-sample. Audio-frequency AM will almost certainly lead to aliasing! Even if you don't generate 'virtual' frequencies above the Nyquist frequency, there is still a strong possibility of producing unwanted, inharmonic sidebands within the audible range.
The big takeaway is that Lerping is generally 'good enough' when used for fixed (or slowly-varying) fractional delays. However, once you get into pitch-shifting (via naive resampling), you can expect some unwanted artifacts to appear in your output. Whether these artifacts are acceptable or not is a decision that can be made after thorough testing.
Re: oversampling?
Posted: Sun Dec 17, 2023 10:48 pm
by ColinP
utdgrant wrote: ↑Sun Dec 17, 2023 5:26 pm
Short answer:
It isn't lerping if f==0.0 or f==1.0. There will be no low-pass filtering.
So at least we agree that there is definitely no possibility of low-pass filtering when f = 0 or f = 1.
This special pleading that lerping is somehow not lerping when f = 0 or f = 1 was why I wanted to set out exactly what lerping was before continuing with my argument.
Would you argue that x * y isn't multiplication if either x or y are 1 and x + y isn't addition if either x or y are 0?
I think you will struggle to find any mathematician that defines multiplication or addition or indeed lerping that way.
Re: oversampling?
Posted: Sun Dec 17, 2023 11:29 pm
by ColinP
I think that the whole lerped bufffer access = filtering paradigm is problematic. You can look at it through that lens but it's not a particularly useful way of thinking about something that is actually quite simple. Although if you are looking at this from the POV of something like chorus effects then the filtering perspective is an obvious starting point.
As I said previously there's nothing peculiar about f = 0 or f = 1. In GS we are actually looking at [0, 1) rather than [0, 1] so 1 never occurs. But f = 0 pops up frequenty when there is no pitch shifting or we are doing octave shifts.
I think focusing on modulation is a distraction too. In granular synthesis each grain's parameters are static post seeding, yet I still believe aliasing can occur using lerped buffer access for the reason previously stated.
I am of course playing devil's advocate here. I'm criticizing my own work but I agree lerping is a "good enough" approximation so I am not too concerned. Just as a matter of opinion, as I have stated before, I think aliasing and oversampling are things that techies obsess about but the average listener couldn't give a damn about such minor things. I think in the context of a real-world mix almost nobody can hear moderate aliasing. But that's just my opinion and I respect that other people may take a very different view.
Re: oversampling?
Posted: Mon Dec 18, 2023 1:04 am
by utdgrant
I think we're in total(*) agreement, actually.
I've proved to myself that replaying a buffer with non-integer increments can indeed lead to aliasing when using simple Lerping. This is because f will jump around as the playback head increments through the buffer.
I've also proved to myself that if you have a fixed-length fractional delay, then you will get a fixed comb filter response, with the intensity of the notch being based on the value of f. If f is 0, the notch is non-existent, and the original signal is passed through, unfiltered. If f is 0.5, the notch extends down to - inf dB at the Nyquist frequency, with the tail extending back to around 10kHz before becoming insignificant.
* We might have a semantic / philosophical disagreement over whether the fixed, known points at each end of a straight line (f=0) have special significance over the Lerped approximations in between (0 < f < 1).
Re: oversampling?
Posted: Mon Dec 18, 2023 9:56 am
by ColinP
Cheers Grant, it's nice to arrive at some argreement.
And yes one should be aware that f jumps around even when doing something simple like a semitone pitch rise with no modulation whatsoever...
Code: Select all
d = 12th root of 2
repeat
{
index = floor( headPosition )
f = headPosition - index
lerp
headPosition += d
}
So in this instance the frequency response changes sample by sample. It's not what most people would call filtering.
But I don't think that's the cause of aliasing (at least not directly). The problem to me is the inability of lerping to produce bandlimited fractional samples as we approach Nyqist because the linear approximation becomes increasingly inaccurate.
Re: oversampling?
Posted: Mon Dec 18, 2023 2:06 pm
by ColinP
Most of my thought experiments are in the visual domain so I've done a quick scribble to better show what I've been talking about.
This is close to Nyquist with f = 0.5.
A and B are two adjacent samples in the buffer. The curve represents the bandlimited analog signal that would be constructed without any interpolation.
Q is the desired bandlimited interpolated sample value for half way between A and B.
L is the result of lerping between A and B and is obviously not bandlimited.
The dotted line shows the error.
- lerp.png (255.51 KiB) Viewed 57281 times