Wavetable Synthesis Handbook

An essential guide to wavetables and wavetable synthesis.

What is Wavetable Synthesis?

The term “wavetable” is often used to represent several different things. In the most basic conception, any waveform (the graphic shape of a signal as a function of time) stored in a numeric table of values, is essentially a wavetable.

For instance, the following numeric sequence: [ 0, 0.707, 1, 0.707, 0, -0.707, -1, -0.707 ] is an 8-sample sine wavetable (shown in Figure 1).

The fact that the table is missing the last sample in this example (the final 0) responds to the purpose of this type of wavetable: to create a continuous sound by simply playing the table from start to end, then repeating the sequence (0 to 7 in this case) in a loop.

Figure 1: 8-sample sine waveform (WaveTable Synthesis)
Figure 1: 8-sample sine waveform

This process, traversing a numeric table at a certain speed and outputting the table values as audio, makes for the most elemental type of digital oscillator: the Lookup-Table Oscillator. This design was first introduced in 1957 in the MUSIC-N computer program, written by Max Matthews at Bell Labs. It was the very first program to make sound and music using a digital computer.

The LUT oscillators are most likely the most used oscillators in nowadays synthesizers. While there are several oscillator types in the digital domain nowadays, many of the high-end ‘Virtual-Analog’ type synthesizers store their primitive waveforms in a table, often with several bandwidth-staged versions of the same waveform, which are dynamically selected according to pitch and sample rate to prevent aliasing. Every synthesizer using non-trivial waveform resorts to this mechanism.

On the other hand, and in this same field of sound synthesis and synthesizers, the table storing a sine wave like the one in the previous example is called a “waveform”. The term wavetable is used to name a collection of waveforms stored in a table. This is, a table storing multiple waveforms instead of a single waveform.

This is how a wavetable made of trivial waveforms looks. In the early 80’s, Wavetable-Synthesizers such as the Waldorf PPG introduced the novel (yet elemental) concept of expanding the sound capabilities of the LUT oscillator by dynamically changing the “index” of the table being scanned. As the wavetable had all the waveforms in contiguous digital space, it was natural to allow the index to be modulated by different sources (such as envelope generators, random-number generators, low frequency oscillators or diverse performance gestures such as the key played, velocity, foot pedal, etc.).

In this article, “wavetable” will refer to this latter definition, while “waveform” will be used to indicate a single-cycle waveform table. Similarly, “wavetable synthesis” will be used to refer to signify the ability to change the played waveform by modulation or user gestures,

Wavetable Synthesis

Besides of the PPG and the follow-up “classic” synthesizers of the past, there are numerous hardware and software synthesizers in the market nowadays, which allow for different variants of wavetable synthesis. In fact, the resurgence of wavetable synthesis has been instrumental in the conformation of several modern music genres and their sound palette.

A less known concept is that Wavetable Synthesis is actually a sub-set of Additive Synthesis (or Fourier Synthesis) in which only harmonic overtones are used (Additive Synthesis can also produce inharmonic components, represented as aperiodic waveforms).
One simple way of seeing Wavetable Synthesis is as a form of pre-calculated Additive Synthesis, with the main purpose of substantially reducing the required power of calculation for a real-time implementation. While a stretch out of this notion could apply to several other deterministic synthesis mechanisms, it is immediate in Wavetable Synthesis. The different waveforms are ‘snapshots’ of distinct harmonic structures.

Some hardware units featuring wavetable synthesis (only newer units):

  • Waldorf Blofeld
  • Waldorf NW1 (Eurorack)
  • Waldorf Quantum
  • Novation Ultranova/Mininova
  • Novation Peak
  • Studiologic Sledge (Waldorf engine)
  • Clavia Nord Lead 4

And the most known and used software units (there’re over a hundred now):

  • Native Instruments Massive
  • XFer Records Serum
  • Ableton Wavetable (part of Live 10)
  • U-He Zebra
  • Waves Codex

WCreate

WCreate is a small command-line utility (windows) which creates bandlimited waveforms of any indicated size by using additive/Fourier synthesis, the most fundamental synthesis algorithm.

