本文是用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));buffer = readByteBuffer(fileInputStream, 2);if(buffer[0] == 0x66 && buffer[1] == 0x61){//如果是factbyte[] bufferFactEnd = readByteBuffer(fileInputStream, 2);byte[] bufferFact = new byte[4];bufferFact[0] = buffer[0];bufferFact[1] = buffer[1];bufferFact[2] = bufferFactEnd[0];bufferFact[3] = bufferFactEnd[1];riffFormat.setwFact(bufferFact);riffFormat.setnFactDataLength(readInt(fileInputStream));riffFormat.setwFactData(readByteBuffer(fileInputStream, riffFormat.getnFactDataLength()));buffer = readByteBuffer(fileInputStream,4);} else if(buffer[0] == 0x64 && buffer[1] == 0x61){// 如果是databyte[] bufferDataEnd = readByteBuffer(fileInputStream, 2);byte[] bufferData = new byte[4];bufferData[0] = buffer[0];bufferData[1] = buffer[1];bufferData[2] = bufferDataEnd[0];bufferData[3] = bufferDataEnd[1];buffer = bufferData;} else{byte CbSize0 = buffer[0];buffer[0] = buffer[1];buffer[1] = CbSize0;short CbSize = byteArrayToShort(buffer);riffFormat.setCbSize(CbSize);buffer = readByteBuffer(fileInputStream,4);if(buffer[0] == 0x66 && buffer[1] == 0x61 && buffer[2] == 0x63 && buffer[3] == 0x74){//如果是factriffFormat.setwFact(buffer);riffFormat.setnFactDataLength(readInt(fileInputStream));riffFormat.setwFactData(readByteBuffer(fileInputStream, riffFormat.getnFactDataLength()));buffer = readByteBuffer(fileInputStream,4);}}riffFormat.setWdid(buffer);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_PCMshort nChannels;//采样声道数int nSamplesPerSec;//采样率int nAvgBytesPerSec;//每秒字节数  通道数*采样率*采样精度/8(字节位数)short nBlockAlign;//块大小 采样字节*声道数short wBitsPerSample;//采样精度 采样精度/8 = 采样字节short cbSize;      //预留字节 一般为0扩展域有的没有byte[] wdid; //data 标志int wdSize; //块大小byte[] wdbuf; //数据指针 有符号byte[] wFact; //Fact 标志int nFactLength; //Fact数据块的长度byte[] wFactData;   // Fact数据块@Overridepublic String toString() {return "ckid=" + byte2Ascii(ckid) + "\n" +"fileSize=" + fileSize + "\n" +"fccType=" + byte2Ascii(fccType) + "\n" +"unknowChar=" + Arrays.toString(unknowChar) + "\n" +"unknowChar2=" + Arrays.toString(unknowChar2) + "\n" +"waveFormat=" + byte2Ascii(waveFormat) + "\n" +"CkSize=" + CkSize + "\n" +"wFormatTag= " + wFormatTag + "\n" +"nChannels= " + nChannels + "\n" +"nSamplesPerSec=" + nSamplesPerSec + "\n" +"nAvgBytesPerSec=" + nAvgBytesPerSec + "\n" +"nBlockAlign= " + nBlockAlign + " Byte\n" +"wBitsPerSample= " + wBitsPerSample + " Bit\n" +"cbSize=" + cbSize + "\n" +"wFact=" + (wFact==null?"":byte2Ascii(wFact)) + "\n" +"nFactLength=" + nFactLength + "\n" +"wFactData=" + (wFactData==null?"":Arrays.toString(wFactData)) + "\n" +"wdid=" + byte2Ascii(wdid) + "\n" +"wdSize=" + wdSize + "\n";}/*** byte转Ascii码*/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<Integer> points = new ArrayList<>();int sizeCheck = riffFormat.getnAvgBytesPerSec();int channel = riffFormat.getnChannels();byte[] content = new byte[sizeCheck];System.arraycopy(riffFormat.getWdbuf(),0,content,0,sizeCheck);int bitPerSample = riffFormat.getwBitsPerSample();int blockSize = riffFormat.getnBlockAlign();int[][] audioData = new int[channel][sizeCheck/channel/(bitPerSample/8)];int blockCount = sizeCheck/blockSize;for(int m = 0; m < blockCount; m++){for(int ch = 0 ; ch < channel ; ch ++) {// https://blog.csdn.net/imxiangzi/article/details/80265978if(bitPerSample == 16) {audioData[ch][m] = byteArrayToShort(new byte[]{content[m * blockSize + 1 + ch * 2], content[m * blockSize + ch * 2]});}else if(bitPerSample == 32){audioData[ch][m] = byteArrayToInt(new byte[]{content[m * blockSize + 3 + ch * 4], content[m * blockSize + 2 + ch * 4],content[m * blockSize + 1 + ch * 4],content[m * blockSize + ch * 4]});}}}// nSamplesPerSec : 44100Hzint cacheLength = 25;if(riffFormat.getnSamplesPerSec() == 44100)cacheLength = 37;else if(riffFormat.getnSamplesPerSec() == 48000)cacheLength = 43;int[] cache;for(int ch = 0 ; ch < channel ; ch ++) {cache = new int[cacheLength];points.clear();for (int value : audioData[ch]) {int[] cacheNew = new int[cacheLength];System.arraycopy(cache, 1, cacheNew, 0, cacheLength - 1);cacheNew[cacheLength - 1] = value;try {boolean tp = isTerminalPoint(cacheNew);if (tp) {points.add(cacheNew[cacheLength / 2]);}cache = cacheNew;} catch (Exception e) {e.printStackTrace();}}System.out.println("第" + ch + "声道 *****" + points.size());}}

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

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

代码下载地址:https://download.csdn.net/download/baoolong/86929960

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

  1. java 双声道音频_java实现切割wav音频文件的方法详解【附外部jar包下载】

    本文实例讲述了java实现切割wav音频文件的方法.分享给大家供大家参考,具体如下: import it.sauronsoftware.jave.Encoder; import it.sauronso ...

  2. java切割wav音频文件

    import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.MultimediaInfo; import java.io. ...

  3. Java程序获取和修改.wav音频文件的内部结构

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/79498075冷血之心的博客) wav音频文件是一种无损的音频文件, ...

  4. java wav音频文件播放器demo

    java 简易wav音频文件播放器 测试文件 源码 相关资料 测试文件 csdn下载 : https://download.csdn.net/download/qq_41054313/18704149 ...

  5. Java 采集声音_通过java采集PC麦克风音频及播放wav音频文件

    AudioFormat对象 sampleRate 采样率 每秒音频采样数量 sampleSizeInBits 采样位数 每个采样的位数 channels 声道 1: Mono 单声道,2:Stereo ...

  6. android 字节转wav,android开发:把一个byte数组转换成wav音频文件,并且播放

    ============问题描述============ 如题,byte数组转换成wav音频文件,并且播放,下面代码能生成data/data/com.example.playwav/cache/tem ...

  7. C语言解析WAV音频文件

    转载:http://www.cnblogs.com/LexMoon/p/wave-c.html 1.C语言解析WAV音频文件 代码地址: Github : https://github.com/Cas ...

  8. Windows Phone 8初学者开发—第21部分:永久保存Wav音频文件

    第21部分:永久保存Wav音频文件 原文地址:http://channel9.msdn.com/Series/Windows-Phone-8-Development-for-Absolute-Begi ...

  9. 将wav音频文件转化为16k Hz 单通道的文件

    一般做语音分析16k Hz 单通道的文件就够了,这里介绍如何查看和转化wav文件的采样频率和通道数. 1. 查看wav文件的采样频率和通道数 这里用python查看 from scipy.io imp ...

