Wavetable Viewer

Wavetable Viewer lets you visualize and listen to wavetables stored in WAV files. It will automatically reload the wavetable as it gets modified, speeding up your process of creating wavetables.

Wavetable Coding Tutorial

Here’s a sawtooth wavetable created in Python:

# main.py
import numpy as np
from scipy.io.wavfile import write

FRAME_SIZE = 2048
frame = np.linspace(-1, 1, FRAME_SIZE)

write("output.wav", 44100, frame.astype(np.float32))

We can run it like this:

python3 -m venv .venv
source ./venv/bin/activate
pip install numpy scipy
python main.py

We can preview the wavetable using Wavetable Viewer:

wtv ./output.wav &

The & starts the program in the background, so we can keep using our shell.

We can now start modifying the script. Let’s turn the saw wave into a square wave:

x = np.linspace(-1, 1, FRAME_SIZE)
frame = np.sign(x)

Running the script will overwrite output.wav, and Wavetable Viewer will automatically reload it and show you the new wavetable.

We can try a few more waveforms:

frame = np.sign(x - 0.5)
frame = np.abs(x)
frame = x ** 2

We set endpoint=False for the sine wave, since it is a periodic function, and we don’t want to have duplicate values at the start and end of a waveform.

x = np.linspace(-1, 1, FRAME_SIZE, endpoint=False)
frame = np.sin(x * 2 * np.pi)

Here’s an example of creating a sequence of frames that interpolate between two waveforms:

FRAMES = 256

x = np.linspace(-1, 1, FRAME_SIZE, endpoint=False)
sine = np.sin(x * np.pi)
square = np.sign(x)

wt = np.empty((0))

for frame_id in range(0, FRAMES):
    t = frame_id / (FRAMES - 1)
    frame = t * square + (1 - t) * sine
    wt = np.concatenate((wt, frame))


write("output.wav", 44100, wt.astype(np.float32))

Here’s an example for creating wavetables using the Fourier Series:

wt = np.zeros(FRAME_SIZE)

x = np.linspace(-1, 1, FRAME_SIZE, endpoint=False)
for h in range(1, FRAME_SIZE):
    wt += np.sin(x * np.pi * h) * (1 / (h * np.pi))

We can go many ways from here. Have fun!