The Karplus-Strong algorithm is not exactly a physical model, but it can be considered a preliminary stage to waveguides. The algorithm is based on a ringbuffer, filled with (white) noise, which is then manipulated. With very simple means, Karplus-Strong can synthesize sounds with the characteristics of plucked strings. Although not entirely realistic, the result has a intriguing individual character.
The Ringbuffer¶
Ringbuffers are the central element of the Karplus-Strong algorithm. As the name suggests, they are FIFO (first in - first out) buffers, with beginning and end connected.
A ringbuffer with N
samples can be visualized as follows:
White Tone from White Noise¶
If a ringbuffer is filled with a sequence of white noise, it can be used for creating a white tone - a harmonic sound with a strong overtone structure. Without resampling, the ring buffer can be shifted by one sample each $1/f_s$ seconds. The resulting pitch of the sound is then determined by the buffer size:
$$f_0 = \frac{f_s}{N}$$
For a sampling rate of $48000$ Hz, a ringbuffer with a length of $N=200$ samples, results in the following pitch:
$$f_0 = \frac{ 48000 \mathrm{\ kHz} }{ 200 } = 240.0\ \mathrm{Hz}$$
The sound of this harmonic signal is similar to a buzzer:
Spectrum and Individual Timbre¶
The spectrum of the white tone includes all harmonics up to the Nyquist frequency with a random amplitude. The overtone structure is individual for every white noise sequence, as is the timbre. These are three versions, started with an individual noise sequence of $N=400$ samples.
Version 1¶
Version 2¶
Version 3¶
Karplus-Strong¶
Karplus-Strong makes use of the white-tone buffer and combines it with a moving average filter with the impulse response $h[n]$ and an additional gain $g$:
In the original (and most basic form), two samples are read from the buffer $b$, starting from index $i$ (the playhead), and the average of both samples is written to the buffer. An additional gain factor - set to $0.95$ in this example, results in a faster decay:
$$ b[i] = 0.5 (b[i] + b[i+1])$$
$b[i]$ is directly sent to the output $y$ in each step:
$$y[i] = b[i]$$
$i$ is increased, until it reaches $N$ and continues from the beginning. The following image shows this for the step $i=3$:
The result of this circular smoothing is a gradual decrease in high frequencies. The sound begins with a metallic transient:
Increasing the Filter Size¶
A faster decay of high frequencies can be achieved by larger moving average filters. This example uses a moving average of $10$ samples and a gain of $0.99$.
Exercise¶
The above introduced version of the Karplus Strong algorithm is limited to integer shifts and allows only specific frequencies. Code a version that allows fractional shifts and arbitrary frequencies.