最新文章

  1. oracle schema与mysql_Oracle数据库之Oracle 11g R2 用户与模式(schema)
  2. 平衡二叉树-FHQ Treap(无旋平衡树)c/c++代码实现
  3. python爬虫——随机生成headers
  4. pickle,json ;random,shelve
  5. 是什么优化让 .NET Core 性能飙升?
  6. 匿名内部类可以访问private_内部类一篇文章搞定
  7. MyBatis 源码解读-获得Mapper 对象
  8. java循环队列_Java 循环队列的实现
  9. Mr.J--俄罗斯方块实现(框架)
  10. LNMP安装了哪些软件?安装目录在哪?
  11. Windows下利用C++实现Git自动克隆项目
  12. 神奇技术:科学家借助AI从受害人脑中还原犯罪者样貌
  13. html页面简单访问限制
  14. nexus3.x批量上传jar包
  15. oracle中sqlplus,Oracle sqlplus命令的详细解析
  16. Android Studio创建AVD教程
  17. 鸿蒙之唯一真界,275无量量劫即将到来,束手无策的命运
  18. 微信小程序如何从数组里取值_微信小程序 怎么数组里面值
  19. 【线程知识点】-- 自旋锁
  20. Caché的studio如何Debug

热门文章

  1. python 微博图片爬虫 不用cookie
  2. 通俗易懂的YOLO系列(从V1到V5)模型解读!
  3. 算法:根据四色定理(Four color theorem),求出地图的所有着色方案
  4. python做数据可视化视频_B站上的数据可视化视频是怎么做的,用到了什么技术和工具?...
  5. ABB 120 六轴机械手臂编程调试(二)
  6. PostgreSQL对汉字按拼音排序
  7. win10切换输入法快捷键_电脑小白必学的5个Win10技巧
  8. 厦门大学计算机科学俞俊,厦门大学计算机学科距离进入ESI全球前1%的接近程度为66%-厦门大学计算机科学系...
  9. 网页多媒体服务器,大区网页直播间搭建,服务器流媒体全对接服务
  10. webworker应用场景_JavaScript 工作原理之七-Web Workers 分类及 5 个使用场景