The tool is fed with the size, an expression defining the spectral behavior (or harmonic magnitude/phase responses) and a filename, and it spits the corresponding waveform as a standard wave file.

This sounds complicated, but it’s actually very simple (as long as the reader has a basic understanding of Fourier series). WCreate will calculate all the partials (like Sin( x ), Sin( 2x ), Sin( 3x ), etc. ) and then will find in the expression what amplitudes and phases should apply to each partial. A few examples:

WCreate 1024 “x=1” sine.wav

This creates a single-cycle sine wave, 1024 samples long.

WCreate will iterate thru “x” values, from 1 to maximum (half of length), then will replace that value in the expression and calculate the partial amplitude.

In this way, complex harmonic series can be represented very simply.

WCreate 1024 "(x=1)+(x=2)" sine_1_2.wav

(x=1) + (x=2) indicates the sum of the two first partials, the fundamental and the 2nd harmonic, at same amplitude and phase.

WCreate 1024 "x<=8" sine_1_8.wav

This expression uses the <= comparation to avoid the long (x=1)+(x=2)+…(x=8) series.
The waveform is the sum of the first eight partials at same amplitude.

WCreate 1024 "1/x" saw.wav

This expression is slightly more complex, but extremely important, as the SawTooth waveform is of utmost importance in sound synthesis, technologically, sound-wise and from historical perspectives.

What makes the SawTooth waveform singular is that it features all harmonics, decaying linearly. It can be expressed as:

Saw( x ) = Sin( x ) + Sin( 2x ) / 2 + Sin( 3x ) / 3 + …

First partial is at full amplitude, second partial at half, third partial at one-third, etc. Therefore, the expression in this command line “1/x” represents the “/2”, “/3”, “/4”, etc.

WCreate 1024
"(x=1)+(x=2)*0.5+(x=3)*0.33+(x=4)*0.25" saw_4.wav

This example shows how only 4 partials of a sine wave result in a waveform which starts resembling a SawTooth.

WCreate 1024 "1/x*(x<=8)" saw_8.wav

Same concept as previous, now with 8 partials.

WCreate 1024 "1/x*(x%2)" square.wav

The Square wave is another extremely interesting case, as part of the main combo in subtractive synthesis together with the SawTooth and Triangle.

It has the same spectral decay characteristics of the SawTooth, but only even partials are present.

The “x%2” term (x modulus 2) returns the reminder of dividing the partial number by 2 (so it’s 1 for odd partials and 0 for even).

WCreate 1024 "1/x^2*((x%4=1)-((x+2)%4=1))" triangle.wav

The triangle wave is another classic waveform, fundamental in the “analog waveforms” set together with SawTooth and Square. It has the same spectral composition as the Square wave (only odd partials have non-zero amplitude), however, the spectral decay is quadratic (faster), and the phase of every other partial is inverted:

Tri = Sin( x ) – Sin( 3x ) / 9 + Sin( 5x ) / 25 – Sin( 7x ) / 49 + …

WCreate 1024 "(1/x^2*((x%4=1)-((x+2)%4=1)))*(x<8)" triangle_4.wav

Precisely because of a faster spectral decay, the triangle wave is simpler to approximate with a few components.

This is a triangle wave made of only 4 sines.

WCreate 1024 "1,,,,,,,,,1" sine_1_10.wav

This expression uses Partials mode to create a waveform which has the funtamental and the 10th partial at full-scale amplitude.


The following are the first ten waveforms in the “buzz” folder, created by the example script. They combine three groups of partials to form different buzzy sounds:

WCreate 1024 "(x<6)+(x>17)&&(x<19)+(x>50)*0.015" buzz_00.wav
WCreate 1024 "(x<6)+(x>19)&&(x<22)+(x>50)*0.015"buzz_01.wav
WCreate 1024 "(x<6)+(x>21)&&(x<25)+(x>50)*0.015" buzz_02.wav
WCreate 1024 "(x<6)+(x>23)&&(x<28)+(x>50)*0.015" buzz_03.wav
WCreate 1024 "(x<6)+(x>25)&&(x<31)+(x>50)*0.015" buzz_04.wav
WCreate 1024 "(x<6)+(x>27)&&(x<34)+(x>50)*0.015" buzz_05.wav
WCreate 1024 "(x<6)+(x>29)&&(x<37)+(x>50)*0.015" buzz_06.wav
WCreate 1024 "(x<6)+(x>31)&&(x<40)+(x>50)*0.015" buzz_07.wav
WCreate 1024 "(x<6)+(x>33)&&(x<43)+(x>50)*0.015" buzz_08.wav
WCreate 1024 "(x<4)+(x>35)&&(x<45)+(x>50)*0.015" buzz_09.wav

