Karplus-strong algorithm in c# with Naudio

• C/++/#
Mod note: Added [ code ] tags to the following code.
I wrote the karplus-strong algorithm in c# using Naudio. I plays the sound, but it does not stop. It should get to 0 and you should not hear anything.
but I code get point where it just repeats the same value over and over. so I when in and did the math but hand and I see why.
well I kind of see why
array[90] = -0.19160895
array[91] = - 0.193147987
0.996 * 0.5 * ( array[90] + array[91] ) = -0.191608954626
array[90] = -0.19160895
see is is the same number!!!
do the sound does not get to 0 and it does not stop.
array[91] = - 0.193147987
array[92] = -0.194699377
0.996 * 0.5 * ( array[91] + array[92] ) = -0.193147987
arra[91] = -0.193147987272

this is my code :
Code:
class Guitar : WaveStream
{
public  Guitar()
{
Frequency = 0;
n2 = 0;
rnd1 = new System.Random();
t = 0;
}
public double Frequency { get; set; }
public double Amplitude { get; set; }
static int n2;
public long Bufferlength { get; set; }
private long position;
float[] temp;
public override long Length { get { return Bufferlength; } }
public override WaveFormat WaveFormat { get { return WaveFormat.CreateIeeeFloatWaveFormat(44100, 2); } }
Random rnd1;
static int t;
public override int Read(byte[] buffer, int offset, int sampleCount)
{
int N = (int)(44100D/Frequency);
float sum;
if (n2 ==0)
{
temp = new float[N];
for (int i = 0; i < N; i++)
{
temp[I] = (float)(0.1 * rnd1.Next(-5, 5));
byte[] bytes = BitConverter.GetBytes(temp[I]);
buffer[i * 4 + 0] = bytes[0];
buffer[i * 4 + 1] = bytes[1];
buffer[i* 4 + 2] = bytes[2];
buffer[i * 4 + 3] = bytes[3];
}
n2 = 1;
for (int r = N; r < sampleCount / 4; r++)
{
if (t == (N-1))
t = 0;
sum = (float)(0.996 * 0.5 * (temp[t] + temp[t + 1]));
temp[t] = sum;
t++;
byte[] bytes = BitConverter.GetBytes(sum);
buffer[r * 4 + 0] = bytes[0];
buffer[r * 4 + 1] = bytes[1];
buffer[r * 4 + 2] = bytes[2];
buffer[r * 4 + 3] = bytes[3];
}
return sampleCount;
}
for (int r =0; r < sampleCount/4; r++)
{
if (t == (N-1))
t = 0;
sum = (float)(0.996 *0.5 *( temp[t] + temp[t + 1]));
temp[t] = sum;
t++;
byte[] bytes = BitConverter.GetBytes(sum);
buffer[r * 4 + 0] = bytes[0];
buffer[r * 4 + 1] = bytes[1];
buffer[r * 4 + 2] = bytes[2];
buffer[r * 4 + 3] = bytes[3];
}

return sampleCount;
}
}

Last edited by a moderator:

Answers and Replies

ok it works sometimes and sometimes it has ticks and other times i just does not stop playing
is something wrong with my random function ?

Mark44
Mentor
Your indentation isn't as helpful as it could be. Here's how I would have done it. BTW, use a [ code ] tag at the top and a [ /code ] tag (without extra spaces) to preserve your indentation.

Code:
class Guitar : WaveStream
{
public  Guitar()
{
Frequency = 0;
n2 = 0;
rnd1 = new System.Random();
t = 0;
}

public double Frequency { get; set; }
public double Amplitude { get; set; }
static int n2;
public long Bufferlength { get; set; }
private long position;
float[] temp;
public override long Length { get { return Bufferlength; } }
public override WaveFormat WaveFormat { get { return WaveFormat.CreateIeeeFloatWaveFormat(44100, 2); } }

Random rnd1;
static int t;
public override int Read(byte[] buffer, int offset, int sampleCount)
{
int N = (int)(44100D/Frequency);
float sum;
if (n2 ==0)
{
temp = new float[N];
for (int i = 0; i < N; i++)
{
temp[I] = (float)(0.1 * rnd1.Next(-5, 5));
byte[] bytes = BitConverter.GetBytes(temp[I]);
buffer[i * 4 + 0] = bytes[0];
buffer[i * 4 + 1] = bytes[1];
buffer[i* 4 + 2] = bytes[2];
buffer[i * 4 + 3] = bytes[3];
}
n2 = 1;
for (int r = N; r < sampleCount / 4; r++)
{
if (t == (N-1))
t = 0;
sum = (float)(0.996 * 0.5 * (temp[t] + temp[t + 1]));
temp[t] = sum;
t++;
byte[] bytes = BitConverter.GetBytes(sum);
buffer[r * 4 + 0] = bytes[0];
buffer[r * 4 + 1] = bytes[1];
buffer[r * 4 + 2] = bytes[2];
buffer[r * 4 + 3] = bytes[3];
}
return sampleCount;
}
for (int r =0; r < sampleCount/4; r++)
{
if (t == (N-1))
t = 0;
sum = (float)(0.996 *0.5 *( temp[t] + temp[t + 1]));
temp[t] = sum;
t++;
byte[] bytes = BitConverter.GetBytes(sum);
buffer[r * 4 + 0] = bytes[0];
buffer[r * 4 + 1] = bytes[1];
buffer[r * 4 + 2] = bytes[2];
buffer[r * 4 + 3] = bytes[3];
}
return sampleCount;
}
}
It's hard to tell what you're doing, as there is not a single comment anywhere in your code.
To answer your question about your random function - you don't have a random function. In your Guitar constructor, you have a variable named rnd1 that is an instance of the Random class, but I don't see that you are doing anything with it. You have a Guitar class member, also named rnd1, which is different from the variable of the same name in the Guitar constructor. The rnd1 variable in the Guitar constructor serves no purpose that I can see, and should probably be removed. The other rnd1 variable should be properly initialized by calling the Random() constructor.

