I have recently gotten back into Pure Data in the interest of familiarizing myself more with it, and perhaps to integrate it with Unity for a future project. For anyone who may not be familiar with it, more info on it can be found here. It’s a great environment for building synthesizers and experiment with a great variety of audio processing techniques in a modular, graphically-based way.

Oscillators are the foundation of synthesizers of course, and Pure Data comes with two modules that serve this purpose: osc~ for sine waves, and phasor~ for a sawtooth (it’s actually just a rectified ramp in the range 0 – 1, so it needs a couple of minor additions to turn it into a sawtooth wave). However, the phasor~ module (not being band-limited) suffers from aliasing noise. This can be avoided either by passing it through an anti-aliasing filter, or by using the sinesum message to construct a sawtooth wave according to the Fourier Theorem of summing together sine waves (i.e. creating a wavetable). Both of these methods have some drawbacks though.

A robust anti-aliasing filter is often computationally expensive, whereas wavetables sacrifice the quality of the waveform and are not truly band-limited across its entire range (unless the wavetable is divided into sections constructed with decreasing number of harmonics as the frequency increases). A wavetable sawtooth typically lacks richness and depth due to the lack of harmonics in its lower range. These issues can be fixed by constructing the sawtooth using band-limited steps (BLEPs), which are based on band-limited impulse trains (BLITs), at the expense of some increased complexity in the algorithm. And fortunately, Pure Data allows for custom modules to be built, written in C, that can then be used in any patches just like a normal module.

The process behind this method is to construct a naive sawtooth wave using the equation

*sample = (2 * (f / SR * t)) – 1*

where *f* is frequency (Hz), *SR* is sample rate (Hz), and *t* is a time constant (in this case, the sample count). At the waveform’s discontinuities, we insert a PolyBLEP to round the sharp corners, which is calculated by a low order polynomial equation (hence, “Poly”nomial Band-Limited Step). The polynomial equation is of the form

*x ^{2} + 2x + 1*

The equation for the PolyBLEP is based on the discussion of the topic on this KVR forum thread. The concensus in the thread is that the PolyBLEP is far superior to using wavetables, but sounds slightly duller than using minBLEPs (which are far more complicated still, and require precalculation of the BLEP using FFT before integrating with the naive waveform). PolyBLEP oscillators strike a good balance between high quality, minimal aliasing noise, and reasonable complexity.

Here is a quick sample of the PolyBLEP sawtooth recorded from Pure Data. Of course, PolyBLEPs can be used with other waveforms as well, including triangle and square waves, but the sawtooth is a popular choice for synths due to it’s rich sound.

The GitHub page can be found here, with projects for Mac (Xcode 5) and Windows (Visual Studio 2010).

kernelbobActually, for a triangle, a polyBLEP won’t work directly. The polyBLEP corrects for a discontinuous change in amplitude. A triangle is continuous, but its first derivative is discontinuous. PolyBLAM is the correction to use (polynomial approximation to Bandwidth-Limited rAMp).

I just implemented polyBLEP and polyBLAM in my synth (not yet published) this weekend. I found lots of info for polyBLEP, but had to derive the polyBLAM polynomials myself.

Here is the first order polyBLAM.

polyBLAM(d, h) =

h * d**4 / 6 for the sample before the corner,

h * (1-d)**4 / 6 for the sample after.

d is the fractional time of the triangle’s corner. d = T[previous sample] – T[corner]

h is the height of the discontinuity in the derivative. For example, if the previous slope was 0.01/sample and the following slope was -0.02/sample, h would be -0.02 – 0.01 = -0.03.

This paper is where I got the polyBLEP polynomials. It has one tantalizing mention of polyBLAM.

“In case of the triangle wave, however, the replacement of each unit step function with a bandlimited step function is inadequate. Here, the ramp functions of Eq. (4), i.e., terms of form su(s) need to be replaced with the integral of the band- limited step function, given by [big hairy equation].”

V. Välimäki, J. Pekonen, and J. Nam, “Perceptually informed synthesis of bandlimited classical waveforms using integrated polynomial interpolation,” Journal of the Acoustical Society of America, vol. 131, no. 1, pt. 2, pp. 974–986, Jan. 2012.

kernelbobOops, that should be “d = T[current sample] – T[corner]”.

ChristianPost authorTo do a PolyBLEP on a triangle wave you use a naive square, apply the PolyBLEP to it as normal, and then integrate. This does produce a rather odd-looking triangle, however, so yes, it’s not totally adequate.

I’ve not heard of PolyBLAM though. Thanks for the info on this. I will look into this more. There are all sorts of interesting ways people are coming with to generate alias-free waveforms!

krighxzHey Christian, thanks for the write-up! I made a pd vanilla version of this patch for the enzien heavylib today based on your code (https://github.com/enzienaudio/heavylib/blob/master/hv_blepsaw.pd). It works surprisingly well! I hadn’t known about this method and will look into other polynomial corrections next time I get the chance.

ChristianPost authorNo problem! That’s awesome that you made a version for the enzien library based on this code.

PolyBLEPs are surprisingly good given their relatively low computational cost. If you don’t already know about them, MinBLEPs are even better, but at an increased complexity and cost. Worth looking into though.

krighxzNice! Have you by any chance looked into generating impulse trains using similar methods?

ChristianPost authorNo, I had come across some talk on BLITs but as far as I can remember, it sounded like MinBLEPs were the better way to go, so I implemented that.