Java - 估算基频的问题

时间:2013-07-19 12:42:42

标签: java signal-processing fft wav

我试图估算一个.wav文件的基频,该文件包含一个单词的录音记录。

我试图做的是用audioInputStream读取文件。格式为PCM_SIGNED 44100.0 Hz,16位,立体声,4字节/帧,小端。

因此我创建了一个新的缓冲区来包含一个通道。此代码实现了:

double [] audioRight = new double[audioBytes.length/2]; 
for(int i = 0, k = 0; i <= audioBytes.length-1; i+=4, k+=2){
    audioRight[k]=audioBytes[i];
    audioRight[k+1]=audioBytes[i+1];
}

然后将数据移动到fftBuffer,这是两倍大小,然后应用DFT。使用的库是JTransform。使用的函数称为realForwardFull。

DoubleFFT_1D fftDo= new DoubleFFT_1D(audioLeft.length);
double[] fftBuffer = new double [audioLeft.length*2];

for (int i = 0; i < audioLeft.length; i++){
     fftBuffer[i] = audioLeft[i];
}
fftDo.realForwardFull(fftBuffer);

这给出了一个复数列表,我用它来计算每个复数的幅度/幅度,以便得到功率谱。

用于获得振幅幅度= sqrt(IM IM + RE RE)的公式。

这提供了我应用谐波求和方法的振幅数组。谐波求和是给出最高和的指数+3次谐波是表示基频的指数。

double top_sum = 0;
double first_index = 0;
double sum = 0;
double f_0 = 0;
double FR = audioInputStream.getFormat().getSampleRate()/2/ampBuffer.length;

for (int i = 50; i <= ampBuffer.length/4-1; i++){
sum = ampBuffer[i]+ampBuffer[i*2]+ampBuffer[i*3]+ampBuffer[i*4];
     if (top_sum < sum){
 top_sum=sum;
 first_index = i;

然而,该索引需要映射回正确的频率domnain。 据我所知,应该通过说(index / fttBuffer.length)* sampleRate。

来完成

这提供了基频的估计值。

但结果并非“正确”。我有几个不同的.wav文件要测试,其中大部分结果超出预期范围。对于相同的女性声音,三个不同的单词给出结果40,13和360.所有三个结果预计在大约250到350的范围内。

我认为导致这个问题的一些问题是幅度缓冲值。绘制时,图表不会显示任何代表和谐的清晰峰值。

这是图表的图像:

Amplitudes http://i39.tinypic.com/29wkg7.png

我知道这是很多信息,但我相信更多信息可以让您更容易理解已经完成的工作。

RECAP:我不确定的是幅度数据。这些价值观是否有意义?它们是否正确绘制?在搜索谐波并找到基频之前,我是否需要对数据做些什么?

我已经考虑过应用某种窗口,因为我怀疑泄漏可能就是为什么图表中的峰值彼此之间没有谐波的原因。

任何帮助或建议将不胜感激。 提前谢谢你的帮助!

编辑: 试图建议:

 ByteBuffer buf = ByteBuffer.wrap(audioBytes);
         buf.order(ByteOrder.LITTLE_ENDIAN);
         double[] audio = new double[audioBytes.length/2];  


         for(int i = 0; i < audioBytes.length/2; i++) {
             short s = buf.getShort();
             double mono = (double) s;
             double mono_norm = mono / 32768.0;

             audio[i]=mono_norm;


         }

现在,pcm数据的一个通道应保存在数组音频[]中。

1 个答案:

答案 0 :(得分:1)

一些一般提示:

你说你试图估计一个口语的基本频率。 “单词”由几个辅音和元音组成(或更好phonemes)。每个“元音”将具有不同的基频,并且在大多数情况下,频率甚至会在一个元音内发生变化(这会产生我们句子的“旋律”)。 Thius意味着你应该估计一个非常短的语音间隔的基本频率/音高,并确保你正在看一个元音(辅音是某种形式的噪音并具有循环分量)。

所以第一个应该是生成你的单词的谱图。

然后,您可以计算有趣部分的短期FFT,然后进行谐波求和。

然而,使用短期自相关函数可以获得更好的结果。

其他研究方法:Pitch-Detection,Cepstrum