In your Read method, you are using I (capital letter i) as an index into your temp array. That seems like a typo, since I is not declared (that I can see).

ok I do not know how the I became a capital letter it is not in my code by
and I do not understand what you mean by I should remove rn1. I only have one rnd1.

and it is a variable of the Guitar class

Mark44
Mentor
ok I do not know how the I became a capital letter it is not in my code by
and I do not understand what you mean by I should remove rn1. I only have one rnd1.

and it is a variable of the Guitar class
As for the i/I, it might have gotten changed when you copied your code. Sometimes editors automatically change "i" to "I".
As for the rnd1, you're right - there is only one. I mistakenly thought there were two separate variables.

You said this at the start of your post:
I wrote the karplus-strong algorithm in c# using Naudio. I plays the sound, but it does not stop. It should get to 0 and you should not hear anything.
but I code get point where it just repeats the same value over and over. so I when in and did the math but hand and I see why.
well I kind of see why
array[90] = -0.19160895
array[91] = - 0.193147987
0.996 * 0.5 * ( array[90] + array[91] ) = -0.191608954626
array[90] = -0.19160895
see is is the same number!!!
do the sound does not get to 0 and it does not stop.
array[91] = - 0.193147987
array[92] = -0.194699377
0.996 * 0.5 * ( array[91] + array[92] ) = -0.193147987
arra[91] = -0.193147987272
I don't understand what you're saying here. What is array? You have several array variables, temp, bytes, and buffer. Which one are you talking about?

Whatever is going wrong is probably happening in your Read() method. As already mentioned, without any comments, it's hard to comprehend what this method is supposed to be doing.

when you do the karplus-strong-algorithm, the buffer is of Size N and N = Fs/F

you randomly enter value between -0.5 - 0.5 in to the buffer of N size.
and then you start playing the sound right
and as you play the sound you add new value to the end of the buffer by doing 0.996 * 0.5 array[N+1 ] =(x[0] + x[1]) then array[N+2] = 0 .996 0.5 *( x[1] + [2]) and so on.. is that right?

or is it output[n] = x[n] + 0.998 *(0.5 *output[n - N] + 0.5* output[n-(N+1)]).
so
output[0]= x[0] + 0.990 * ( 0.5 *output[ -N] + 0.5 *output[ -N +1] )
output[0] = x[0] // there are not output[ -N] and no utput[ -N +1] so I am making them 0
is that how it should work ?
I am lost here

ok all this code here:

byte[] bytes = BitConverter.GetBytes(temp);
buffer[i *4+0]= bytes[0];
buffer[i *4+1]= bytes[1];
buffer[i*4+2]= bytes[2];
buffer[i *4+3]= bytes[3];

only writes the values from the buffer I am using for the karplus-strong algorithm to buffer that is return to play the sound.
so that buffer is not the karplus-strong algorithm buffer

the temp[t] array is the karplus-strong algorithm buffer

sampleCount is the number is sample I am returning to the be played

The very 1st for loop, only sets the circular buffer of size N to random values between -0.5 to 0.5
and then it add the save values to the buffer that will be returned to be play but it does not return them. that loop only happens once time.

the 2 for loop
start low pass filter
sum = (float)(0.996 * 0.5 * (temp[t] + temp[t + 1]));
it start writing the values to the buffer that is going to be play from the point of the filter.
then it returns the buffer that will be play after the buffer is full
then the function ends and the sound starts playing

when the function is called again
it only going to the 3rd loop
and the 3rd loop picks up where the sec loop start
that is why t is static. so it will not lose it place
the 3rd loop does the same thing the sec loop does.

