views:

267

answers:

2

I have implemented a basic Karplus-Strong algorithm.
Ringbuffer, filling with white noise, output a sample from the front and append the average of first two elements to the end and delete the first element. Repeat last to steps.

For better results and control over them I tried to implement a extended version of the algorithm.
Therefore instead of an averaging filter I need a frequency filter like a low pass filter.
My averaging filter has two inputs and one output: avg(a,b) = (a+b)/2

The sample code on the wikipedia page gives as many outputs as inputs.
http://en.wikipedia.org/wiki/Low-pass%5Ffilter

I have found other (mathematic) versions like:
http://cnx.org/content/m15490/latest/
H(z) = (1+(1/z))/2
I guess z is a complex number.

Both version have two inputs but also two outputs.
How do I get one meaningful value out of this?
Or do I have to rewrite bigger parts of the algorithm?
If thats the case where can I find a good explanation of it?

A: 

Your filter is a specialization of the Finite Impulse Response filter. You're using the moving average method to select the coefficients, using N = 1. It already is a low-pass filter.

Calculating the coefficient and order for the filter to tune it to a specific frequency response involves tricky math. Best thing to do is to use a software package to calculate the coefficients if moving average doesn't fit your bill. Matlab is the usual choice, GNU Octave is an open source option.

Hans Passant
Thanks for the response.I wasn't aware that I am already using a low pass filter.Then I need a more advanced one with parameters.Thanks for the hints to calculate the coefficient and order.I will propably use that in the future.But the current problem is the implementation of such a filter.
David R
The implementation is *very* simple: y = c0*x[0] + c1*x[1]... Setting good values for c is the hard part.
Hans Passant
Yes that is simple. Also explains why average is a low pass filter. (a+b)/2 => 0.5*a+0.5*b. Question answered and accepted. I guess high and band bass is equaly simple? If so could you also write these algorithms?
David R
A: 

Filters can expressed in a number of ways:

  1. On the complex plain, your example H(z) = (1+(1/z))/2
  2. As a filter, y[i] = h[0]*x[i] + h[1]*x[i-1] + h[2]*x[i-2] + ...
  3. In the frequency domain, Y[f] = H[f] * X[f]

The second of these is actually a convolution of the h and x arrays. This is also the easiest to understand.

The previous answer explained where to start on constructing a filter. Assuming you have your filter coefficients, the h's, then it is simply summing over the non-negative ones.

I believe I see what you are asking. Though you do not need more than one output. From the Wikipedia page the Karplus-Strong string synthesis algorithm needs a buffer of length L. If we have M filter coefficients (h) that gives an output of the form,

y[i] = x[i] + h[0]*y[i-L] + h[1]*y[i-(L+1)] + h[2]*y[i-(L+2)] + ...

The Karplus-Strong synthesis from here uses a ring buffer to hold the last L outputs, y[i-1],...,y[i-L]. This is initialised to be the x[i] noise values for i<=L; however, for i>L x[i]=0. The algorithm will be space efficient as you only store L values. The signal x[i] for i>L is just added to the ring buffer.

Finally, as a note of warning, if you are not careful with both the number of coefficients h and the values the outputs y may not have the desired behaviour.

biosonar
I know next to nothing about this stuff so maybe I implemented it wrong. I used the explanation from: http://www.cs.princeton.edu/courses/archive/fall07/cos126/assignments/guitar.html (not my homework) and according to that the ringbuffer is used as delay and feedback. Also the update step only takes two inputs.And generated audio sounds like a guitar. If you still think all values in the buffer should be used could you explain further?
David R
I was working from a glance at the paper from the [Wikipedia page][1]. It has `y[n] = x[n] + 0.5*(y[n-N] + y[n-(N+1)])` rather than `y[n] = x[n] + 0.5*(y[n-1] + y[n-2])` which is what I assumed. So you appear to be correct about the way the buffer is constructed. The princeton page also adds a decay of 0.996 to the averaging in the buffer. I don't see any reason why you cannot have more than just two elements filtered together. But your mileage will vary, so you'll have to experiment, as to what sounds best. [1] http://www.jstor.org/pss/3680063
biosonar
I have edited my answer to correct my misunderstanding.
biosonar