public static double FindFundamentalFrequency_(float[] x, int sampleRate, double minFreq, double maxFreq) { float[] spectr = FftAlgorithm.Calculate(x); int usefullMinSpectr = Math.Max(0, (int)(minFreq * spectr.Length / sampleRate)); int usefullMaxSpectr = Math.Min(spectr.Length, (int)(maxFreq * spectr.Length / sampleRate) + 1); var maxMagnitude = float.NegativeInfinity; var maxIndex = -1; for (int i = usefullMinSpectr; i < usefullMaxSpectr; i++) { if (spectr[i] > maxMagnitude) { maxMagnitude = spectr[i]; maxIndex = i; } } if (maxMagnitude < 0.000_1f) { return(0); } return(maxIndex * sampleRate / (double)spectr.Length); }
/// <summary> /// Finds fundamental frequency: calculates spectrogram, finds peaks, analyzes /// and refines frequency by diff sample values. /// </summary> /// <param name="x">The sounds samples data</param> /// <param name="sampleRate">The sound sample rate</param> /// <param name="minFreq">The min useful frequency</param> /// <param name="maxFreq">The max useful frequency</param> /// <returns>Found frequency, 0 - otherwise</returns> public static double FindFundamentalFrequency(float[] x, int sampleRate, double minFreq, double maxFreq) { float[] spectr = FftAlgorithm.Calculate(x); int usefullMinSpectr = Math.Max(0, (int)(minFreq * spectr.Length / sampleRate)); int usefullMaxSpectr = Math.Min(spectr.Length, (int)(maxFreq * spectr.Length / sampleRate) + 1); // find peaks in the FFT frequency bins const int PeaksCount = 3; int[] peakIndices; peakIndices = FindPeaks(spectr, usefullMinSpectr, usefullMaxSpectr - usefullMinSpectr, PeaksCount); if (Array.IndexOf(peakIndices, usefullMinSpectr) >= 0) { // lowest usefull frequency bin shows active // looks like is no detectable sound, return 0 return(0); } // select fragment to check peak values: data offset const int verifyFragmentOffset = 0; // ... and half length of data int verifyFragmentLength = (int)(sampleRate / minFreq); // trying all peaks to find one with smaller difference value double minPeakValue = Double.PositiveInfinity; int minPeakIndex = 0; int minOptimalInterval = 0; for (int i = 0; i < peakIndices.Length; i++) { int index = peakIndices[i]; int binIntervalStart = spectr.Length / (index + 1), binIntervalEnd = spectr.Length / index; int interval; double peakValue; // scan bins frequencies/intervals ScanSignalIntervals(x, verifyFragmentOffset, verifyFragmentLength, binIntervalStart, binIntervalEnd, out interval, out peakValue); if (peakValue < minPeakValue) { minPeakValue = peakValue; minPeakIndex = index; minOptimalInterval = interval; } } if (minPeakValue < 0.000_001 || minOptimalInterval < double.Epsilon) { return(0); } return((double)sampleRate / minOptimalInterval); }