Waveform Workbench

J. Donald Tillman
Mar 27, 2020


(Sharing with colleagues. Please don't publish it on a mailing list or forum just yet.)

Electronic music generally starts with an oscillator and a waveform. From the point of view of an electrical engineer designing the oscillator, the goal is to provide a specific set of waveform shapes; sine, square, triangle, sawtooth, and so forth.

However, our sense of hearing isn't sensitive to waveform shape. Wildly different waveform shapes can have the same spectrum and sound identical, or nearly so. So an oscillator's spectrum is far more imporant than its waveform.

Regardless of the shape or spectrum, at some level a static waveform is just a fundamental sine wave and a series of harmonics. (And thanks to the sawtooth wave, we have already heard all the harmonics.)

A much more interesting world opens up when the waveform is dynamically modified, changing both the waveform shape and the spectrum. That change can mimic mechancial processes of the very type our sense of hearing has evolved to detect. You can have a simple Y-axis fade between waveforms, or you can morph the waveforms over the time axis. Very, very different effects.

This is a tool for exploring the characteristics of any arbitrary waveform. The waveform is described with a JavaScript function, the resulting waveform is displayed, the spectrum of the waveform is displayed, and we synthesize the waveform to hear what it sounds like.

But there is also a parameter slide pot. And you can write the waveform function to depend on the parameter in any arbitrary way. Some examples are provided below.

The function is written in Javascript. x is the time axis, and goes from 0.0 to 1.0 over the course of a cycle. a is the parameter to vary the waveform. It also goes from 0.0 to 1.0 over the slider range. The Javascript Math library is imported for less swearing. And there is a tri() function for an easy triangle wave.

The spectrum display uses color to represents the phase of the harmonic. It transistions though 0° red, 90° green, 180° cyan, 270° violet.

Here are some preset waveform functions to try:

Sine Wave
sin(2 * PI * (x + a))
The parameter adjusts the phase, and you can see that displayed in the spectrum.
Sawtooth Wave
(1 - 2 * a) * (1 - 2 * x)
Classic sawtooth, all harmonics, 1/n.
Variable Width Pulse/Square Wave
((a * .95 + .02) < x) ? 1 : -1
This is the classic Pulse Width Modulated (PWM) wave. The harmonics are shaped like a comb filter, where the spacing between the null changes with the parameter.
ARP/Rhodes Chroma Variable Saw
(1 - 2 * x) + .5 * ((x < (a * .95 + .02)) ? -1 : 1) + a - .5
The ARP/Rhodes Chroma offered a very interesting variation on PWM, where the pulse wave was subtracted from the sawtooth.
Variable Width Sawtooth/Triangle
2 * min((1 + exp(4 - 8 * a)) * x, (1 + exp(-4 + 8 * a)) * (1 - x)) - 1
The equation here is based on my paper Voltage Controlled Duty Cycle Sawtooth Circuit.
Stairstep Wave
(1 - 2 * x) + 2 * (x % (1 / (8 * a + 2)))
A stairstep wave has a spectrum like a sawtooth wave, but, with every nth harmonic removed, where n is the number of levels in the stair steps. You can make this with a sawtooth wave sync'd to another, and subtract.
Triangle Overdrive
tanh((.5 + 10 * a) * tri(x))
A triangle wave driving a long-tailed differential transistor pair provides a tanh function. Such a circuit is often used to create a sine wave from a triangle.
Flattened Sine
max((2 * a - 1), sin(2 * PI * x))
Slowly take the bottom out of a sine wave.
Flattened Triangle
max((2 * a - 1), 4 * max(min(x, .5 - x), -1 + x))
Slowly take the bottom out of a triangle wave.
Sine Driving a Multicycle Sine Shaper
sin(8 * (.05 + a) * sin(2 * PI * x))
Weirdly close to FM.
FM Synthesis 1:1
sin(2 * PI * x + 10 * a * sin(2 * PI *x))
Classic FM synthesis.
FM Synthesis 2:1
sin(2 * PI * x + 10 * a * sin(4 * PI *x))
Modulator is twice the frequency of the carrier.
FM Synthesis 3:1
sin(2 * PI * x + 10 * a * sin(6 * PI *x))
Modulator is three times the frequency of the carrier. Feel free to bop in other multipliers.
Sync'd Sine
sin(2 * PI * x * (1 + 15 * a))
A sync'd sine acts sort of like a weird resonanant filter.
Exponential Sync'd Sine
sin(2 * PI * x * (1 + 15 * a)) * 2 * exp(1 - 8 * x)
Like the above, but exponentially decaying, so you don't have that sync discontinuity. And the waveform looks and sounds all the world like a resonant filter.
Wavelets
sin(2 * PI * x * (1 + 15 * a)) * sin(PI * x)
The sync'd wave fades in and out over the cycle. It plays harmonies in the form of neighboring harmonics.
Wavelet Variation
sin(2 * PI * x * (1 + 15 * a)) * sin(2 * PI * x)
This variation plays harmonics in the form of a pair of harmonics skipping over one in between them.
Max Operation
max(sin(2 * PI * x), sin(2 * PI * a * 10 * x))
A simple max function between two sines is interesting.

More to come...