Karplus-strong algorithm in c# with Naudio

In summary: Bufferlength) position = 0; } public override void Write(byte[] buffer, int offset, int sampleCount) { if (n2 ==0) { temp = new float[N]; for (int i = 0
  • #1
btb4198
572
10
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:
Technology news on Phys.org
  • #2
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 ?
 
  • #3
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).
 
  • #4
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
 
  • #5
btb4198 said:
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.
 
  • #6
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 into 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
 
  • #7
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
 
  • #8
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 playingwhen 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:
  • #9
btb4198 said:
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.
 
  • #10
btb4198 said:
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 into 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".
 
  • #11
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:
  • #12
also the
Code:
this did not work
 
  • #13
btb4198 said:
also the
Code:
this did not work
It worked when I added them.
 
  • #15
I would be using the debugger on this, setting breakpoints to see what values are in the arrays.
 
  • #16
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?
 
  • #17
anyone?
 

What is the Karplus-Strong algorithm?

The Karplus-Strong algorithm is a digital signal processing technique used for creating realistic sounding plucked string instrument sounds. It is based on the physical modeling of a vibrating string and uses a delay line and a feedback loop to create a rich and complex sound.

How does the Karplus-Strong algorithm work?

The Karplus-Strong algorithm starts by creating a buffer of random noise, which is then filtered through a low pass filter to create a plucked string sound. The output of the filter is fed back into the buffer, creating a loop that simulates the vibrations of a string. This process is repeated in real-time, creating a sustained sound that can be manipulated by adjusting the parameters of the algorithm.

What is the role of NAudio in implementing the Karplus-Strong algorithm in C#?

NAudio is a popular audio library for .NET that provides a set of tools for working with audio in C#. It includes functions for creating and manipulating audio buffers, applying filters, and playing back audio. NAudio makes it easier to implement the Karplus-Strong algorithm in C# by providing the necessary tools and functions for working with audio signals.

What are the advantages of using the Karplus-Strong algorithm in C# with NAudio?

One of the main advantages of using the Karplus-Strong algorithm in C# with NAudio is the flexibility it offers. NAudio allows for easy manipulation of the algorithm's parameters, making it possible to create a wide range of realistic string instrument sounds. Additionally, NAudio's efficient processing capabilities make it suitable for real-time applications such as audio synthesis and effects.

Can the Karplus-Strong algorithm in C# with NAudio be used for other purposes besides creating string instrument sounds?

While the Karplus-Strong algorithm was originally designed for creating string instrument sounds, it has been adapted for use in other applications as well. With NAudio, the algorithm can be used for various audio synthesis and processing tasks, such as creating percussion sounds or generating unique sound effects. Its versatility makes it a valuable tool for any audio engineer or musician.

Similar threads

  • Programming and Computer Science
Replies
21
Views
1K
  • Programming and Computer Science
Replies
16
Views
8K
  • Programming and Computer Science
Replies
3
Views
1K
Replies
1
Views
1K
  • Programming and Computer Science
Replies
5
Views
2K
  • Electrical Engineering
Replies
1
Views
2K
  • Programming and Computer Science
Replies
2
Views
2K
  • Programming and Computer Science
Replies
5
Views
4K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
2
Views
1K
Back
Top