I tried to implement the Karplus-Strong algorithm with some of the Jaffe-Smith extensions (improve pitch, dynamics, etc). Here is the code.
When I run it with a sampleRate of 48000Hz, I get very reasonably sounding string, without any hissing, aliasing or very high frequencies.
The thing that is messing me up is that when I increase the sampleRate (to 2x, 4x), I get a hissy/high freq sound. This is a 48k example and a 192k example.
I'm pretty sure I've messed something up on my implementation, as I was learning about this while reading the papers and writing the code. So please feel free to point anything else that I may be overlooking.
If I simplify the algorithm to be only a single lowpass filter (a filter like to the one I use for the random input) with the N-delay (which, as far as I understand, is the original algorithm), it works much better (without any difference between sample rates). As soon as I add any of the modifications (like the "pitch fix" on module C), it messes up.
My current guess is that increasing the sample rate increases the available frequencies. But I don't get how they are not being filtered like all other frequencies by any of the low pass filters.
The brown noise input is not part of the original algorithm, but it was one of my many attempts to figure out what's causing those extra frequencies (I was assuming that a higher sample would imply a higher frequency noise, which would make the sound naturally higher pitched). It didn't help much, but I left it there because I thought it makes sense.
Any comments, suggestions or ideas are appreciated.
update
The modification on the Karplus-Strong are the ones described in this paper. I do a simplified version, that shows on my top level comment. The relevant parts:
Instead of using a delay of
N = round(sampleRate / freq)
we use a modifiedN
and include theC
block ($H_c$ in the paper) to compensate for the rounding and improve how close the pitch is to the desired frequency. This is the first part of the update function and thecn
line on thestep
.I also apply what the paper call "Dynamics" ($H_d$). As far as I understand it's another lowpass filter that tries to balance the energy on each partial. On the code, it's the second block of
_update
that calculatesR
and the last step of thestep
function.
If you remove those two, you get a trivial Karplus-Strong with a delay line and a lowpass filter. When I add any of them, I get a similar sound to the examples above.