Tutorial: BLEPs (using PolyBLEPs but extensible)

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Marvinh wrote: Sun Jan 11, 2026 6:37 pm Oh it’s about this step in general

“Build C1 continuous impulse from two cubic "smooth steps" which on their own looks like p(t)=3*t^2-2*t^3”

In reference to higher order bleeps I was interested in how the formulas were made so I looked up “continuous steps” and saw there were higher orders of the original function in the first post by mystran .

They use S instead C in the higher order formulas

Question being do we need longer delays for higher orders ?
Higher order BLEPs (eg. for anti-aliasing more derivatives) and higher order functions for the kernel are two different things. For the kernel (as an impulse) itself we mostly just want something that has reasonably flat spectrum up to Nyquist and then ideally decays as far as possible past that. There are pictures of the spectra of the "piece-wise linear" vs. "cubic smoothsteps" kernels somewhere around page 2 in this thread; going higher order is not useful without increasing the length of the kernel... but it's really any "band-limited impulse" that you can come up (windowed sinc works fine if you don't mind long tabulated kernels).

Once you have an impulse, you integrate. If your impulse is define piecewise, just integrate the pieces and choose the integration constants such that they line up. For anti-aliasing first derivative, you integrate a second time, for anti-aliasing 2nd integral you integrate a third time and so on.

The complication here is that for every additional integral it becomes more complicated to choose a kernel that actually allows the Nth integral to correctly line up with the naive function (and also all the previous one). Step and ramp aren't much of an issue, but beyond that things start to become increasingly complicated and I don't have very good solutions to be honest.

Post

Thanks for clearing that up!. I think my issue was understanding span and residual. The original post is a 2 sample span. with the function

-polyblep(1-t)

as the second residual.

the integral is the first residual.

more span = more delay more having to compute residuals instead.

Post

Marvinh wrote: Mon Jan 12, 2026 1:38 am Thanks for clearing that up!. I think my issue was understanding span and residual. The original post is a 2 sample span. with the function

-polyblep(1-t)

as the second residual.

the integral is the first residual.

more span = more delay more having to compute residuals instead.
Usually "residue" refers to the difference between the band-limited step (or one-sided ramp, etc) and the naive waveform. The residue spans multiple samples and the polyblep() function is used to compute those samples. However, there is symmetry in the residue (for a linear-phase BLEP such as this) such that the second half is the same as the first half, just time-reversed and inverted in polarity... so we can just have a function for the first half and then use this symmetry to compute the second half.

Post

mystran wrote:Usually "residue" refers to the difference between the band-limited step (or one-sided ramp, etc) and the naive waveform.
I'm wondering, why is the BLEP residue/residual never called highpass filtered step? That's what it actually is. Would make things a lot easier to grasp.
Marvinh wrote:more span = more delay
You can have a BLEP oscillator without delay. Phase is all you need for that. Smoothstep function S5 sounds good to me (length 6, SR 88.2 kHz).

Post

odibo wrote: Fri Jan 16, 2026 1:13 am
mystran wrote:Usually "residue" refers to the difference between the band-limited step (or one-sided ramp, etc) and the naive waveform.
I'm wondering, why is the BLEP residue/residual never called highpass filtered step? That's what it actually is. Would make things a lot easier to grasp.
You're not the first one to make the observation... although I think you need to be careful, because it's really the lowpass response that we need, the lowpass response that we're trying to optimize and the "highpass" response of the residue is only useful as far as it partially cancels the spectrum of the naive waveform in order to give us a lowpass response.. frankly dealing with lowpass filters is much easier (especially as we're doing things in "continuous" time) as you don't need to concern yourself with Dirac deltas.

Post

Sloppy wording on my end. Let me rephrase:

I'm wondering, why is the BLEP residue/residual never called continuous time highpass filtered step, sampled with the same discrete time, with which the non band-limited feature waveform was sampled?

The way a BLEP residue is typically designed makes my wondering, maybe, clearer (details left out for brevity):

- design a band-limited impulse
- integrate
- subtract the step
- resulting in residue = lowpass(step) - allpass(step)

which is equivalent to:

- design a FIR lowpass kernel
- make it highpass by spectral inversion
- convolve with the step

There's our highpass filtered step - unless I missed something, which is perfectly possible.

Post

odibo wrote: Sat Jan 17, 2026 11:54 pm which is equivalent to:

- design a FIR lowpass kernel
- make it highpass by spectral inversion
- convolve with the step

There's our highpass filtered step - unless I missed something, which is perfectly possible.
You're basically neglecting two things: sampling and integration.

If we have an analytical kernel (such as PolyBLEP) and we're integrating and evaluating analytically then it doesn't really matter... but if we were to use a sampled filter (such a windowed sinc) then sufficiently high oversampling factor, perhaps combined with interpolation is a decent approximation of a lowpass filter... but it's not a good approximation of a highpass filter due to the pesky Dirac-delta and aliasing and all that.

When we then numerically integrate, it works fairly well if we have a lowpass filter, because numerical integration works well on low frequencies... but if you try to do this with a highpass filter (which we can't even properly sample in the first place), then the results probably won't be very useful. In fact, it turns out that for correct results, if you want to interpolate the result, you need to do this (conceptually at least) before you subtract the naive waveform, because you can't interpolate across the discontinuity (in waveform or it's derivatives) correctly.

