栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java C#分析WAV音频文件1Khz是否有声音

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java C#分析WAV音频文件1Khz是否有声音

本文是用Java写的,C#原理一样并已经验证

最近工作需要检测设备的是否有音频输出,找了很多资料,但是关于1Khz的验证并没有多少,所以我就自己查WAV的文件格式,并手撸了代码,来检测是否1Khz有声音,也可以检测WAV是否有声音

首先,我们需要将WAV文件读出来并将它的头文件分析,关于头文件的网上有很多文章,但是都不是很全面,头文件总会多一些或少一些无关紧要的信息,导致分析出错,下面是我读取头文件的代码(get 和 set方法自行补全)

  
  public void readAudioFile(){
        String filePath = "C:\Users\1002212\Music\baiduAudio.wav";
        File file = new File(filePath);
        if(!file.exists()){
            System.out.println("文件不存在,请检查");
            return;
        }
        FileInputStream fileInputStream;
        try{
            fileInputStream = new FileInputStream(file);
            RiffFormat riffFormat = parseRiffFormat(fileInputStream);
            System.out.println(riffFormat);
            parse1KHZ(riffFormat);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

下面是分析WAV文件的主要代码 ,因为有一些信息不一定有,所以要做一些判断,下面的代码中CDsize也是不一定有的,需要自己判断下(我比较懒,就不写了),关于分析的都是些什么,可以查看RiffFormat类

  private RiffFormat parseRiffFormat(FileInputStream fileInputStream) throws Exception{
        RiffFormat riffFormat = new RiffFormat();
        riffFormat.setCkid(readByteBuffer(fileInputStream,4));
        riffFormat.setFileSize(readInt(fileInputStream));
        riffFormat.setFccType(readByteBuffer(fileInputStream,4));
        byte[] buffer = readByteBuffer(fileInputStream, 4);
        if(buffer[0]==0x66 && buffer[1]==0x6D && buffer[2]==0x74 && buffer[3]==0x20){
            riffFormat.setWaveFormat(buffer);
        } else {
            riffFormat.setUnknowChar(buffer);
            riffFormat.setUnknowChar2(readByteBuffer(fileInputStream, 32));
            riffFormat.setWaveFormat(readByteBuffer(fileInputStream,4));
        }

        riffFormat.setCkSize(readInt(fileInputStream));
        riffFormat.setwFormatTag(readShort(fileInputStream,true));
        riffFormat.setnChannels(readShort(fileInputStream,true));
        riffFormat.setnSamplesPerSec(readInt(fileInputStream));
        riffFormat.setnAvgBytesPerSec(readInt(fileInputStream));
        riffFormat.setnBlockAlign(readShort(fileInputStream,true));
        riffFormat.setwBitsPerSample(readShort(fileInputStream,true));
        riffFormat.setCbSize(readShort(fileInputStream,true));
        riffFormat.setWdid(readByteBuffer(fileInputStream,4));
        riffFormat.setWdSize(readInt(fileInputStream));
        int wdSize = riffFormat.getWdSize();
        riffFormat.setWdbuf(readByteBuffer(fileInputStream,wdSize));
        return riffFormat;
    }

下面是RiffFormat类,对应头文件的一些信息,分析出来的信息就对应下面的类

public class RiffFormat {
    byte[] ckid;	//RIFF标识
    int fileSize; //文件大小
    byte[] fccType; //WAVE标志
    byte[] unknowChar = new byte[4];
    byte[] unknowChar2 = new byte[32];
    byte[] waveFormat; //WAVE格式标志
    int CkSize; //块大小
    short wFormatTag;//音频格式一般为WAVE_FORMAT_PCM
    short nChannels;//采样声道数
    int nSamplesPerSec;//采样率
    int nAvgBytesPerSec;//每秒字节数  通道数*采样率*采样精度/8(字节位数)
    short nBlockAlign;//块大小 采样字节*声道数
    short wBitsPerSample;//采样精度 采样精度/8 = 采样字节
    short cbSize;		//预留字节 一般为0扩展域有的没有
    byte[] wdid; //data 标志
    int wdSize; //块大小
    byte[] wdbuf; //数据指针 有符号

    public RiffFormat(){}

    
    public static String byte2Ascii(byte[] byteArr){
        Charset cs = StandardCharsets.UTF_8;
        ByteBuffer bb = ByteBuffer.allocate(byteArr.length);
        bb.put(byteArr);
        bb.flip();
        CharBuffer cb = cs.decode(bb);
        return new String(cb.array());
    }
}

文件读取完了,就该来分析文件数据了,原理是先将音频文件分声道,然后读取一个声道的1秒的数据,分析其波峰是不是有1000左右(误差在15左右吧),如果不是1000再读取下一秒的数据,如果是的话就分析下一个声道

波峰计算是将声道数据拖到21长度的数组中,判断中间的数字(第10位)是否比左边和右边的数据都大,如果都大,那它是波峰无疑,如果你感觉不精确,可以将数组的长度加大,如41,但是数组的长度必须是奇数,因为好找中间数

下面就是分析音频的代码

  private void parse1KHZ(RiffFormat riffFormat){
        List points = new ArrayList<>();
        int sizeCheck = riffFormat.getnAvgBytesPerSec();
        int channel = riffFormat.getnChannels();
        short bitSample = riffFormat.getwBitsPerSample();
        byte[] content = new byte[sizeCheck];
        System.arraycopy(riffFormat.getWdbuf(),0,content,0,sizeCheck);
        short[] leftContent = new short[sizeCheck/2/2];
        short[] rightContent = new short[sizeCheck/2/2];
        int blockSize = riffFormat.getnBlockAlign();
        int blockCount = sizeCheck/blockSize;
        for(int m = 0; m < blockCount; m++){
            // https://blog.csdn.net/imxiangzi/article/details/80265978
            leftContent[m] = byteArrayToShort(new byte[]{content[m*4+1],content[m*4]});
            rightContent[m] = byteArrayToShort(new byte[]{content[m*4+3],content[m*4+2]});
        }

        int cacheLength = 21;
        System.out.println("rightContent length is " +rightContent.length);

        short[] cache = new short[cacheLength];
        for (short value : rightContent) {
            short[] cacheNew = new short[cacheLength];
            short bts = value;
            System.arraycopy(cache, 1, cacheNew, 0, cacheLength - 1);
            cacheNew[cacheLength - 1] = bts;
            try {
                boolean tp = isTerminalPoint(cacheNew);
                if (tp) {
                    points.add(cacheNew[cacheLength / 2]);
                }
                cache = cacheNew;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("右声道 *****"+points.size());

        points.clear();
        for(int i = 0; i 

好了。分析就结束了,赶紧去试试吧

参考文献:https://blog.csdn.net/imxiangzi/article/details/80265978

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/601898.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号