The “Bandlimited” part

A closer examination of the Square wave graph above might indicate at first glance that it’s not a “perfect” wave: it shows some jagged lines near the transitions. Here’s how it compares to a theoretical, perfect square wave:

The “perfect square” image on the right (we’ll call it “trivial square” from now on) is a theoretical representation of a square wave containing an infinite number of partials.

Once a single-cycle waveform is stored in a file, the number of partials it can contain is limited to a half of its size. Any partial which is beyond that limit is mirrored against the limit, or aliased.

In other words, the trivial square has unwanted harmonics that do not belong to the mathematical series. In other words (and practical terms), it’s distorted, and sounds… ugly. Here’s how the spectral diagram looks for a LUT oscillator using the above waveforms:

The graphic shows consecutive five notes, separated by one octave. Note how the trivial square show intensity bands at partials which are not supposed to be present. That intensity is unwanted, and therefore a distortion.

To avoid such a distortion, the waveforms have to bandlimited. This is, only the partials up to Nyquist limit (half of the size) should be calculated. For a 1024-sample waveform, it looks just like the graph in the left.

The bigger the size, the more it resembles the trivial square. However, this has no real meaning for audio applications. As the human ear can only perceive frequencies form 20 Hz to 20 kHz (in average a much lower range), the 1001-th partial of a 20 Hz note will be out of hearing range.

That is the reason why most modern wavetable instruments pick 1024 or 2048 samples as file size. A 1024-samples file will allow for up to 512 partials, which suffices to cover the whole audio spectrum starting at 40 Hz.

In practice, most waveforms have a spectral decay. This means, the intensity of upper partials is progressively lower. For most waveforms that respond to such a construct, much lower table sizes will be enough.

Using WCreate

As seen above, WCreate only takes three parameters:

WCreate <size> <expression> <output filename> [-64]

Size

The waveform size in samples. It is usually a power-of-two value: 64, 256, 1024, 2048, etc., yet it can be any value.
Size does matter: as per the Nyquist theorem, a N-sized waveform can only hold N/2 partials. This means that smaller sized waveforms will sound duller than bigger waveforms.

To be musically usable, the LUT oscillator using the waveforms need to change their pitch, using a process known as resampling (upsampling when rising the pitch, downsampling when lowering it). Small waveforms will exhibit audible artifacts when downsampled to very low frequencies.

As an example, when resampling (changing the pitch) a 256-sample waveform to play a 100 Hz frequency, the last partial will be at 25.6 kHz (100 x 256) so this size is more than sufficient to play the whole spectrum, as last partial is beyond audible spectrum.
However, playing a 40 Hz frequency will place the last partial in 10.4 kHz, which lands well inside the audio spectrum. Depending on the spectral construction of the expression, this effect could be clearly audible.

Additionally, bigger sizes help the LUT oscillator to produce less interpolation noise when resampling. While this can be compensated by using a higher-order interpolation algorithm, this requires additional computational power.

In the early days of wavetable synthesis, memory (and the capabilities to address it) was expensive. So the total size and number of waves was limited. One of the most successful, early wavetable synthesizers, the Waldorf PPG Wave 2.2 had 128-sample wavetables (each sample was also 8-bit, later changed to 12-bit in the 2.3 revision).

Nowadays, in the age of terabyte sample libraries, those limitations no longer exist. Ableton Live’s Wavetable synthesizer requires 1024-sample waveforms, and XFer Records’s Serum requires 2048-samples.

WCreate will produce standard 16-bit PCM wavetables as default, or 64-bit floating point wavetables if the -64 option is used.

Expression

Here’s where the magic happens. WCreate can understand two different expression modes: Partials and Series.

Partials Mode

