gpt4 book ai didi

Java - 估计基频的问题

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:08:23 27 4
gpt4 key购买 nike

我正在尝试从包含 1 个单词的语音录音的 .wav 文件中估计基频。

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

因此我制作了一个新的缓冲区,只包含一个 channel 。此代码实现了这一点:

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(IMIM+RERE).

这提供了一个振幅数组,我对其应用了谐波求和方法。谐波求和是指给出最高和的指数 + 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 的范围内。

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

这是图表的图像:

Amplitudes

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

回顾:我不确定的是振幅数据。这些值(value)观有意义吗?它们绘制正确吗?在搜索和声并找到基频之前,我是否需要对数据做些什么?

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

如有任何帮助或建议,我们将不胜感激。预先感谢您的帮助!

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

 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;


}

现在应该在数组audio[]中保存一个 channel 的pcm数据。

最佳答案

一些一般提示:

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

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

然后您可以计算感兴趣部分的短期 FFT,并进行调和求和。

不过,使用短期自相关函数会得到更好的结果。

其他要研究的东西:音调检测、倒谱

关于Java - 估计基频的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17746350/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com