Category Archives: Writing

Simple Karplus-Strong Synthesis and Note Length

Ever waste a whole bunch of time trying to understand something, where the only way to feel less guilty about wasting so much time on it is to tell someone about it? Me too… here goes.

In between more important things, I was thinking about Karplus-Strong (KS) plucked string synthesis again the other day — more than just the general concept of a filtered feedback network creating something that sounds like a plucked string — specifically, how high notes are quick to decay, and how low notes sustain for longer.

The reason this happens is because of the amplitude scaling that is applied through each feedback recursion. Each feedback recursion multiplies the amplitude by some value less than (but close to) 1. Essentially, the note lasts as long as the recursive geometric sequence doesn’t tend to zero. Because the recursive geometric sequence terminates at zero (well, at least at some point in a fixed bit number system anyway), the number of times a grain repeats before fading to silence is exactly the same whether it’s a low or high note. Since the high notes have a short grain-length, they die quicker.

I set out to figure out a way for one to specify note length, and have the algorithm figure out the scaling factor based on the desired pitch (as the geometric sequence should occur more often, the closer it gets to 1). Not sure if someone has written about this before (there’s probably plenty published about it, and to be honest, I didn’t look), but it was an excuse to kick around a couple of under-used neurons in my brain.

Where to begin…

When we think about sound in a medium (eg. in air, water, or earth), the relationship between pitch and wavelength is that they are inversely proportional about the speed of sound in the medium. The pitch is the number of oscillations per second, and the wavelength would be some value specified in metres, feet, etc. If something has a frequency x, the length of a cycle of the wave is speed of sound in the medium divided by frequency x — so if sound travels 343 feet per second in air, something with a frequency of 343 Hz would have a wavelength of 1 foot. A frequency of 440Hz would have a wavelength of 0.78 feet, etc. etc.

It’s more useful to think of wavelength in the temporal sense though, when it comes to KS synthesis.
‘Wavelength’ in KS synthesis is really just ‘time in ms’ of a repeating grain/cycle. I’ll refer to this from here onwards as cycle-time, or grain-width… ehhh, I can’t decide. Grain-width is probably better. Essentially, in KS synthesis, we’re more interested in the time it takes for a cycle of the wave to complete. Therefore, in the KS algorithm, the delay-line length of the repeating wave (the grain-width) in ms is 1000 / frequency.

Why? Because the frequency is the number of time it repeats each second. For example, a frequency of 440 Hz would have a grain-width of 1000/ 440 = ~2.27ms. A frequency of 343 Hz would have a cycle-time… I mean grain-width… of ~2.915ms. This is the ‘length’ of the repeated noise burst.

Calculating the Scaling Factor

Firstly, let’s lock the desired length of the plucked sound to be 2 seconds. In order for something to play for 2 seconds, we need to know the pitch we want to hear, and consequently adjust the multiplication factor so that for a given cycle-time/grain-width, a repeated wave will terminate after a specific number of recursions.

OK… so let’s say we want to play a 440 Hz note. The cycle-time is 2.27ms. The sound should repeat 880 times (given that it repeats 440 times per second).

It wasn’t immediately obvious to me how I should figure out how to set a multiplication value such that a geometric sequence (starting at 1., ending at 0.) should terminate after 880 recursions. The answer to this question might be fairly straightforward to someone out there with a background in number manipulation (or quantisation) in fixed bit number bit systems, but it seemed like the only way for me to understand this was to plot out the ‘recursions’ given a series of fixed scaling factors.

So, to figure this out, I did something really dull… (I’ll call it brute-force “modelling” to make it sound more interesting than it is). I set up a really basic system to count the number of times that a number (1.) is recursively scaled (with values < 1.) until it was less than 0.000001*. At an amplitude of 0.000001, I figured the sound was essentially silent (for 16-bit audio anyway). The way I did it was pretty rough, but that didn’t matter. I just wanted to glean a sense of how the scaling factor affected the number of recursions.

*Disclaimer: Having a poor understanding of number representation in the computer, I couldn’t count the number of times the function ‘actually’ happened because if I set the counter function to stop when the geometric sequence ‘equalled’ zero, it kept counting. I figured it had something to do with subnormal numbers — or that the internal mechanics of the ‘accum’ object had a finer resolution than the upper world of Max (or maybe it’s that I just upgraded to Max 6.1, where it appears that objects are working internally with 64bit precision… I think).

