Java 从wav文件中提取频率

Java 从wav文件中提取频率,java,fft,Java,Fft,我试图从wav文件中提取频率,但看起来好像出了问题 首先,我从文件中提取字节,然后对其应用FFT,最后找到大小 似乎我做错了什么,因为输出不接近实际值。 下面是代码 try{ File log = new File("files/log.txt"); if(!log.exists()) log.createNewFile(); PrintStream ps = new PrintStream(log); File f = ne

我试图从wav文件中提取频率,但看起来好像出了问题

首先,我从文件中提取字节,然后对其应用FFT,最后找到大小

似乎我做错了什么,因为输出不接近实际值。 下面是代码

try{

        File log = new File("files/log.txt");
        if(!log.exists()) log.createNewFile();
        PrintStream ps = new PrintStream(log);

        File f  = new File("files/5000.wav");                       
        FileInputStream fis = new FileInputStream(f);   
        int length = (int)f.length();
        length = (int)nearestPow2(length);
        double[] ibr = new double[length]; //== real
        double[] ibi = new double[length]; //== imaginary
        int i = 0;
        int l=0;
        //fis.skip(44);
        byte[] b = new byte[1024];
        while((l=fis.read(b))!=-1){
            try{

                for(int j=0; j<1024; j++){
                    ibr[i] = b[j];
                    ibi[i] = 0;
                    i++;
                }
            }catch(Exception e){}
        }

        double[] ftb = FFTBase.fft(ibr, ibi, true);
        double[] mag = new double[ftb.length/2];
        double mxMag = 0;
        long avgMg = 0;
        int reqIndex = 512; //== no need to go till end
        for(i=1;i<ibi.length; i++){
            ibr[i] = ftb[i*2];
            ibi[i] = ftb[i*2+1];
            mag[i] = Math.sqrt(ibr[i]*ibr[i]+ibi[i]*ibi[i]);
            avgMg += mag[i];
            if(mag[i]>mxMag) mxMag = mag[i];
            ps.println(mag[i]);
        }
        avgMg = avgMg/ibi.length;
        ps.println("MAx===="+mxMag);
        ps.println("Average===="+avgMg);

    }catch(Exception e){e.printStackTrace();}
试试看{
文件日志=新文件(“files/log.txt”);
如果(!log.exists())log.createNewFile();
PrintStream ps=新的PrintStream(日志);
文件f=新文件(“文件/5000.wav”);
FileInputStream fis=新的FileInputStream(f);
int length=(int)f.length();
长度=(int)最接近POW2(长度);
双精度[]ibr=新双精度[长度];//==实值
双精度[]ibi=新双精度[长度];//==虚拟
int i=0;
int l=0;
//财政司司长(44);
字节[]b=新字节[1024];
而((l=fis.read(b))!=-1){
试一试{

对于(int j=0;j提取一个频率或“音高”是不可能的,不幸的是,仅通过fft和搜索“最响亮”的频率或类似的东西。至少如果你试图从音乐信号中提取它

还有不同种类的音调。大部分乐器(如吉他或我们的声音)产生和声,这些和声由几个频率组成,这些频率遵循一定的模式

但也有一些音调只有一个峰值/频率(即口哨声)

此外,你通常必须处理信号中的噪声,而这些噪声根本不是音调。这可能是背景噪声,也可能是乐器本身产生的。例如,吉他在攻击阶段有很大的噪声部分

您可以使用不同的方法,即不同的算法来查找这些信号的基音,具体取决于其类型

如果我们停留在频域(fft)中,假设我们想要分析谐波声音,例如,
双向失配算法
,它使用统计模式匹配来查找谐波并猜测
基频
,这是我们耳朵感知为音调的频率


这里可以找到一个示例实现:此repo是coursera音频信号处理完整课程的一部分,也许这会有所帮助。

}catch(例外e){}
← 永远不要写空的catch块。你应该完全删除try/catch。如果出现问题,你将无法知道。这是出于某种目的。您好,您所说的完全正确,但我正在测试的音频文件频谱平坦,因此我怀疑其中是否有峰值。但是在代码中,我得到了价值s不是常数。哦,对不起……说实话,我不明白你说的“找到震级”是什么意思。听起来你在寻找一个单一的震级值。在我的理解中是“震级”频谱上的y轴是否与fft一致,因此频谱中的每个箱子都会有一个大小。是的,如果频谱是平线,所有点的大小都会一样吗?或者至少应该足够近?如果wav文件中有完美的静音,那么我希望所有箱子的大小都为0。但是你在pastebin上的值包含指数298、298*2和298*3处的峰值…并非100%完美,但非常接近。在我看来,这是一个谐波。谐波的频率应为
spampleRate/fftSize*298