Является ли моя Java-реализация алгоритма Harmonic Product Spectrum неправильной?
Я строил реализацию алгоритма спектра гармонического произведения для транскрипции аудио в миди для гитарных инструментов, результаты, похоже, неверны. Я использую частоту дискретизации 44100 и размер буфера от 1024 до 131072, но пока не повезло. Я использовал этот алгоритм для своего проекта, однако результаты совершенно другие по сравнению с другими детекторами основного тона, такими как YIN или MPM. Возможно, у меня есть алгоритмическая ошибка, если да, то я был бы признателен, если бы ее можно было указать и исправить.
public double getPitch(double[] audioBuffer){
int n = audioBuffer.length;
// zero-pad the data 16x
double[] fft = new double[16*n];
for(int k=0; k < n; k++){
fft[k] = audioBuffer[k];
}
//apply hanning window
fft = hanning(fft);
//apply fft
RealDoubleFFT transformer = new RealDoubleFFT(fft.length);
transformer.ft(fft);
//slice the array to get only the first half
double[] fft1 = new double[8*n];
double[]fft2 = new double[8*n];
System.arraycopy(fft, 0, fft1, 0, fft1.length);
System.arraycopy(fft, fft1.length, fft2, 0, fft2.length);
//get absolute values of the first half of fft
fft1 = getAbs(fft1);
// Downsample x2
double[] times2 = this.fft.downSample(fft1, 2);
// Downsample x3
double[] times3 = this.fft.downSample(fft1, 3);
// Calculate the Harmonic Product Spectrum
int max = this.fft.HPSMax(fft1, times2, times3, minIdx, maxIdx);
// Convert the index to frequency.
freq[0] = this.fft.indexToFrequency(RATE, fft.length, max);
return freq[0];
}
Это метод HPSMax и downsample:
public double[] downSample(double[] spectrum, int factor) {
int downsampleLength = spectrum.length / factor;
double[] d = new double[spectrum.length];
// Load the new array with the average of factor consecutive samples
// of the original. Remainder should be set to 1.
for (int i = 0; i < spectrum.length; i ++) {
if (i < downsampleLength) {
for (int j = 0; j < factor; j++) {
d[i] += spectrum[(i * factor) + j];
}
d[i] = d[i] / factor; // and average them.
} else {
d[i] = 1;
}
}
return d;
}
public int HPSMax(
double[] original, double[] times2, double[] times3, int min, int max) {
double[] d = new double[original.length];
// Calculate the product of the spectrums.
for (int i = min; i < max; i++) {
d[i] = original[i] * times2[i] * times3[i];
}
// Find the index with the highest value.
int maxIdx = 0;
for (int i = 0; i < original.length; i++) {
if (d[i] > d[maxIdx]) {
maxIdx = i;
}
}
return maxIdx;
}