I therefore used an arbitrary small value, namely 0.000001 (which seemed to be the smallest number in magnitude that I could use as an argument in an object or write in a message box).

This is what I learned:

Starting with 1, the following values were less than 0.000001 after being recursively multiplied n times:

0.90 = 131 recursions 0.990 = 1374 recursions 0.9990 = 13808 recursions
0.91 = 146 recursions 0.991 = 1528 recursions 0.9991 = 15343 recursions
0.92 = 165 recursions 0.992 = 1720 recursions 0.9992 = 17262 recursions
0.93 = 190 recursions 0.993 = 1966 recursions etc.
0.94 = 223 recursions 0.994 = 2295 recursions
0.95 = 269 recursions 0.995 = 2756 recursions
0.96 = 338 recursions 0.996 = 3446 recursions
0.97 = 453 recursions 0.997 = 4598 recursions
0.98 = 683 recursions 0.998 = 6900 recursions

The pattern I spotted was that with more precision (as we tend toward 1.), the resolution jumps tenfold. Seems somewhat straightforward. I thought this over, and came to the conclusion that we can model this ‘precision’ by:

subtracting the scaling factor from 1, and then dividing 1 by that number.

eg. for 0.98:

1. – 0.98 = 0.02
1. / 0.02 = 50.

and 0.998:

1. – 0.998 = 0.002
1. / 0.002 = 500.

This produced values that shared the same ratios as the figures I got from my tests, but the numbers themselves were proportionally out by another value. Dividing the numbers produced by my recursive scaling tests by these precision ‘ratios’ I derived, I get a value somewhere around 13.75. I don’t know what this means… I’ll try to understand this later.

Firstly though, in order for me to calculate the scaling factor for a given pitch, I should do some kind of lookup (or reversal of the above process): find a value that terminates after n recursions, and set that as the scaling factor.

So, back to the example of making a note ring on for two seconds, lets pick a pitch and try it out… Say 440Hz.

OK. 440Hz will recur 880 times in two seconds.

If we want 880 recursions, our scaling factor should be somewhere between 0.98 and 0.99. Given that 0.98 produces 683 recursions, and 0.99 produces 1374, there’s quite a bit of leeway there.

Let’s try using the reverse of the formula (with the mystical ~13.75 ) to try to derive the scaling factor. [Strangely, I only just noticed the 1374 on the line above… maybe it’s just a coincidence.]

880 (number of recursions) / 13.75 = 64

1 / 64 = 0.015625

1 – 0.015625 = 0.984375 (Fits the conditions of being between 0.98 and 0.99. Good).

The formula to calculate scaling factor therefore appears to be,

1 minus the inverse of ((pitch * length in seconds) / 13.75)

or (since 13.75 is just a constant)

1. – (1. / ((frequency * length in seconds) / magicNumber))

It’s not perfect, but notes now seem to sustain for similar lengths, whether played low or high.

Other thoughts

Up to this point (in order to remove variables) I’d been working with an ideal situation, where no low-pass filter existed in the KS feedback network. Depending on the cutoff (or amount that is attenuated), the filter plays a big part in how long the note appears to resonate. Notes down the bottom still start with a broader spectrum, so a proportional filter cut-off (based on the fundamental of the synthesised note) might be a good idea too. I’ll think about that another day. After adding a fixed cut-off it doesn’t sound bad as it is though.

What have I learned from this?

  1. If something is percolating away in your brain, it’s faster to go about something in a laborious way and put pen to paper with the data you acquire, than it is for something to become self-evident.
  2. That producing something useful with the Karplus-Strong algorithm is much more complicated than scaling/filtering feedback of noise.

What am I still to learn?

With regard to different scaling factors, I haven’t yet looked in depth at how different pitches decay with different values (basically, whether a geometric sequence is the same at different scales). From some basic tests in a spectrogram, the geometric sequence appears to be similar at different scales. Notes seem to decay at similar rates when the grain is smaller (and the scaling factor is consequently closer to 1). It isn’t immediately obvious to me that it should or shouldn’t be this way.

