mathr / blog / #

Bandlimited wavetables

bandlimited wavetables in Pd

One of the fun parts of using Pure-data is being able to draw arbitrary waveforms and use them for oscillators. Unfortunately the naive approach using [tabread4~] suffers badly from aliasing - if you define your table with 1027 points (a power of two plus 3 guard points for polynomial interpolation), using it for an oscillator at frequencies above around 45Hz (depending on sample rate) will cause aliasing of high frequencies in the table (playing a table faster than 1 table sample per output sample will start aliasing, playing slower is fine). Halving the table size doubles this aliasing frequency, but loses the high frequency content from the table.

I do some graphics, and learned that mipmapping is a very important part of OpenGL texturing if you don't want it to look really bad (with lots of aliasing artifacts like Moiré patterns). So I thought about applying the same technique to audio. Mipmapping works by using the spatial derivative of the index into the texture to choose which resolution to use - when the index is changing rapidly, the derivative is large and a low resolution should be chosen, when the index is changing slowly the derivative is small and a high resolution should be chosen.

My implementation requires only Pd vanilla (built-in core objects) and is available at maximus/pd-bl on Gitorious bandlimited on code.mathr.co.uk, under the same BSD-style license as Pd itself.

Usage is quite simple: create a [table] for your source waveform, create a [bl-table] for the bandlimited wavetable, turn on dsp and send a message to a [bl-gen~] to generate the content in the [bl-table] by copying from the source [table] and repeatedly filtering and downsampling. Then you can use the [bl-table] as an oscillator waveform with [phasor~] and [bl-tabread4~].

Here are some images of a waveform repeatedly filtered and down-sampled by [bl-gen~] (I hacked a patch together to save all the tables inside the [bl-table] to text files, then rendered them with some Haskell code):

And here's what the two methods sound like (you might want to reduce volume before playing as they are quite loud):

aliased (using [tabread4~])
FLAC, Ogg Vorbis
bandlimited (using [bl-tabread4~])
FLAC, Ogg Vorbis

You can also download the Haskell source code used to create the gallery images in this post, using the Diagrams library.

Future work might research into extending the technique to wave-shaping distortion, or other domains I haven't thought of yet.