So really in the general case (not just kernels that we can handle analytically), you MUST treat it as a lowpass filter in terms of implementation.

Post

Oh, now I see your concern. Thank you for the detailed explanation.
mystran wrote:but it's not a good approximation of a highpass filter due to the pesky Dirac-delta and aliasing and all that.
You are right. A single Dirac delta would be pesky. But if you bring many of them to the BLEP party, you will notice that it's a quite likeable little fellow.

I think we're not on the same page. With "kernel" you are referring to an oversampled kernel, while i had a single branch of it in mind. With a BLEP length of 8 the kernel would be 9 for instance. Maybe my "recipe" makes now more sense?

Post

odibo wrote: Mon Jan 19, 2026 12:47 am I think we're not on the same page. With "kernel" you are referring to an oversampled kernel, while i had a single branch of it in mind. With a BLEP length of 8 the kernel would be 9 for instance. Maybe my "recipe" makes now more sense?
Actually when I'm thinking about a "BLEP kernel" I'm thinking about a continuous-time function that we're trying to approximate. The whole BLEP technique in essence is about a practical method to filter the signal (conceptually) before it is sampled... so it's not really a digital filter, it's a an approximation of a continuous-time filter.

In practice, if you design a regular polyphase lowpass kernel with enough branches, you can then interpolate it to approximate a continuous kernel (or equivalently a polyphase kernel with infinite number of branches). If you integrate such an approximation, that's fine, numerical integration works fine at low frequencies (relative to the sampling rate of the approximation which is high, because we used lots of branches).

ps. Having a polyphase filter with lots of branches is actually not really even sufficient to get good results.. you really need it to approximate a continuous-time kernel, or things will not work well.

Post

odibo wrote: Fri Jan 16, 2026 1:13 am
mystran wrote:Usually "residue" refers to the difference between the band-limited step (or one-sided ramp, etc) and the naive waveform.
I'm wondering, why is the BLEP residue/residual never called highpass filtered step? That's what it actually is. Would make things a lot easier to grasp.
Marvinh wrote:more span = more delay
You can have a BLEP oscillator without delay. Phase is all you need for that. Smoothstep function S5 sounds good to me (length 6, SR 88.2 kHz).

Interesting I think the original was for minbleps as well. The other example I’ve seen was in the PolyBLAMP paper which had delays .

For delayless polybleps say span 4 we would do

if (phase + 3*phaseIncrement >= 1) then (add first equation) and so on

Post

Marvinh wrote:For delayless polybleps say span 4 we would do

if (phase + 3*phaseIncrement >= 1) then (add first equation) and so on
Well, basically yes, but actually no. Here is some code for demonstration:

Code: Select all

// phase in [-1,1], phaseInc in ]0,1], cutoff 1.0 nominal

float getSawtoothSample (float phase, float phaseInc, float cutoff)
{
   float m = max (0.5f, (cutoff * (2.f/NSL)) / phaseInc);
   float y = phase - getResidue ( max (0.f, ((phase - 1.f) *  m + 1.f)) );
   return y        + getResidue ( max (0.f, ((phase + 1.f) * -m + 1.f)) );
}

Code: Select all

#define NSL   6.87f	// nominal step length for the polynomial below

// input x in [0,1], output in [0,1]

float getResidue (float x)
{
   float y = x * (0.446f + x * (1.234312f - 0.680312f * x));
   return y*y*y;
}
Some notes:

The BLEP polynomial is suited for 88.2/96 kHz sample rates and needs some simple post-filtering (a boost at Nyquist/2). The cutoff parameter controls the BLEP cutoff, i.e. oscillator bandwidth.

Post

...In practice, if you design a regular polyphase lowpass kernel with enough branches, you can then interpolate it to approximate a continuous kernel (or equivalently a polyphase kernel with infinite number of branches)...
Things would become more easy and fast if there we would have a closed form formula for a minimum phase lowpass kernel. Is there something like this? I still haven't found anything.
https://www.tone2.com
Our award-winning synthesizers offer true high-end sound quality.

Post

Tone2 Synthesizers wrote: Thu Feb 05, 2026 7:15 am
...In practice, if you design a regular polyphase lowpass kernel with enough branches, you can then interpolate it to approximate a continuous kernel (or equivalently a polyphase kernel with infinite number of branches)...
Things would become more easy and fast if there we would have a closed form formula for a minimum phase lowpass kernel. Is there something like this? I still haven't found anything.
If we're talking about lowpass, then sure. Design a continuous-time lowpass as a rational function in s (as you would normally do) then take the inverse Laplace transform symbolically (made much easier when you already know the poles from the design phase) to get the impulse response; it'll be a bunch of decaying exponentials.

As far as true brickwall, (as far as I can see) you can't really have a causal one no matter what (uncertainty principle and all that).
Last edited by mystran on Thu Feb 05, 2026 9:17 am, edited 1 time in total.

Post

With 'closed form' i am meaning somthing that is easy and fast to compute in realtime.
Something that looks similar like
Sin(x * a) * exp(-x * b)
https://www.tone2.com
Our award-winning synthesizers offer true high-end sound quality.

Post

Tone2 Synthesizers wrote: Thu Feb 05, 2026 9:15 am Something that looks similar like
Sin(x * a) * exp(-x * b)
What @mystran suggests is pretty close, since you can compute it as the sum of a few exp(-x*b[k]).

Post Reply

Return to “DSP and Plugin Development”