Karplus-Strong drum algorithm

260 views
Skip to first unread message

Paulo Sérgio Almeida

unread,
Jul 30, 2012, 10:29:20 AM7/30/12
to over...@googlegroups.com
Hi all,

I have implemented Karplus-Strung drum algorithm, one of the generalisations of the basic "string" algorithm described in the original paper, where a "blend" factor can be used. The original string algorithm is obtained for blend=1. The idea is that for blend=1/2, drumlike sounds are supposed to be produced, but I am not sure that what I got corresponds to it. In case someone wants to play with it, here it goes.

Regards,
Paulo

(definst drum [freq 440 dur 5 blend 0.5 gain 1]
  (let [p (- (reciprocal freq) (reciprocal (control-rate)))
        burst (* (env-gen (perc p dur :curve :step) :action FREE) (white-noise))
        y (local-in 1)
        x (delay-n y 0.1 p)
        r (- (sign (dust:ar (* blend (sample-rate)))) 0.5)
        _ (local-out (+ burst (* gain r (+ x (delay1 x)))))]
    y))

; string algorithm: blend=1
(drum 600 10 1 0.99)
(drum 400 10 1 0.98)
(drum 200 10 1 0.97)
(drum 100 10 1 0.95)
; blend=0
(drum 600 10 0 0.99)
(drum 400 10 0 0.98)
(drum 200 10 0 0.97)
(drum 100 10 0 0.95)
; blend=0.5
(drum 200 10 0.5 1)
(drum 100 10 0.5 1)
(drum 50 10 0.5 1)
; blend near 0
(drum 200 10 0.1 1)
(drum 200 10 0.04 1)
(drum 200 10 0.02 1)
(drum 200 10 0.01 1)
(drum 200 10 0.004 1)
(drum 200 10 0.002 1)
(drum 200 10 0.001 1)
; blend near 1
(drum 200 10 0.999 1)
(drum 200 10 0.998 1)
(drum 200 10 0.996 1)
(drum 200 10 0.98 1)
(drum 200 10 0.95 1)
(drum 200 10 0.9 1)

Sam Aaron

unread,
Aug 2, 2012, 9:00:52 AM8/2/12
to over...@googlegroups.com
Hey Paulo,

this KS drum is fun to play with :-) Do you have a link to the paper you were referring to? Also, if you are feeling charitable, it would be amazing to spend some time and break down this synth and explain it to people that might not have played with KS synthesis before - it would be super useful for others...

Sam

---
http://sam.aaron.name

Paulo Sérgio Almeida

unread,
Aug 2, 2012, 10:33:25 AM8/2/12
to over...@googlegroups.com

Hi Sam,

On Thursday, August 2, 2012 2:00:52 PM UTC+1, Sam Aaron wrote:
Hey Paulo,

this KS drum is fun to play with :-) Do you have a link to the paper you were referring to? Also, if you are feeling charitable, it would be amazing to spend some time and break down this synth and explain it to people that might not have played with KS synthesis before - it would be super useful for others...


The paper is the original one from Karplus and Strong:  http://users.soe.ucsc.edu/~karplus/papers/digitar.pdf
This paper is extremely readable, and explains it much better than I could attempt to.

What I can point out is something about overtone / SC that I only learnt some time after my first attempts, and that is the need to account for the extra delay incurred when one uses buses, as when one uses local-in /local-out what one writes is only read one "block" later. This means that one has to subtract that time when computing the delay corresponding to some wanted freq, as I do with:

