Tutorial: BLEPs (using PolyBLEPs but extensible)

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

matt42 wrote: Thu Jul 23, 2020 4:42 pm Combine your residuals with a step function and you should notice that the linear version has much more visually obvious discontinuities. I haven't checked the spectra, but I'd guess it will alias a lot more. https://www.desmos.com/calculator/t1dguzczh7
Compared "LinearBLEP" version against PolyBLEP implementation found on Shadertoy :
PolyBLEP https://streamable.com/hbcc71
LinearBLEP https://streamable.com/pxobsh

but, actually, dunno what all happens there so (even it sounds OK to my ears but) by linked videos I can't be sure if linear version is good or bad ... .
Last edited by juha_p on Thu Jul 23, 2020 8:50 pm, edited 1 time in total.

Post

cjohs wrote: Thu Jul 23, 2020 6:49 pmExactly - I think we actually agree just using different terminology :wink:
yes the t input to the polyBlep function yields the graph I plotted above and is the subsample position of the discontinuity ...
BLEP stands for a band limited step, but your function looks like just the first half of such a step. I think you need to invert and mirror that for the second half of the function:
https://www.desmos.com/calculator/ekxhqqwf1a
You align x=1 with the discontinuity. And the whole thing covers a length of 2 samples
Last edited by matt42 on Thu Jul 23, 2020 9:02 pm, edited 1 time in total.

Post

juha_p wrote: Thu Jul 23, 2020 7:43 pmI can't be sure if linear version is good or bad ... .
Sharp discontinuities in the wave form will yield infinite harmonics, so I'm not sure the linear version will work so well

Post

Obviously a cosine-like edge will produce the fewest harmonics (1), such as a Hann window or Kaiser-Bessel or Dolph-Chebyshev. There are trade-offs between slope and main lobe width as we attempt to "fade" the discontinuity due to the sine being single cycle rather than continuous.

A linear edge will always give a first order falloff. We're starting with a zero-order edge at 1/N amplitude and linear will only give 1/N^2, a mere doubling in slope. A quadratic (parabola) will give 1/N^3. Sums of cosines will give much more extreme slopes.

Regardless of slope there are always infinite harmonics with any discontinuity. Ultimately you'll end up with a unit impulse (wrong terminology, ?) at some level of Nth derivation.
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: Fri Jul 24, 2020 5:42 pm Regardless of slope there are always infinite harmonics with any discontinuity. Ultimately you'll end up with a unit impulse (wrong terminology, ?) at some level of Nth derivation.
Sure, I guess my description above is a bit loose. Polyblep type solutions are always only psudo-band limited. Terms like infinite harmonics aren't so informative as depending on their level and the noise floor they will become pretty irrelevant as they roll off. Still my hunch is it won't be worth the quality/efficiency trade off to use the linear residual. I could easily be wrong though.

Post

matt42 wrote: Thu Jul 23, 2020 8:03 pm BLEP stands for a band limited step, but your function looks like just the first half of such a step. I think you need to invert and mirror that for the second half of the function:
https://www.desmos.com/calculator/ekxhqqwf1a
You align x=1 with the discontinuity. And the whole thing covers a length of 2 samples
Hmmm
In mystran's example code (not mine) he does use 2 steps, and for the second step the correction is
poly3Blep1 = -poly3blep0(1-t) (which is somewhat similar to the second half of your example ( x between 1 and 2)
polyblep0 and 1.png
But he still claims that t (on the x-axis) is the phase.
And I still cannot agree with centering the discontinuity on x=1 in your graph, that would result in always making the correction with a constant value = 0.5 for sample 1?
You do not have the required permissions to view the files attached to this post.
------------
also known as Ambient Lifeforms and Orbital Resonance
http://www.ambientlifeforms.dk/

Post

matt42 wrote: Fri Jul 24, 2020 6:35 pm Still my hunch is it won't be worth the quality/efficiency trade off to use the linear residual. I could easily be wrong though.
I think that's almost certain as it's difficult (impossible?) to go any lower than 1st order without 0th order or something far more expensive. So the linear (1st order) would be the foundational "do something" level with the only practical alternative being naive "do nothing".

It may be difficult to find high-order solutions that don't end up eliminating any potential benefit... but something like a quadratic is probably near the best. There is definitely a point where the added computational cost makes the method fail to compete with other methods at any further quality.
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

cjohs wrote: Fri Jul 24, 2020 7:39 pm And I still cannot agree with centering the discontinuity on x=1 in your graph, that would result in always making the correction with a constant value = 0.5 for sample 1?
Not sure what you mean by sample 1. If you mean the fist sample of the wave form then that would depend on the initial phase. Anyway a square wave is essentially a series of steps, so instead of an instantaneous step from -1 to 1, as in a naive digital square, polyblep uses a smooth transition over a couple of samples. A discontinuity could occur at any point and will often be in a sub sample position, so x=1 on the graph will be positioned at these sub sample positions

Post

matt42 wrote: Fri Jul 24, 2020 8:27 pm
cjohs wrote: Fri Jul 24, 2020 7:39 pm And I still cannot agree with centering the discontinuity on x=1 in your graph, that would result in always making the correction with a constant value = 0.5 for sample 1?
Not sure what you mean by sample 1. If you mean the fist sample of the wave form then that would depend on the initial phase. Anyway a square wave is essentially a series of steps, so instead of an instantaneous step from -1 to 1, as in a naive digital square, polyblep uses a smooth transition over a couple of samples. A discontinuity could occur at any point and will often be in a sub sample position, so x=1 on the graph will be positioned at these sub sample positions
By sample 1 I mean the first sample of the 2-sample correction region.
So if you center the polynomial on the discontinuity the correction value for the first sample-to-be-corrected will be 0.5 and the correction value for the second sample-to-be-corrected will be... what?
Maybe you are confusing this with a BLep using lookup tables which bleps over longer regions?
If you choose to center the polynomial exactly in-between the two samples to be corrected, then my question becomes how do I find the correction value? - and again I return to the tutorial example here which as the only parameter, for finding the correction value using mystrans polyblep, takes t - the phase (or sample position of the discontinuity in the wavetable scaled to be between 0 and 1)).
Maybe the way you think about this is too different from the way mystran has implemented it in this tutorial, or you disagree with his implementation?
------------
also known as Ambient Lifeforms and Orbital Resonance
http://www.ambientlifeforms.dk/