Partials is the most straightforward mode. The expression is just a comma-separated list of Amplitudes for each partial, followed by a similar list of Phases. Amplitudes and Phases are normalized (0 to 1 range) and both lists are separated by a semicolon.
A few examples:

WCreate 1024 "0,1" sine_2.wav
WCreate 1024 "0,1;0,0.25" sine_2a.wav
WCreate 1024 "0,1;0,0.5" sine_2b.wav
WCreate 1024 "0,1;0,0.75" sine_2c.wav

These expressions will create waveforms with no fundamental (zero level) and full-scale 2nd harmonic (1 level ), at four different phase settings (0, 90, 180 and 270 degrees):

WCreate 1024 "1,0.2,1,0.2,1,0.2" buzzsq.wav
WCreate 1024 "1,0.2,1,0.2,1,0.2;0,0.5,0,0.5" buzzsqa.wav

Two arbitrary partial constructions with same levels, at different phases.

Series Mode

In Series mode, all partials will be calculated, and evaluated according to the expression (see above for expression examples).
Series expressions can use the following operators:, in order of precedence:

  • (“ and “)“ for expression delimitation and explicit operation precedence
  • +”, “”: add, subtract
  • =”, ”!=”, ”<”, ”>”, ”<=”, ”>=”: equal, not-equal, less than, greater than, less or equal and greater or equal comparison operators
  • *”, “/“, “%”: multiply, divide, modulus
  • &&”, “||”: and, or logical operations
  • ^“: power (i.e. “x^2”)
  • #”: random (generates a random number between 0.0 and 1.0)

Examples

Besides the examples previously shown in this article, the “create_tables.bat” script file (included in the download) includes 1000+ usage examples for WCreate.

The folders Numeric and Series illustrate the use of the random operator to introduce a controlled degree of unpredictability in the creation. Happy creating!

WMorph

WMorph is another command-line utility (Windows). Given two waveforms created by WCreate and a number of intermediate stages, it’ll calculate a wavetable with all the “morphed” stages, using linear crossfading.
Here’s an example::

WMorph 8 sine.wav square.wav morph.wav

Will create a wavetable with 8 waveforms, interpolated between the two specified.

morph.png

Using WMorph

WMorph will ingest four parameters, as follows:

WMorph <stages> <input file 1> <input file 2> <output file> [-nolast] [-all] [-64]

Stages

Define the total number of waveforms expected as a result of the interpolation process (including the two original).

Using 0 (zero) as stages will result in both input files concatenated. This is very useful when sticking together wavetables of different number of waveforms.

Input File 1, 2

The two input files. They should be of the same length. While the “natural” use is to create a wavetable morph between two files containing only one wavetable, there’s nothing that prevents morphing in between two complete wavetables having multiple waveforms as long as both files have the same length.

Output File

The resulting wavetable file name.

-nolast option

By “sticking together” several wavetables it is easy to make complex wave transitions (such as Sine to Triangle to Square to Saw, with multiple intermediate waveforms each).

For this case, the -nolast option avoids repeating the ending table with the same table as startup of next table. Here’s an example:

Note that using 3 as Stages will not result in the same file: it will return a wavetable with only one interpolated waveform in between the sine and the square.

If the -all option is used, WMorph will additionally write all intermediate waveforms as separate files.

Downloads

Download WCreate, WMorph, and a script to create 1000+ waveforms from here (Windows command-line, 136kb).

The set of example waveforms and wavetables as 32-bit floating point wave files are here.

References

  1. https://en.wikipedia.org/wiki/Wavetable_synthesis
  2. “A Digital Signal Processing Approach to Interpolation”, R. W. Schafer and L. R. Rabiner, 1973.
  3. “Foundations of Computer Music”, “Design of a Digital Oscillator That Will Generate up to 256 Low-Distortion Sine Waves in Real Time”, J. M. Snell, 1985.
  4. “Elements of Computer Music”, F. R. Moore, 1990.
  5. “Wavetable Synthesis 101, A Fundamental Perspective”, Robert Bristow-Johnson, Wave Mechanics, Inc., 1996
  6. https://en.wikipedia.org/wiki/MUSIC-N, The MUSIC-N computer music program.