Last edited:
Mark44
Mentor
sampleCount is the number is sample I am returning to the be played

The very 1st for loop, only sets the circular buffer of size N to random values between -0.5 to 0.5
and then it add the save values to the buffer that will be returned to be play but it does not return them. that loop only happens once time.
How large is the buffer that is passed to the Read() method? Your first loop fills elements buffer[0] through buffer[4*N - 1]. That is certainly larger than what you say above, "the circular buffer of size N."
btb4198 said:
the 2 for loop
start low pass filter
sum = (float)(0.996 * 0.5 * (temp[t] + temp[t + 1]));
it start writing the values to the buffer that is going to be play from the point of the filter.
then it returns the buffer that will be play after the buffer is full
then the function ends and the sound starts playing
The second loop fills in elements from buffer[4*N] through buffer[4 * (sampleCount/4) + 3].
btb4198 said:
when the function is called again
it only going to the 3rd loop
and the 3rd loop picks up where the sec loop start
that is why t is static. so it will not lose it place
the 3rd loop does the same thing the sec loop does.
Since the 3rd loop does the same thing that the 2nd loop does, you could probably change your logic so that the 3rd loop isn't needed.

Mark44
Mentor
when you do the karplus-strong-algorithm, the buffer is of Size N and N = Fs/F

you randomly enter value between -0.5 - 0.5 in to the buffer of N size.
and then you start playing the sound right
and as you play the sound you add new value to the end of the buffer by doing 0.996 * 0.5 array[N+1 ] =(x[0] + x[1]) then array[N+2] = 0 .996 0.5 *( x[1] + [2]) and so on.. is that right?
I don't see how you can add a new value to the end of the buffer. You're at the end of the buffer, so once you're there, you have to start overwriting values at the beginning of the buffer. That's what a circular buffer is all about.
btb4198 said:
or is it output[n] = x[n] + 0.998 *(0.5 *output[n - N] + 0.5* output[n-(N+1)]).
so
output[0]= x[0] + 0.990 * ( 0.5 *output[ -N] + 0.5 *output[ -N +1] )
output[0] = x[0] // there are not output[ -N] and no utput[ -N +1] so I am making them 0
is that how it should work ?
I am lost here
Please use the variable names that are in your code. There's no array named "output".

ok using this:
http://www.cs.sfu.ca/~tamaras/project468_odemiral/
and this
http://en.wikipedia.org/wiki/Karplus–Strong_string_synthesis#Refinements_to_the_algorithm
i re did my code:
Code:
// buffer size is 52920 and so is sampleCount
// oddset is 0
public override int Read(byte[] buffer, int offset, int sampleCount)
{
// Bufferlength set to the min I want the sound to play for
if (n3 >= Bufferlength)
{
Dispose(); // stop playing
return 0; // stop playing
}

int N = (int)(44100D / Frequency); // size of buffer for the karplus-strong algorithm
float sum;// temp holding place
// below only happens once
// it make the karplus-strong algorithm buffer
if (n2 ==0) // flag
{
X = new float[N];
for (int i = 0; i < N; i++)
{
X[I] = (float)(0.1 * rnd1.Next(-5, 5));// random number from -0.5 - 0.5
}
n2 = 1; // flag

}
// karplus-strong algorithm low pass filer
for (int r =0; r < sampleCount/4; r++)
{
if (t == (N-1))
t = 0;
sum = (float)(X[t] + ((temp1 + temp2) * 0.5 * 0.996));// low pass filter and decay factor of 0,996
temp2 = temp1; // n
temp1 = sum; // n + 1
t++; // counter this is a  static  counter
// send sum to the butter that so it can be played later
byte[] bytes = BitConverter.GetBytes(sum);
buffer[r * 4 + 0] = bytes[0];
buffer[r * 4 + 1] = bytes[1];
buffer[r * 4 + 2] = bytes[2];
buffer[r * 4 + 3] = bytes[3];
n3++;
}

return sampleCount;// end of Read sound start playing now
}
but is still do not sound right, in fact it sound worse
I wrote comments this time

Last edited by a moderator:
also the
Code:
this did not work

Mark44
Mentor
also the
Code:
this did not work
It worked when I added them.

Mark44
Mentor
I would be using the debugger on this, setting breakpoints to see what values are in the arrays.

I do not think you understand what I am asking. The code work for how I think the Karplus-Strong Algorithm work from what I read on this page:
http://www.cs.sfu.ca/~tamaras/project468_odemiral/
but the sound is not right. so I am thinking i might be not understanding how the Karplus-Strong Algorithm should work.
That is what i am asking
did I set the code up the way the Karplus-Strong Algorithm should be??
is that page right?

anyone?