At the end of this all… what’s with the number magicNumber constant (~13.75)? I still have no idea. Ultimately, though, the ~13.75 is irrelevant. I arrived at this number from the data I acquired just by counting the number of times 1 (when recursively multiplied by a value less than 1) tended to 0. In the actual synthesis implementation, setting it around 4.5 with a low-pass filter around 8000Hz makes notes appear to last around the desired length. It seems somewhat related to the filter cutoff-value in adjusting note length. (eg. a lower filter value causes the note to appear to fade more quickly, as we’re filtering out a lot of the note’s energy). It’s a little bit subjective though, and I only timed the length of plucked synth note by ear (and on laptop speakers).


Here’s the patch. Adjust the note length number box to produce longer or shorter notes. Make sure you switch between the ‘enable/disable scaling adjustment’ to hear the difference in note sustain lengths (ie. compensating for different grain-widths to produce similar decay lengths).



The base-chords and note progression that forms Tathagata is something that must have been going through Fredrik Thordendal’s head for some time.  This progression is something that has emerged at least 3 times in both Meshuggah and Fredrik’s solo work, and can be heard as the basis of Tathagata (Sol Niger Within, 1997; Sol Niger Within version 3.33, 1999), the close [3:50] of Sublevels (Destroy Erase Improve, 1995) and the outro [9:06] of Fredrik’s Secrets of the Unknown demo.

Tathagata is a beautiful track that seems to will the listener into innately feeling or predicting the next series of notes.  I was wondering why I felt this way about the track, until I sat down and started to score out the notes.  What emerged was a pattern, or a recursive, self-pitch-clipping algorithm.  (While it is a progression that continues to spiral upward, it has octave subtraction protection to stop it going on infinitely upward).  This is a very cool progression that, while it isn’t an auditory illusion, for some reason makes me think of a Shepard-Risset glissando, Risset’s rhythmic accelerando auditory illusion, or Autechre’s Fold4,Wrap5 (LP5, 1998).

At first, I thought the track progressed in measures of 5, with the notes being played on the 1, 2 and 3. Sarah argues that each measure is divided into 16ths with stresses on 1, 4 and 7, which I now think is actually correct.

In lay terms, the track can be represented as such:

The pattern progresses in a count of 16.

The ‘root’ note starts at MIDI pitch 56, and adds 5 semitones after each loop.  If ‘root’ exceeds 62 (or the initial ‘root’ value + 6), then subtract 12.

‘root’ plays a chord (root, root + 7, root + 12 [they are transposed down an octave in the code below]) on the 1 that rings out over the course of the measure.

‘note[1-3]’ is the melodic progression of the plucked parts.  They play on positions 1, 4, and 7 respectively of the measure.

note[1] = root + 2

note[2] = root + 3

note[3] = root + 11

One possible implementation of Tathagata for JS in Max