Post

cjohs wrote: Sat Jul 25, 2020 10:10 amBy sample 1 I mean the first sample of the 2-sample correction region.
So if you center the polynomial on the discontinuity the correction value for the first sample-to-be-corrected will be 0.5 and the correction value for the second sample-to-be-corrected will be... what?
Why would it be 0.5? The only way that would happen is if the discontinuity happens to fall exactly on the first sample. Or if the discontinuity was exactly centered between the two samples then the first sample would align with x = 0.5, which would give a value of approximately 0.094. Typically these values are used to calculate the residual, which needs to be correctly scaled, which is what you actually use as the correction function.
cjohs wrote: Sat Jul 25, 2020 10:10 amMaybe the way you think about this is too different from the way mystran has implemented it in this tutorial, or you disagree with his implementation?
As mentioned I haven't really looked in detail into mystrans implementation, which I would guess will be correct. I was just trying to explain the basics of polyblep theory, because when you described the polyblep covering the whole waveform it was clear you had a misunderstanding. Perhaps a forum post isn't the best medium to explain it and mixing the basics of the theory into a discussion on a specific implementation may be confusing.

Post

As known, the Polynomial Bandlimited Step (PolyBLEP) methodology involves approximating the sinc() function with a polynomial. The most basic polynomial to choose is a uni-polar triangular pulse as it is the linear approximation of the windowed sinc() pulse. Integrating it produces the bipolar integrated triangle which can be expressed as:
formula1.png
The PolyBLEP two part residual is then obtained by subtracting the perfect step from the bipolar integrated triangle and converting again to bipolar.
residual1.png
(Two part residual)

Residual is then applied to the naive wave shape to offset the samples around the discontinuities, shifting them up or down to producing a smoothed waveform.

BTW, how are those polynomials and two part residual actually, step-by-step, derived?

I noticed that similar response (in range [-1,1]) two part residual, as described above, can be expressed directly through those triangles:

Code: Select all

v1=abs(x)-1.0;
v2=-abs(x)+1.0;
h=(v1*v2)*sgn(x)
which results two part residual as:

Code: Select all

-((|t|-1.0)(-|t|+1.0))
((|t|-1.0)(-|t|+1.0))
desmos11.png
(Two part residual)

So, correction function to be used in implementation found at shadertoy:pblep() would then be:

Code: Select all

float pblep(in float t, in float dt)
{
    if( t<dt){ 
    	t=t/dt;
    	return (abs(t)-1.0)*(-abs(t)+1.0);    // return t+t-t*t-1.0 
    	}
    else if( t>1.0-dt ) { 
    	t=(t-1.0)/dt; 
    	return -(abs(t)-1.0)*(-abs(t)+1.0);  // return t*t+t+t+1.0; 
    	}
    return 0.0;
}
Comparison between "original" and introduced residual @ https://www.desmos.com/calculator/xwqyghn8pb

BTW, is that difference in curves (meaning how it goes at outside ±1's) somehow meaningful?
You do not have the required permissions to view the files attached to this post.
Last edited by juha_p on Tue Jul 28, 2020 6:42 am, edited 5 times in total.

Post

Edit

Post

Sorry to bump an old old thread, but I have to say thank you to Mystran for this. I use this technique in all sorts, including in a profoundly terrible Arduino "VCDO" using crazy tricks with pointers and precalculated lookup tables.

Post Reply

Return to “DSP and Plugin Development”