Quantcast
Channel: Hasen Judy
Viewing all articles
Browse latest Browse all 50

Very simple implementation of Karplus-Strong algorithm in coffeescript

$
0
0

I’m a bit over excited as I just managed to successfully implement Karplus-Strong’s guitar string algorithm.

http://en.wikipedia.org/wiki/Karplus-Strong_string_synthesis

The Wikipedia description was too complicated for me. I had to get the original paper and try to study it. It’s rather old and the terminology was a bit weird, so it took me a while to really understand it.

This snippet assumes you have SRATE defined somewhere (the sample rate), and that you already managed to setup the audio output and the mixer and everything else. I’m using audiodata.js to output audio using Firefox4’s Audio Data API.

The function guitar here returns a function which takes a sample index/point and returns the sample. It assumes that it will be called with all the samples sequentially, otherwise it won’t work. Something like:

signal_fn = guitar(440) # 440 being the frequency we want to sound

point = 0
while not done
    sample = signal_fn(point++)
    # output sample

Not exactly that, but something like that.

Here’s the code:

period_len = (freq) -> Math.floor (SRATE/freq)

avg = (a, b) -> (a + b) / 2

ks_noise_sample = (val) ->
    # get either val or -val with 50% chance
    if Math.random() > 0.5
        val
    else
        -val

# karplus strong algorithm
guitar = (freq) ->
    samples = period_len freq
    table = new Float32Array(samples)
    getsample = (index) ->
        point = index % samples
        if index == point
            table[point] = ks_noise_sample(1)
        else
            prev = (index - 1) % samples
            table[point] = avg(table[point], table[prev])

Note that this is coffee-script, where the last expression in a function is returned, and A = B expressions return B. So, guitar returns the getsample function, and getsample return table[point] after we calculate it.

Here’s what this does:

Fill a table of length p with random values (actually: fill it with either A or -A, with 50% chance each). Where p is the period of the signal, which is the sample_rate/frequency.

To produce samples, just keep cycling on this table. That is, to get any point t, take table[t % p].

BUT, as you loop on the table, average each two adjacent samples. That is, everytime you get table[t] (except the first time around), let table[t] be (table[t] + table[t-1]) / 2.

This causes the signal to decay overtime, or something like that.

That’s it.


Viewing all articles
Browse latest Browse all 50

Trending Articles