3

我试图从一个包含 1 个单词的语音记录的 .wav 文件中估计基频。

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

因此,我制作了一个新缓冲区以仅包含一个通道。这段代码实现了:

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);

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

用于获得幅度的公式 Amplitude=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;

然而,该索引需要映射回正确的频率域。据我了解,应该通过说 (index / fttBuffer.length)*sampleRate 来完成。

这提供了对基频的估计。

然而,结果并不“正确”。我有几个不同的 .wav 文件要测试,其中大多数文件的结果都超出了预期范围。对于相同的女性声音,三个不同的词给出的结果分别为 40、13 和 360。所有三个结果都预计在 250 到 350 的范围内。

我认为造成这种情况的一些问题是幅度缓冲区值。绘制时,该图未显示任何代表谐波的清晰峰。

这是图表的图像:

幅度

我知道这是很多信息,但我相信更多信息可以更容易理解所做的事情。

回顾:我不确定的是幅度数据。这些价值观有意义吗?他们绘制正确吗?在搜索谐波并找到基频之前,我是否需要对数据进行处理?

我考虑过应用某种窗口,因为我怀疑泄漏可能是为什么该图确实具有彼此不谐波的峰值。

任何帮助或建议将不胜感激。在此先感谢您的帮助!

编辑:作为对建议的尝试:

 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 数据保存在数组 audio[] 中。

4

1 回答 1

1

一些一般提示:

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

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

然后您可以计算感兴趣部分的短期 FFT 并继续进行谐波求和。

但是,您将使用短期自相关函数获得更好的结果。

其他要研究的东西:音高检测,倒谱

于 2015-02-07T15:21:00.053 回答