I am working on a project using the Unity game engine, The idea of the project is that the user plays a note on a guitar (and other instruments) and the app should display the note frequency that the user played, I have found this block of code that uses Unity API to get the spectrum data based on FFT algorithm:
using UnityEngine;
public class AudioMeasureCS : MonoBehaviour
{
public float RmsValue;
public float DbValue;
public float PitchValue;
private const int QSamples = 1024;
private const float RefValue = 0.1f;
private const float Threshold = 0.02f;
float[] _samples;
private float[] _spectrum;
private float _fSample;
void Start()
{
_samples = new float[QSamples];
_spectrum = new float[QSamples];
_fSample = AudioSettings.outputSampleRate;
}
void Update()
{
AnalyzeSound();
}
void AnalyzeSound()
{
GetComponent<AudioSource>().GetSpectrumData(_spectrum, 0, FFTWindow.BlackmanHarris);
float maxV = 0;
var maxN = 0;
for (i = 0; i < QSamples; i++)
{ // find max
if (!(_spectrum[i] > maxV) || !(_spectrum[i] > Threshold))
continue;
maxV = _spectrum[i];
maxN = i; // maxN is the index of max
}
float freqN = maxN; // pass the index to a float variable
if (maxN > 0 && maxN < QSamples - 1)
{ // interpolate index using neighbours
var dL = _spectrum[maxN - 1] / _spectrum[maxN]; //This line 1
var dR = _spectrum[maxN + 1] / _spectrum[maxN]; //This line 2
freqN += 0.5f * (dR * dR - dL * dL); //This line 3
}
PitchValue = freqN * (_fSample / 2) / QSamples; // convert index to frequency //This line 4
}
}
I have tested this code and it seems it works well only if I play a pure sine wave or pure note (no harmonics).
I have a few questions:
- I don't understand the logic in the last 4 lines (theoretically) in the code which is critical, I understand that we searched the max amplitude index (maxN) but why do we need the next element and the previous element? and why it is divided by the value at index maxN, I will appreciate it if some one could give an explanation of the logic in the code.
- The code above has some issue, most of the time it shows the frequency of the harmonics and not the fundamental, for instance, if I play a string with frequency 65HZ the code returns 130 or 195, What I can do to get the fundamental frequency or all the harmonics frequencies including the fundamental frequency