I found this reddit post regarding an alternative to the karplus-strong algorithm to generate string sounds. But the snippet provided is in javascript. I tried implementing it in pd but am having a tough time transferring all the JS idioms into pd. Kindly help. Also, please skip the suggestion of using [expr].
-
Karplus-Strong alternative help
-
First problem: The algorithm as shown can handle only frequencies that are an integer division of the sample rate. If
len = Math.floor(...)
then len must be whole-number-valued. This makes sense for a buffer length. But, what if you're running at 44.1 kHz and you want 440 Hz? Wavelength = sr / frequency so len = floor(44100 / 440) = 100 but this will really produce 441 Hz. For 440 Hz, you would need to loop over 100.22727272727 samples.I'd suggest that a synthesis algorithm incapable of producing 440 Hz is at best flawed.
Second problem: JS sample-by-sample DSP and Pd unit generators are completely different languages. A literal translation is likely to be extremely clumsy (as you've already found). The key is to understand the concepts, and reimplement those in a Pd-idiomatic way.
-
Looped buffer of noise: Fill an array with bipolar noise, then use [phasor~] --> [*~ buffer length] --> [+~ 1] --> [tabread4~]. The phasor~ and tabread4~ should handle the interpolation necessary for fractional wavelengths.
-
The gaussFilter function appears to be a straightforward first-order IIR but the author said "any other lowpass filter will work too." This means you could get a valid result with a [vcf~] (use the right outlet for lowpass) where the filter frequency comes from an envelope (the author says "the cutoff should decrease sharply at first, then more slowly over time")... and you could do this in 3 minutes, vs however long your screenshot took.
If you really want to try to replicate this exact filter using Pd objects: An IIR filter requires single-sample feedback. There's no way around that. In Pd, this is [fexpr~]. [fexpr~] is often counterindicated because it's slow, but it's the one way I know to get the
prevs[i]
from the JS code.hjh
-
-
I would do the looped-noise part like this (array = 2000 samples for frequencies down to 20-something Hz). The filter is up to you.
hjh
-
if you want to generate the same envelope for the filter you can use
[rpole~ 1] period in samples*4 | / [/~ 1] | [sqrt~]
(period in samples*4 goes to right inlet of
[/~ ]
)
when you start a new note, clear the[rpole~]
and send it another[1 (
-
i dont see how this would be a different principle than K/S, except that you can´t tune it correctly, because the reading is not interpolated.
-
but this will really produce 441 Hz.
For 440 Hz, you would need to loop over 100.22727272727 samples.441... minus the delay of the lowpass filter.
-
@Obineg said:
441... minus the delay of the lowpass filter.
If you're producing the oscillation by a feedback delay, then you need to account for block delay and any phase shifting in the filter, sure.
But, at 44.1 kHz, the wavelength of 440 Hz is 100.227272727..., no matter what technique is used.
The alternate-KS technique in the first post doesn't use a feedback delay line with an embedded filter, so filter delay wouldn't enter into it. (And it isn't hard to do it with interpolation, as in my earlier post.)
hjh