private void HandleFftData(object sender, FftDataAvailableHandlerArgs e) { float[] rawFft = e.FftData; float deltaFreq = (float)AudioIn.SAMPLE_RATE / FftProcessor.FFT_LENGTH; // Operate only on frequencies through MAX_FREQ that may be involved in formants float[] newFft = rawFft.Take((int)(Analyzer.MAX_FREQ / deltaFreq + 0.5f)).ToArray(); // Normalize the fft newFft = newFft.Select(a => (float)(a / Math.Sqrt(FftProcessor.FFT_LENGTH))).ToArray(); // Negative values differ only by phase, use positive ones instead newFft = newFft.Select(a => Math.Abs(a)).ToArray(); // Remove DC component (and close to it) newFft[0] = newFft[1] = newFft[2] = 0; fft = newFft; prepareVisualization(); }
private void HandleFftData(object sender, FftDataAvailableHandlerArgs e) { float[] rawFft = e.FftData; float[] newFft = new float[fft.Length]; // Normalize and then square for power instead of amplitude for (int i = 0; i < newFft.Length; i++) { float n = rawFft[i] / (float)Math.Sqrt(FftProcessor.FFT_LENGTH); newFft[i] = n * n; } // Remove DC component (and close to it) newFft[0] = newFft[1] = newFft[2] = 0; // Remove noise in the fft with a high-pass filter float lastIn = newFft[0]; float lastOut = lastIn; float alpha = 0.96f; for (int i = 1; i < newFft.Length; i++) { float inValue = newFft[i]; float outValue = alpha * (lastOut + inValue - lastIn); lastIn = inValue; lastOut = outValue; newFft[i] = outValue; } // Z-score it, put negative values at 0. float average = newFft.Average(); float sumSquareDiffs = 0; for (int i = 0; i < newFft.Length; i++) { sumSquareDiffs += (newFft[i] - average) * (newFft[i] - average); } float stdDev = (float)Math.Sqrt(sumSquareDiffs / newFft.Length); for (int i = 0; i < newFft.Length; i++) { newFft[i] = (newFft[i] - average) / stdDev; } // Consider it noise/silence if the stdDev is too low Debug.WriteLine(stdDev); if (stdDev > 1e7) { fft = newFft; // Shift in the new fft Array.Copy(lastFfts, 1, lastFfts, 0, lastFfts.Length - 1); lastFfts[lastFfts.Length - 1] = fft; // Shift in new fundamental Array.Copy(lastFundamentals, 1, lastFundamentals, 0, lastFundamentals.Length - 1); lastFundamentals[lastFundamentals.Length - 1] = IdentifyFundamental(fft); prepareVisualization(); } else { // Shift in null and 0 values to clear out the buffer. Array.Copy(lastFfts, 1, lastFfts, 0, lastFfts.Length - 1); lastFfts[lastFfts.Length - 1] = null; Array.Copy(lastFundamentals, 1, lastFundamentals, 0, lastFundamentals.Length - 1); lastFundamentals[lastFundamentals.Length - 1] = 0; Array.Copy(lastDrawnPointsRoundness, 1, lastDrawnPointsRoundness, 0, lastDrawnPointsRoundness.Length - 1); lastDrawnPointsRoundness[lastDrawnPointsRoundness.Length - 1] = Tuple.Create(new PointF(-1, -1), 0f); // Set to not draw it updateUI(); } }