Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Karplus-strong algorithm in c# with Naudio

  1. Oct 16, 2014 #1
    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 (Text):

    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: Oct 17, 2014
  2. jcsd
  3. Oct 16, 2014 #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 ?
     
  4. Oct 17, 2014 #3

    Mark44

    Staff: 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 (C):

    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).
     
  5. Oct 17, 2014 #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
     
  6. Oct 17, 2014 #5

    Mark44

    Staff: Mentor

    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 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.
     
  7. Oct 17, 2014 #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 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
     
  8. Oct 17, 2014 #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
     
  9. Oct 17, 2014 #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 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: Oct 17, 2014
  10. Oct 18, 2014 #9

    Mark44

    Staff: Mentor

    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."
    The second loop fills in elements from buffer[4*N] through buffer[4 * (sampleCount/4) + 3].
    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.
     
  11. Oct 18, 2014 #10

    Mark44

    Staff: Mentor

    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.
    Please use the variable names that are in your code. There's no array named "output".
     
  12. Oct 18, 2014 #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 (Text):

    // 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: Oct 18, 2014
  13. Oct 18, 2014 #12
    also the
    Code (Text):
     
    this did not work
     
  14. Oct 18, 2014 #13

    Mark44

    Staff: Mentor

    It worked when I added them.
     
  15. Oct 18, 2014 #14
  16. Oct 18, 2014 #15

    Mark44

    Staff: Mentor

    I would be using the debugger on this, setting breakpoints to see what values are in the arrays.
     
  17. Oct 19, 2014 #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?
     
  18. Oct 19, 2014 #17
    anyone?
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: Karplus-strong algorithm in c# with Naudio
  1. C++ Digit algorithm (Replies: 10)

Loading...