vetoketju / WP-Noteradar

Pitchdetection / Notedetection application for Windows Phone
4 stars 1 forks source link

Difference function problem #1

Open skosito opened 7 years ago

skosito commented 7 years ago

Hi,

first of all, thanks for this implementation! I have one problem tho, I'm using NAudio library, and in read method I'm sending buffers of 2048 samples with sample rate of 44.1 khz to this pitch detector, and it is always returning -1 as detected pitch... The reason seems to be that in difference function line yinBuffer[tau] += delta * delta; gets added that much that yinBuffer contains all Infinity values... I changed buffer to be double instead of float, but no success. Do I do something wrong? Thank you in advance Cheers

Versette commented 2 years ago

I know that this question is quite old, but I myself just came across this project and found the YIN class quite useful. I was initially having the same issue as you, but somehow solved it (I went a bit deeper into code of the app iself etc).

What solved it was (I think) using the same byte array to float array converter as the author of this, which is:

        private static float[] bytesToFloats(byte[] bytes)
        {
            float[] floats = new float[bytes.Length / 2];
            for (int i = 0; i < bytes.Length; i += 2)
            {
                floats[i / 2] = bytes[i] | (bytes[i + 1] << 8);
            }
            return floats;
        }

But that still returns -1 sometimes (when it doesn't guess anything, probably) So what I did in my code to filter some stuff out is:

        private void RecorderOnDataAvailable(object sender, WaveInEventArgs e)
        {
            if (e.Buffer != null && e.Buffer.Length > 1 && e.BytesRecorded == e.Buffer.Length)
            {
                const int bufferSize = 2048 / 2;
                int completeSampleCount = 0;
                int currentIndex = 0;

                // Convert byte array to float array
                float[] floatBuffer = bytesToFloats(e.Buffer);
                List<float> pitchesList = new List<float>();

                // Initialize Yin
                Yin yin = new Yin(44100, bufferSize);

                // Get complete usable sample count
                completeSampleCount = Convert.ToInt32(Math.Truncate(Convert.ToDouble(floatBuffer.Length / bufferSize)));

                // Process samples
                for (int i = 0; i < completeSampleCount; i++)
                {
                    float[] partialFloatBuffer = floatBuffer.Skip(currentIndex).Take(bufferSize).ToArray();

                    var pitchResult = yin.getPitch(partialFloatBuffer);
                    var candidate = pitchResult.getPitch();
                    var confidence = pitchResult.getProbability();

                    // Filter out wrong results and add to list
                    if (candidate != -1 && confidence > 0.5 && candidate < 350 && candidate > 80)
                            pitchesList.Add(pitchResult.getPitch());

                    currentIndex += bufferSize;
                }

                // Get average pitch
                if (pitchesList.Any())
                {
                    float avgPitch = 0;
                    pitchesList.ForEach(x => avgPitch += x);
                    avgPitch /= pitchesList.Count;

                    // Write output to textbox
                    textBox3.Invoke((MethodInvoker)delegate
                    {
                        textBox3.Text = avgPitch.ToString();
                    });
                }
            }
        }

Another option for using the Yin algorithm in C# is using https://github.com/aybe/aubio.net , which I have found to be quite fast and accurate (and it also supports other kinds of Yin or even other algorithms) But I don't think that it supports byte arrays as input, I have only found ways to make it read files, which is useless for realtime applications. However, I did open an issue because of that: https://github.com/aybe/aubio.net/issues/10