// Simple representation of pitches and key modulation in Fredrik Thordendal's Tathagata.
// Tathagata.js by Alex Mesker / /
// Save as Tathagata.js and put it in your Max search path.
outlets = 2;
setoutletassist(0, "Melodic progression (MIDI pitch)");
setoutletassist(1, "Root chord note/s (MIDI pitch)");
var root = 56;
var cutoff = root + 6;
function msg_int(i) {
if (i==1) {
outlet(1, root-12);
outlet(1, root-5);
outlet(1, root);
outlet(0, root+14);
} else if (i==4) {
outlet(0, root+15);
} else if (i==7) {
outlet(0, root+23);
root += 5;
if (root > cutoff) {
root -= 12;

Save the above JavaScript as Tathagata.js and put it in your Max search path.

A Max patch that uses it can be downloaded here:


Pitched Synthesis with Noise Driven Feedback Delay Lines

The other day I was listening to Autechre’s Quaristice and thinking about my first perceptions of the album.  I remember thinking “This album has a very physical-modeling feel to it”.   I had forgotten about this, and recently I was playing around with Karplus-Strong string-modelling synthesis, after reading about the methodology behind it.

The opening of Autechre’s 90101-5l-l has these gorgeous rich resonating tones, which I accidentally seemed to be able to replicate with a Karplus-Strong model.  It sounds like they are capturing an incoming audio stream and then thrusting a noise-grain into a Karplus-Strong algorithm. (There’s more going on in there, but this seems to be the basis.)

Autechre – 90101-5l-l (Quaristsice)

Example of Noise-Grain Feedback using Karplus Strong Plucked String Synthesis Methods

In simple terms, Karplus-Strong tones are generated by taking a burst of noise, and creating a feedback loop that repeatedly lowpass-filters the noise and scales the volume back slightly.

The combination of each of these factors plays a part in the resulting tone:

  • The brighter the burst of noise, the brighter the attack and note.
  • The loop time determines the pitch (shorter = higher, longer = lower)
  • The amount of filtering determines the length and life of the note.

Kind of like concatenative synthesis with a recursive function applied to each grain.

So, for fun I was trying to make a synth that would generate tones using this noise-based feedback model using Max.

In order to generate a specific tones, I was basing my pitches on the relationship:

F0 = FS / Z-L

That is, the fundamental frequency (F0) is determined by the sample rate (FS) divided by the length of the delay line in samples (Z-L).  Put simply, the number of times the delay line is read through per second is its frequency in Hz.

My first versions suffered from a very strange thing where the pitch accuracy was shockingly bad.  I was getting weird results where tones were getting more out of tune the higher they went.

The first problem is that I was using a [delay~] delay line with integer sample-length delays.  Who would have thought that something that was ‘sample accurate’ could be a bad thing?

I realised later that it was bad because the generated tones were inversely proportional to the sample rate and that the values were being truncated to integer lengths.  When the length of the delay was long, the pitch was moderately accurate.  However, as the sample length got shorter, the pitch went way out.

The reason why this is bad is quite interesting.  Consider that we are working at a sampling rate of 44100 Hz.

What tone will be generated if we use a delay line consisting of 5 samples?

44100 / 5 = 8820Hz

What about a delay line of 4 samples?

44100 / 4 = 11025Hz

This is a big problem.  As the frequency that we are trying to generate gets higher, the less range we have in discrete tones.

At first, this appeared to be a sample rate issue.  If we increase the sample rate we should be able to get finer tone control.  However, doubling it means that we can get only one new pitch between the two we got at 44100.

88200 / 9 = 9800Hz

This is still not that good.  My solution was to make an abstraction and try some ridiculous upsampling with [poly~].  With this, understandably came a hit to my CPU.  The solution was still not all that good, as only one single new pitch could be attained between the previously possible tones each time the sampling was doubled.

This had been puzzling me for about a week until I decided to drop [delay~] for [tapin~].  Amazingly,  [tapin~] allows fractional sample length delays, as it does subsample interpolation when given a signal as its delay time.

The following is an example of the nature of the low-pass roll-off effect.  The clip starts with a fairly moderate low-pass filter (centred around 1500Hz) that is slowly opened up until it is barely filtering the delay line.  As the filter starts out strongly attenuating, the note is quickly damped, and demonstrates a transition from:

Muted > Damped > Koto > Plucked Bass > Slap Bass > Harpsichord > Non-Realistic Model of a Resonating String.
[Examples of Simple Plucked String Synthesis with a Relatively Bright Pink Noise Excitation.]

A simple version of the patch can be downloaded here: Karplus-Strong example

Mad Catz Gametrak Mod for Max/MSP

So it seems that the Gametrak controller that is designed for use with the PS2 doesn’t want to work with Max

A number of people have tried removing the board inside the unit, replacing it with a Bitwacker or Arduino, but after looking at the board in the Gametrak, I found that there is an interesting ‘feature’ built into the existing boards.

This easter egg is probably designed so that one unit can be manufactured to be used across a variety of hardware platforms, from PS2 to PC to Xbox.

Here’s what I did to get it working:

Open the case by removing the screws marked.Open the case by removing the screws marked (I pierced the ‘feet’ with the screwdriver so that I didn’t have to re-stick them later).

Remove the board by unscrewing the screws marked.Remove the board by unscrewing the screws marked.

Flip it over to reveal the underside.Flip it over to reveal the underside.

Rotate the entire Gametrak, so that the board is oriented like this.Rotate the entire Gametrak, so that the board is oriented like this.

This is the cool bit.  Notice the PC label above?This is the cool bit.  Notice the PC label above?
(There’s also an Xbox label to the right).

I shorted this connection with a knife while it was plugged in to Max, and a burst of numbers came out of the ‘hi’ object.  To make this connection permanent*, I put a bit of solder to make a bridge between the two contact points, and now it outputs 12-bit integers on six discrete axes (left hand x, y & z; and right hand x, y, z).  The foot switch works too.

Simple Max interface for the Gametrak.Simple Max 5 interface for the Gametrak (Download)

Note: the first gen Gametrak from In2Games doesn’t seem to have this ‘feature’.

* There’s a tiny layer of lacquer on these contact points that I scratched with a knife so the solder would take to the metal.