所以我刚刚使用谐波积谱算法修改了我的音高计算算法。我只是好奇为什么谐波乘积频谱的解释表明您需要对数据集实施汉宁窗。在数据集上实现其他窗口函数(然后对其进行 FFT)会有什么影响?哪个 Windowing 函数实际上最适合频率检测?以下是我在代码中使用的相关方法:
/**
* Calculates the Frequency based off of the byte array,
* @param bytes The audioData you want to analyze
* @return The calculated frequency in Hertz.
*/
private int getFrequency(byte[] bytes){
double[] audioData = this.bytesToDoubleArray(bytes);
audioData = applyHanningWindow(audioData);
Complex[] complex = new Complex[audioData.length];
for(int i = 0; i<complex.length; i++){
complex[i] = new Complex(audioData[i], 0);
}
Complex[] fftTransformed = FFT.fft(complex);
//return calculateFrequency(fftTransformed);
System.out.println("Max size:" + (fftTransformed.length*getFFTBinSize(fftTransformed.length)/4));
return calculateFundamentalFrequency(fftTransformed,4);
}
private double[] applyHanningWindow(double[] data){
return applyHanningWindow(data, 0, data.length);
}
private double[] applyHanningWindow(double[] signal_in, int pos, int size)
{
for (int i = pos; i < pos + size; i++)
{
int j = i - pos; // j = index into Hann window function
signal_in[i] = (double)(signal_in[i] * 0.5 * (1.0 - Math.cos(2.0 * Math.PI * j / size)));
}
return signal_in;
}
/**
* Harmonic Product Spectrum
* @param fftData
* @param n
* @return
*/
private int calculateFundamentalFrequency(Complex[] fftData, int n){
Complex[][] data = new Complex[n][fftData.length/n];
for(int i = 0; i<n; i++){
for(int j = 0; j<data[0].length; j++){
data[i][j] = fftData[j*(i+1)];
}
}
Complex[] result = new Complex[fftData.length/n];//Combines the arrays
for(int i = 0; i<result.length; i++){
Complex tmp = new Complex(1,0);
for(int j = 0; j<n; j++){
tmp = tmp.times(data[j][i]);
}
result[i] = tmp;
}
//Calculates Maximum Magnitude of the array
double max = Double.MIN_VALUE;
int index = -1;
for(int i = 0; i<result.length; i++){
Complex c = result[i];
double tmp = c.getMagnitude();
if(tmp>max){
max = tmp;;
index = i;
}
}
return index*getFFTBinSize(fftData.length);
}