public void freqSTFT(object threadID)
        {
            int id    = (int)threadID;
            int start = id * blockSize;
            int end   = Math.Min(start + blockSize, size - 1);

            Complex[] temp    = new Complex[wSamp];
            Complex[] tempFFT = new Complex[wSamp];

            for (int ii = start; ii < end; ii++)
            {
                for (int jj = 0; jj < wSamp; jj++)
                {
                    temp[jj] = xx[ii * (wSamp / 2) + jj];
                }

                tempFFT = FastFourierTransform.IterativeFFT(temp, wSamp, twiddles);

                for (int kk = 0; kk < wSamp / 2; kk++)
                {
                    Y[kk][ii] = (float)Complex.Abs(tempFFT[kk]);

                    if (Y[kk][ii] > fftMax)
                    {
                        fftMax = Y[kk][ii];
                    }
                }
            }
        }
        private void onsetDetection()
        {
            noteStarts = new List <int>(100);
            noteStops  = new List <int>(100);
            lengths    = new List <int>(100);
            pitches    = new List <double>(100);

            SolidColorBrush sheetBrush = new SolidColorBrush(Colors.Black);
            SolidColorBrush ErrorBrush = new SolidColorBrush(Colors.Red);
            SolidColorBrush whiteBrush = new SolidColorBrush(Colors.White);

            HFC = new float[stftRep.timeFreqData[0].Length];

            Parallel.For(0, stftRep.wSamp / 2, new ParallelOptions
            {
                MaxDegreeOfParallelism = numThreads
            }, ii =>
            {
                for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
                {
                    HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
                }
            });

            float maxi = HFC.Max();

            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                HFC[jj] = (float)Math.Pow((HFC[jj] / maxi), 2);
            }

            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                if (starts > stops)
                {
                    if (HFC[jj] < 0.001)
                    {
                        noteStops.Add(jj * ((stftRep.wSamp - 1) / 2));
                        stops = stops + 1;
                    }
                }
                else if (starts - stops == 0)
                {
                    if (HFC[jj] > 0.001)
                    {
                        noteStarts.Add(jj * ((stftRep.wSamp - 1) / 2));
                        starts = starts + 1;
                    }
                }
            }

            if (starts > stops)
            {
                noteStops.Add(waveIn.data.Length);
            }

            // DETERMINES START AND FINISH TIME OF NOTES BASED ON ONSET DETECTION

            for (int ii = 0; ii < noteStops.Count; ii++)
            {
                lengths.Add(noteStops[ii] - noteStarts[ii]);
            }

            Complex[][] yArrays       = new Complex[lengths.Count][];
            Complex[][] twiddleArrays = new Complex[lengths.Count][];
            Complex[]   twiddle;

            for (int mm = 0; mm < lengths.Count; mm++)
            {
                int nearest = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
                twiddle = new Complex[nearest];

                Parallel.For(0, nearest, new ParallelOptions
                {
                    MaxDegreeOfParallelism = numThreads
                }, ll =>
                {
                    double a    = 2 * pi * ll / nearest;
                    twiddle[ll] = Complex.Pow(Complex.Exp(-i), (float)a);
                });

                twiddleArrays[mm] = twiddle;
            }

            Parallel.For(0, lengths.Count, new ParallelOptions
            {
                MaxDegreeOfParallelism = numThreads
            }, mm =>
            {
                int nearest     = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
                Complex[] compX = new Complex[nearest];

                for (int kk = 0; kk < nearest; kk++)
                {
                    if (kk < lengths[mm] && (noteStarts[mm] + kk) < waveIn.wave.Length)
                    {
                        compX[kk] = waveIn.wave[noteStarts[mm] + kk];
                    }
                    else
                    {
                        compX[kk] = Complex.Zero;
                    }
                }

                yArrays[mm] = FastFourierTransform.IterativeFFT(compX, nearest, twiddleArrays[mm]);
            });

            for (int mm = 0; mm < lengths.Count; mm++)
            {
                int nearest = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
                absY = new double[nearest];

                double maximum = 0;
                int    maxInd  = 0;

                for (int jj = 0; jj < yArrays[mm].Length; jj++)
                {
                    absY[jj] = yArrays[mm][jj].Magnitude;
                    if (absY[jj] > maximum)
                    {
                        maximum = absY[jj];
                        maxInd  = jj;
                    }
                }

                for (int div = 6; div > 1; div--)
                {
                    if (maxInd > nearest / 2)
                    {
                        if (absY[(int)Math.Floor((double)(nearest - maxInd) / div)] / absY[(maxInd)] > 0.10)
                        {
                            maxInd = (nearest - maxInd) / div;
                        }
                    }
                    else
                    {
                        if (absY[(int)Math.Floor((double)maxInd / div)] / absY[(maxInd)] > 0.10)
                        {
                            maxInd = maxInd / div;
                        }
                    }
                }

                if (maxInd > nearest / 2)
                {
                    pitches.Add((nearest - maxInd) * waveIn.SampleRate / nearest);
                }
                else
                {
                    pitches.Add(maxInd * waveIn.SampleRate / nearest);
                }
            }

            musicNote[] noteArray;
            noteArray = new musicNote[noteStarts.Count()];

            for (int ii = 0; ii < noteStarts.Count(); ii++)
            {
                noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
            }

            int[] sheetPitchArray = new int[sheetmusic.Length];
            int[] notePitchArray  = new int[noteArray.Length];

            for (int ii = 0; ii < sheetmusic.Length; ii++)
            {
                sheetPitchArray[ii] = sheetmusic[ii].pitch % 12;
            }

            for (int jj = 0; jj < noteArray.Length; jj++)
            {
                notePitchArray[jj] = noteArray[jj].pitch % 12;
            }

            string[] alignedStrings = new string[2];

            alignedStrings = stringMatch(sheetPitchArray, notePitchArray);

            musicNote[] alignedStaffArray = new musicNote[alignedStrings[0].Length / 2];
            musicNote[] alignedNoteArray  = new musicNote[alignedStrings[1].Length / 2];
            int         staffCount        = 0;
            int         noteCount         = 0;

            for (int ii = 0; ii < alignedStrings[0].Length / 2; ii++)
            {
                if (alignedStrings[0][2 * ii] == ' ')
                {
                    alignedStaffArray[ii] = new musicNote(0, 0);
                }
                else
                {
                    alignedStaffArray[ii] = sheetmusic[staffCount];
                    staffCount++;
                }

                if (alignedStrings[1][2 * ii] == ' ')
                {
                    alignedNoteArray[ii] = new musicNote(0, 0);
                }
                else
                {
                    alignedNoteArray[ii] = noteArray[noteCount];
                    noteCount++;
                }
            }

            // STAFF TAB DISPLAY

            Ellipse[] notes;
            Line[]    stems;
            notes = new Ellipse[alignedNoteArray.Length];
            stems = new Line[alignedNoteArray.Length];
            SolidColorBrush myBrush = new SolidColorBrush(Colors.Green);

            RotateTransform rotate = new RotateTransform(45);

            for (int ii = 0; ii < alignedNoteArray.Length; ii++)
            {
                //noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
                //System.Console.Out.Write("Note " + (ii + 1) + ": \nDuration: " + noteArray[ii].duration / waveIn.SampleRate + " seconds \nPitch: " + Enum.GetName(typeof(musicNote.notePitch), (noteArray[ii].pitch) % 12) + " / " + pitches[ii] + "\nError: " + noteArray[ii].error * 100 + "%\n");
                notes[ii]                 = new Ellipse();
                notes[ii].Tag             = alignedNoteArray[ii];
                notes[ii].Height          = 20;
                notes[ii].Width           = 15;
                notes[ii].Margin          = new Thickness(ii * 30, 0, 0, 0);
                notes[ii].LayoutTransform = rotate;
                notes[ii].MouseEnter     += DisplayStats;
                notes[ii].MouseLeave     += ClearStats;
                stems[ii]                 = new Line();
                stems[ii].StrokeThickness = 1;
                stems[ii].X1              = ii * 30 + 20;
                stems[ii].X2              = ii * 30 + 20;
                stems[ii].Y1              = 250 - 10 * alignedNoteArray[ii].staffPos;
                stems[ii].Y2              = 250 - 10 * alignedNoteArray[ii].staffPos - 40;
                notes[ii].Fill            = ErrorBrush;
                notes[ii].StrokeThickness = 1;
                stems[ii].Stroke          = ErrorBrush;


                Canvas.SetTop(notes[ii], (240 - 10 * alignedNoteArray[ii].staffPos));
                if (alignedNoteArray[ii].flat)
                {
                    System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
                    flat.Content    = "b";
                    flat.FontFamily = new FontFamily("Mistral");
                    flat.Margin     = new Thickness(ii * 30 + 15, 0, 0, 0);
                    Canvas.SetTop(flat, (240 - 10 * alignedNoteArray[ii].staffPos));
                    noteStaff.Children.Insert(ii, flat);
                }

                noteStaff.Children.Insert(ii, notes[ii]);
                noteStaff.Children.Insert(ii, stems[ii]);
            }

            Ellipse[]   sheetNotes;
            Rectangle[] timeRect;
            Line[]      sheetStems;
            sheetNotes = new Ellipse[alignedStaffArray.Length];
            sheetStems = new Line[alignedStaffArray.Length];
            timeRect   = new Rectangle[2 * alignedStaffArray.Length];

            Fline.Width     = alignedStaffArray.Length * 30;
            Dline.Width     = alignedStaffArray.Length * 30;
            Bline.Width     = alignedStaffArray.Length * 30;
            Gline.Width     = alignedStaffArray.Length * 30;
            Eline.Width     = alignedStaffArray.Length * 30;
            noteStaff.Width = alignedStaffArray.Length * 30;

            for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            {
                sheetNotes[ii]                 = new Ellipse();
                sheetNotes[ii].Tag             = alignedStaffArray[ii];
                sheetNotes[ii].Height          = 20;
                sheetNotes[ii].Width           = 15;
                sheetNotes[ii].Margin          = new Thickness(ii * 30, 0, 0, 0);
                sheetNotes[ii].LayoutTransform = rotate;
                sheetNotes[ii].MouseEnter     += DisplayStats;
                sheetNotes[ii].MouseLeave     += ClearStats;
                sheetStems[ii]                 = new Line();
                sheetStems[ii].StrokeThickness = 1;
                sheetStems[ii].X1              = ii * 30 + 20;
                sheetStems[ii].X2              = ii * 30 + 20;
                sheetStems[ii].Y1              = 250 - 10 * alignedStaffArray[ii].staffPos;
                sheetStems[ii].Y2              = 250 - 10 * alignedStaffArray[ii].staffPos - 40;

                sheetNotes[ii].Fill            = sheetBrush;
                sheetNotes[ii].StrokeThickness = 1;
                sheetStems[ii].Stroke          = sheetBrush;


                Canvas.SetTop(sheetNotes[ii], (240 - 10 * alignedStaffArray[ii].staffPos));
                if (alignedStaffArray[ii].flat)
                {
                    System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
                    flat.Content    = "b";
                    flat.FontFamily = new FontFamily("Mistral");
                    flat.Margin     = new Thickness(ii * 30 + 15, 0, 0, 0);
                    Canvas.SetTop(flat, (240 - 10 * alignedStaffArray[ii].staffPos));
                    noteStaff.Children.Insert(ii, flat);
                }
                noteStaff.Children.Insert(ii, sheetNotes[ii]);
                noteStaff.Children.Insert(ii, sheetStems[ii]);
            }

            // FOR TIMING ERROR RECTANGLES
            for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            {
                timeRect[ii]        = new Rectangle();
                timeRect[ii].Fill   = sheetBrush;
                timeRect[ii].Height = 10 * alignedStaffArray[ii].duration * 4 * bpm / (60 * waveIn.SampleRate);
                timeRect[ii].Width  = 15;
                timeRect[ii].Margin = new Thickness(ii * 30 + 5, 0, 0, 0);

                Canvas.SetTop(timeRect[ii], 200);

                noteStaff.Children.Insert(ii, timeRect[ii]);
            }

            for (int ii = alignedStaffArray.Length; ii < alignedStaffArray.Length + alignedNoteArray.Length; ii++)
            {
                timeRect[ii]        = new Rectangle();
                timeRect[ii].Fill   = ErrorBrush;
                timeRect[ii].Height = 10 * alignedNoteArray[ii - alignedStaffArray.Length].duration * 4 * bpm / (60 * waveIn.SampleRate);
                timeRect[ii].Width  = 10;
                timeRect[ii].Margin = new Thickness((ii - alignedStaffArray.Length) * 30 + 5, 0, 0, 0);

                Canvas.SetTop(timeRect[ii], 200);
                noteStaff.Children.Insert(ii, timeRect[ii]);
            }
        }