(let [p (- (reciprocal freq) (reciprocal (control-rate)))

and this means that the highest frequencies achievable this way are somewhat low (around 680 Hz with a block of 64). I wonder if there is a better way to do things that does not incur in this limitation.

In fact, I am still confused about these things, and I don't know how many kinds of "blocks" there are, because when SC boots I see

SC_AudioDriver: sample rate = 44100.000000, driver's block size = 512

but the "block" that I mean, corresponding to control rate is 64 samples ...

Regards,
Paulo

Jeff Rose

unread,
Aug 2, 2012, 11:15:49 AM8/2/12
to over...@googlegroups.com
On Thu, Aug 2, 2012 at 3:33 PM, Paulo Sérgio Almeida
<pssal...@gmail.com> wrote:
> In fact, I am still confused about these things, and I don't know how many
> kinds of "blocks" there are, because when SC boots I see
>
> SC_AudioDriver: sample rate = 44100.000000, driver's block size = 512
>
> but the "block" that I mean, corresponding to control rate is 64 samples ...

I think there are 3 different block sizes. The audio and control rate
block sizes which are used to communicate between ugens and over
busses, and the audio driver block size. I think the audio card fires
an interrupt when it needs data to fill the DSP buffer, which calls up
to the driver, which calls up to the registered application(s)
requesting audio data. This is the driver's block size, how big of an
array it hands you to fill on each interrupt. By using larger blocks
you get more time to process in between generating blocks (without
causing an underflow), but longer latency from the time you trigger a
synth to the time you first hear it.

The worst case latency will be 1 / (sample-rate / block-size):

512 ~ 12ms
256 ~ 6ms
128 ~ 3ms

From what I've read right around 10-12ms is the point where people
with acute hearing can start perceiving the delay. In Overtone since
we are also reading in the midi values, processing a bit, and then
triggering the synth, my guess is we are probably up around 20ms
currently. With the new internal server we can manipulate all of
these configuration values pretty easily though, so it's worth
experimenting with.

-Jeff

Paulo Sérgio Almeida

unread,
Aug 2, 2012, 11:21:31 AM8/2/12
to over...@googlegroups.com
Hi again,


On Thursday, August 2, 2012 2:00:52 PM UTC+1, Sam Aaron wrote:
Hey Paulo,

this KS drum is fun to play with :-) Do you have a link to the paper you were referring to? Also, if you are feeling charitable, it would be amazing to spend some time and break down this synth and explain it to people that might not have played with KS synthesis before - it would be super useful for others...

I realised there are other maybe non-obvious things with the code ;)

Basically it tries to implement the recurrence

          /     1/2 * ( Y_{t-p} + Y_{t-p-1} )   with probability blend
Y_t =  |
          \    -1/2 * ( Y_{t-p} + Y_{t-p-1} )   with probability 1- blend

> (definst drum [freq 440 dur 5 blend 0.5 gain 1]
>   (let [p (- (reciprocal freq) (reciprocal (control-rate)))
>         burst (* (env-gen (perc p dur :curve :step) :action FREE) (white-noise))
>         y (local-in 1)
>         x (delay-n y 0.1 p)
>         r (- (sign (dust:ar (* blend (sample-rate)))) 0.5)
>         _ (local-out (+ burst (* gain r (+ x (delay1 x)))))]
>     y))


For that it uses a local bus, written with local-out, and read with local-in, uses the delay1, which delays one sample, delay-n to delay p time, and apart from that adjusting of the delay p to account for the extra control-rate delay, my main challenge was to generate values at audio-rate, either 1/2 or -1/2, with probability given by blend. (This was what my other post was about.) I ended up using

(- (sign (dust:ar (* blend (sample-rate)))) 0.5)

to produce those. The starting signal used to initiate the recurrence is a burst of white-noise of p duration, achieved with

(* (env-gen (perc p dur :curve :step) :action FREE) (white-noise)) 

which is also used to free the synth after "dur" seconds.

That "gain" parameter can be lowered a bit from 1 to make the sound decay faster. Higher values should not be used, unless a bit above 1 for blends like 0.5, that make the sound decay very fast, to try to compensate it, but very easily makes it unstable.

Hope this helps somehow,
Paulo 

Paulo Sérgio Almeida

unread,
Aug 2, 2012, 11:28:44 AM8/2/12
to over...@googlegroups.com
Hi Jeff,

thanks for the explanation. It clarified another gap I had.

Regards,
Paulo
Reply all
Reply to author
Forward
0 new messages