Karplus Strong implementation


#1

Im looking at implementing Karplus Strong on Axoloti, and thought it might be interesting to discuss it here to learn a bit more about patching axoloti.

so the basic algorithm is described well here: https://en.wikipedia.org/wiki/Karplus–Strong_string_synthesis

There is also an implementation in the axoloti tutorials, but Id like to refine this... as it diverges from the above explanation in a couple of ways.

a) the noise burst should theoretically be N samples, i.e. its controlled by the pitch. rather than be under users control
b) the damping is handed by a 1 pole low pass filter.

but really the main reason I'm doing this is for my own 'education' ... and perhaps others may learn too.

I see this as a two part process
a) understanding the tutorial patch fully... and the objects it uses
b) creating a new patch, with the changes mentioned above.


#2

Ok, so first lets dig into the tutorial patch.

basically, it create a noise burst, controlled by a VCA, which writes into the delay buffer, and also out to the output.

the feedback loop is where it gets interesting...
working 'backwards' we can see it reads the delay line (using linear interpolation), and thats mixed in, sent to the output, and written back into the buffer. (hence the feedback loop)

at the start of this chain, we can see that delay/mtod is used to calculate the length of the delay line used (its a % of the buffer size, determined in the write object)... and then uses linear interpolation to go from k-rate to audio rate.

ok, this basically makes sense... but the bits I'm still investigating are:
- the mtod tuning reference... my assumption is this has to be configured so that it matches the delay buffer specified in delay write BECAUSE the delay time is a function of frequency but the input for delay read is a % (actually a ratio, but equiv for discussion purposes) of the buffer. BUT in practice if I tune this with a tuner, I don't see the numbers I expect.
- maths/-c not sure what this is for, it could be an offset to allow for feedback sample, but its unclear, and seems to make little difference in practice when i tested with a tuner.
- conv/interp is this required? I think this is only required if the pitch changes over time e.g. a pitch bend? otherwise pitch is constant, so no interp required. or perhaps its just 'tidier' to do this when going from k-rate to s-rate.

the main area of investigation is my understanding of MtoD and the tuning reference and how it relates to the buffer size in write... and ensuring that the resulting output is correctly tuned
(a bit concerning there is a comment that there is a bug in the tuning reference... hopefully if I figure this out, then I can 'fix it' smile )


Help making a pitch shifter
#3

Basically mtod does not compensate for the one-buffer (16 audio samples) implicit delay caused by the feedback connection. And it cannot do that properly, since the delay line length is selectable in the delay/write object, while the delay time unit of the delay/read object is in fractions of the full delay time. The mtod object does not have a reference to that object.


#4

So in the Karplus Strong tutorial patch, there is a delay line of 2048 samples allocated.
mtod will outlet the relative delay time modulation, but because of the one-buffer delay the effective delay time is 16 samples longer. Doing -0.5(/64) compensates that since 2048*-0.5/64=-16 samples.
After this compensation the delay line pitch is chromatic.

Still, the mtod tuning reference is off. That is an easy bugfix.


#5

a bug in the mtod (axo) object?

the -c I had wondered if it was that, forgot that the buffer was 16 samples, but makes perfect sense now smile


#6

has this been fixed now?


#7

still sounds a little out of tune on mine, but maybe someone has remedied this by now?


#8

Reviving this conversation since it doesn't look to be over; the tutorial still mentions a potential bug. Here is my take on this problem.
The tuning reference also depends on the length of the delay line: correct scaling is "662.65194 divided by the number of samples in the delay line".
Here is a version of the patch with the correct scaling, as well as an object that takes the length of the delay line as an attribute. If the idea of "delay/mtod" is to include the scaling inside the object, then maybe this is a possible implementation.
Thanks for any comment on the code, I hope someone with more experience can make it more efficient if possible.
20_karplus_strong-fix.axp (8.3 KB)


#9

I think there is still some tuning issues. I just uploaded in contrib my patch based on tutorial, harpsimono. Maybe you could try it out.


#10

Thanks @janifr!
Indeed, it looks like we have to subtract 17 samples, not 16 samples, to account for the feedback loop. This is what you achieve with your additional "-0.03".
I updated my code, which is compatible with various delay line lengths:
20_karplus_strong-fix-02.axp (6.2 KB)


#11

I was just watching the "Bela" video with its karplus-strong instrument and correctly figured someone was doing it for Axo: right out of the box we have two audio-rate inputs that could drive such an implementation in two voices (or, two trigger sources that could drive X many voices in turn, like the 'Pluck' eurorack module)

It does seem like tuning issues could relate to the sample rate: at high frequencies the tuning granularity would get increasingly worse. Oversampling would help :slight_smile:


#12

About the 16 samples issue. I think this can be bypassed by hardcoding everything into the object, no? Feedback created internally in the object should fix the 16 samples issue as far as I know and right tuning should be possible without too much "after math" :slight_smile:


#13

Couldn't help it :slight_smile:

Here is my version of karplus strong. To me the tuning seems correct for all octaves.
I hacked MTOF object instead of using MTOD. I do have to offset the pitch with -4, but after that it seems correct. But I might have missed something, I dunno:

Karplus 1.3 FOR COM .axp (12.2 KB)

(Okay, routing is not correct here, but pitch seems to be)