关于ADPCM编码和PCM编码的.wav文件通过Java进行相互转换

最近在做一个呼叫器的项目,中间碰到了点问题,就是呼叫器那边传过来的数据是ADPCM编码格式的,经过程序转换成.wav文件后可以在播放器上进行播放,但是无法在浏览器上进新播放。在网上查资料的时候,几乎都是C语言的版本,在程序中无法使用,就参考C语言用Java写了个编解码程序。

对.wav文件做编码转换,就需要对wav文件的格式进行了解,网上有很多wav文件格式解析的文章。我总结了一下,做了一个表格。

代码里面有些重复的,没有进行优化缩减,用到的可以自行优化一下

wav头中的RIFF块

/*** @Description TODO* @Author liminghui* @Date 2020/3/14 9:14* @Version 1.0**/
public class RIFF {private String RIFFID;private Long RIFFSize;private String RIFFType;public RIFF() {this.RIFFID = "RIFF";this.RIFFType = "WAVE";}public String getRIFFID() {return RIFFID;}public void setRIFFID(String RIFFID) {this.RIFFID = RIFFID;}public Long getRIFFSize() {return RIFFSize;}public void setRIFFSize(Long RIFFSize) {this.RIFFSize = RIFFSize;}public String getRIFFType() {return RIFFType;}public void setRIFFType(String RIFFType) {this.RIFFType = RIFFType;}}

wav头中的fmt 块

/*** @Description TODO* @Author liminghui* @Date 2020/3/14 9:14* @Version 1.0**/
public class FORMAT {private String FORMATID;private Long FORMATSize;private Integer FORMATAudioFormat;private Integer FORMATNumChannels;private Long FORMATSampleRate;private Long FORMATByteRate;private Integer FORMATBlockAlign;private Integer FORMATBitsPerSample;private Integer FORMATsbSize;private Integer FORMATSamplesPerBlock;public FORMAT(String str) {if (str == "ADPCM") {this.FORMATID = "fmt ";this.FORMATSize = 20l;this.FORMATAudioFormat = 17;this.FORMATNumChannels = 1;this.FORMATSampleRate = 8000l;this.FORMATByteRate = 4055l;this.FORMATBlockAlign = 256;this.FORMATBitsPerSample = 4;this.FORMATsbSize = 2;this.FORMATSamplesPerBlock = 505;} else {this.FORMATID = "fmt ";this.FORMATSize = 16l;this.FORMATAudioFormat = 1;this.FORMATNumChannels = 1;this.FORMATSampleRate = 8000l;this.FORMATByteRate = 16000l;this.FORMATBlockAlign = 2;this.FORMATBitsPerSample = 16;}}public String getFORMATID() {return FORMATID;}public void setFORMATID(String FORMATID) {this.FORMATID = FORMATID;}public Long getFORMATSize() {return FORMATSize;}public void setFORMATSize(Long FORMATSize) {this.FORMATSize = FORMATSize;}public Integer getFORMATAudioFormat() {return FORMATAudioFormat;}public void setFORMATAudioFormat(Integer FORMATAudioFormat) {this.FORMATAudioFormat = FORMATAudioFormat;}public Integer getFORMATNumChannels() {return FORMATNumChannels;}public void setFORMATNumChannels(Integer FORMATNumChannels) {this.FORMATNumChannels = FORMATNumChannels;}public Long getFORMATSampleRate() {return FORMATSampleRate;}public void setFORMATSampleRate(Long FORMATSampleRate) {this.FORMATSampleRate = FORMATSampleRate;}public Long getFORMATByteRate() {return FORMATByteRate;}public void setFORMATByteRate(Long FORMATByteRate) {this.FORMATByteRate = FORMATByteRate;}public Integer getFORMATBlockAlign() {return FORMATBlockAlign;}public void setFORMATBlockAlign(Integer FORMATBlockAlign) {this.FORMATBlockAlign = FORMATBlockAlign;}public Integer getFORMATBitsPerSample() {return FORMATBitsPerSample;}public void setFORMATBitsPerSample(Integer FORMATBitsPerSample) {this.FORMATBitsPerSample = FORMATBitsPerSample;}public Integer getFORMATsbSize() {return FORMATsbSize;}public void setFORMATsbSize(Integer FORMATsbSize) {this.FORMATsbSize = FORMATsbSize;}public Integer getFORMATSamplesPerBlock() {return FORMATSamplesPerBlock;}public void setFORMATSamplesPerBlock(Integer FORMATSamplesPerBlock) {this.FORMATSamplesPerBlock = FORMATSamplesPerBlock;}

wav头中的FACT 块

/*** @Description TODO* @Author liminghui* @Date 2020/3/14 9:14* @Version 1.0**/
public class FACT {private String FACTID;private Long FACTSize;private Long FACTSampleLength;public FACT() {this.FACTID = "fact";this.FACTSize = 4l;}public Long getFACTSampleLength() {return FACTSampleLength;}public void setFACTSampleLength(Long FACTSampleLength) {this.FACTSampleLength = FACTSampleLength;}public Long getFACTSize() {return FACTSize;}public void setFACTSize(Long FACTSize) {this.FACTSize = FACTSize;}public String getFACTID() {return FACTID;}public void setFACTID(String FACTID) {this.FACTID = FACTID;}
}

wav头中的DATA 块

/*** @Description TODO* @Author liminghui* @Date 2020/3/14 9:14* @Version 1.0**/
public class DATA {private String DATAID;private Long DATASize;public DATA() {this.DATAID = "data";}public Long getDATASize() {return DATASize;}public void setDATASize(Long DATASize) {this.DATASize = DATASize;}public String getDATAID() {return DATAID;}public void setDATAID(String DATAID) {this.DATAID = DATAID;}
}

wav头中的BLOCKHEARD 块

/*** @Description TODO* @Author liminghui* @Date 2020/3/14 9:16* @Version 1.0**/
public class BLOCKHEARD {private Integer BLOCKPresample;private Integer BLOCKIndex;private Integer BLOCKRSV;public BLOCKHEARD() {this.BLOCKRSV = 0;}public Integer getBLOCKPresample() {return BLOCKPresample;}public void setBLOCKPresample(Integer BLOCKPresample) {this.BLOCKPresample = BLOCKPresample;}public Integer getBLOCKIndex() {return BLOCKIndex;}public void setBLOCKIndex(Integer BLOCKIndex) {this.BLOCKIndex = BLOCKIndex;}public Integer getBLOCKRSV() {return BLOCKRSV;}public void setBLOCKRSV(Integer BLOCKRSV) {this.BLOCKRSV = BLOCKRSV;}
}

/**
* WAV文件以小端形式来进行数据存储。
* 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
* 所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
* 以四个字节存储一个数据为例:类似于字符串,从右到左是从低位到高位
*/
编码encoder

package enCoder;import entity.*;import java.io.*;/*** @Description TODO* @Author liminghui* @Date 2020/3/13 15:13* @Version 1.0**/
public class encoder02 {private static int[] indexTable={-1, -1, -1, -1, 2, 4, 6, 8,-1, -1, -1, -1, 2, 4, 6, 8};private static int[] stepsizeTable = {7, 8, 9, 10, 11, 12, 13, 14, 16, 17,19, 21, 23, 25, 28, 31, 34, 37, 41, 45,50, 55, 60, 66, 73, 80, 88, 97, 107, 118,130, 143, 157, 173, 190, 209, 230, 253, 279, 307,337, 371, 408, 449, 494, 544, 598, 658, 724, 796,876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767};private static FileOutputStream fos = null;private static FileInputStream fis = null;private static RIFF riff = null;private static FORMAT format = null;private static DATA data = null;private static FACT fact = null;private static BLOCKHEARD blockheard = null;public static void main(String[] args) {try {File inFile = new File("C:\\Users\\Administrator\\Desktop\\pcm文档\\9110999302110.wav");File outFile = new File("C:\\Users\\Administrator\\Desktop\\pcm文档\\ddd.wav");if (!outFile.exists()) outFile.createNewFile();fis = new FileInputStream(inFile);fos = new FileOutputStream(outFile);long length = inFile.length();writeHeard(length);blockheard=new BLOCKHEARD();//设置默认的index和rsvblockheard.setBLOCKIndex(0);blockheard.setBLOCKRSV(0);byte[] inData=new byte[1024];//读取前44个字节的PCM编码的WAV头fis.read(inData, 0, 44);int len=0;while (len != -1) {byte[] bytes = new byte[2];fis.read(bytes,0,2);blockheard.setBLOCKPresample((bytes[0] & 0xff) | bytes[1] << 8);fos.write(Hex2ByteDTX(blockheard.getBLOCKPresample()));fos.write(HexByteDTX(blockheard.getBLOCKIndex()));fos.write(HexByteDTX(blockheard.getBLOCKRSV()));len = fis.read(inData, 0, 1008);if (len != -1) {CoderRealize(inData, len, blockheard);}}fis.close();fos.close();} catch (IOException e) {e.printStackTrace();}}private static void CoderRealize(byte[] inData, int len, BLOCKHEARD blockheard) {try {int sign;int delta;int step;int valpred;int vpdiff;int diff;int index;boolean bufferstep;int outputbuffer = 0;valpred = blockheard.getBLOCKPresample();index = blockheard.getBLOCKIndex();step = stepsizeTable[index];bufferstep = true;for (int i = 0; i < len / 2; i++) {int val = (inData[i * 2] & 0xff) | inData[i * 2 + 1] << 8 ;diff = val - valpred;sign = (diff < 0) ? 8 : 0;if (sign != 0) {diff = (-diff);}delta = 0;vpdiff = (step >> 3);if (diff >= step) {delta = 4;diff -= step;vpdiff += step;}step >>= 1;if (diff >= step) {delta |= 2;diff -= step;vpdiff += step;}step >>= 1;if (diff >= step) {delta |= 1;vpdiff += step;}if (sign != 0)valpred -= vpdiff;elsevalpred += vpdiff;if (valpred > 32767)valpred = 32767;else if (valpred < -32768)valpred = -32768;delta |= sign;index += indexTable[delta];if (index < 0) index = 0;if (index > 88) index = 88;step = stepsizeTable[index];if (bufferstep) {outputbuffer = delta & 0x0f;} else {fos.write((byte) ((delta << 4) & 0xf0) | outputbuffer);}bufferstep = !bufferstep;}if (!bufferstep) {fos.write(outputbuffer & 0xff);}blockheard.setBLOCKIndex(index);} catch (IOException e) {e.printStackTrace();}}/*** 16进制大端转小端*  WAV文件以小端形式来进行数据存储。*/private static byte[] Hex4ByteDTX(Long l) {int len = 4;byte[] b = new byte[len];for (int i = 0; i < len; i++) {b[i] = (byte) (l >> (i * 8) & 0x00ff);}return b;}private static byte[] Hex2ByteDTX(int l) {int len = 2;byte[] b = new byte[len];for (int i = 0; i < len; i++) {b[i] = (byte) (l >> (i * 8) & 0x00ff);}return b;}private static byte HexByteDTX(int l) {byte b = (byte) (l & 0x00ff);return b;}private static void writeHeard(long length) {long dataSize = (length - 44) / 1010 * 256;if ((length - 44) % 1010 != 0) {dataSize += ((length - 44) % 1010 - 2) / 4 + 4;}riff = new RIFF();format = new FORMAT("ADPCM");data = new DATA();fact = new FACT();fact.setFACTSampleLength(dataSize);data.setDATASize(dataSize);riff.setRIFFSize(dataSize + 58);try {//写入RIFF块fos.write(riff.getRIFFID().getBytes());fos.write(Hex4ByteDTX(riff.getRIFFSize()));fos.write(riff.getRIFFType().getBytes());//写入‘fmt ’块fos.write(format.getFORMATID().getBytes());fos.write(Hex4ByteDTX(format.getFORMATSize()));fos.write(Hex2ByteDTX(format.getFORMATAudioFormat()));fos.write(Hex2ByteDTX(format.getFORMATNumChannels()));fos.write(Hex4ByteDTX(format.getFORMATSampleRate()));fos.write(Hex4ByteDTX(format.getFORMATByteRate()));fos.write(Hex2ByteDTX(format.getFORMATBlockAlign()));fos.write(Hex2ByteDTX(format.getFORMATBitsPerSample()));fos.write(Hex2ByteDTX(format.getFORMATsbSize()));fos.write(Hex2ByteDTX(format.getFORMATSamplesPerBlock()));//写入FACT块fos.write(fact.getFACTID().getBytes());fos.write(Hex4ByteDTX(fact.getFACTSize()));fos.write(Hex4ByteDTX(fact.getFACTSampleLength()));//写入Data块fos.write(data.getDATAID().getBytes());fos.write(Hex4ByteDTX(data.getDATASize()));} catch (IOException e) {e.printStackTrace();}}
}

解码decoder

package deCoder;import entity.BLOCKHEARD;
import entity.DATA;
import entity.FORMAT;
import entity.RIFF;import java.io.*;/*** @Description TODO* @Author liminghui* @Date 2020/3/13 15:13* @Version 1.0**/
public class decoder {private static int[] indexTable={-1, -1, -1, -1, 2, 4, 6, 8,-1, -1, -1, -1, 2, 4, 6, 8};private static int[] stepsizeTable = {7, 8, 9, 10, 11, 12, 13, 14, 16, 17,19, 21, 23, 25, 28, 31, 34, 37, 41, 45,50, 55, 60, 66, 73, 80, 88, 97, 107, 118,130, 143, 157, 173, 190, 209, 230, 253, 279, 307,337, 371, 408, 449, 494, 544, 598, 658, 724, 796,876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767};private static FileOutputStream fos = null;private static FileInputStream fis = null;private static RIFF riff = null;private static FORMAT format = null;private static DATA data = null;private static BLOCKHEARD blockheard = null;public static void main(String[] args) {try {File inFile = new File("C:\\Users\\Administrator\\Documents\\WeChat Files\\LMH13073784256\\FileStorage\\File\\2020-05\\888.pcm");File outFile = new File("C:\\Users\\Administrator\\Desktop\\pcm文档\\9110999302110.wav");if (!outFile.exists()) outFile.createNewFile();fis = new FileInputStream(inFile);fos = new FileOutputStream(outFile);long length = inFile.length();writeHeard(length);blockheard=new BLOCKHEARD();byte[] inData=new byte[1024];int len;while ((len = fis.read(inData, 0, 256)) != -1) {blockheard.setBLOCKPresample(inData[0]|inData[1]<<8);blockheard.setBLOCKIndex((int) inData[2]);blockheard.setBLOCKRSV((int) inData[3]);fos.write(inData[0]);fos.write(inData[1]);CoderRealize(inData, len, blockheard);}fis.close();fos.close();} catch (IOException e) {e.printStackTrace();}}private static void CoderRealize(byte[] inData, int len, BLOCKHEARD blockheard) {int sign;int delta;int step;int valpred;int vpdiff;int index;boolean bufferstep;int j=4;valpred = blockheard.getBLOCKPresample();index = blockheard.getBLOCKIndex();step = stepsizeTable[index];bufferstep = true;for (int i = 0; i < (len - 4) * 2; i++) {try {if (bufferstep) {//取低四位delta = inData[j] & 0xf;} else {//取高四位delta = (inData[j] >> 4) & 0xf;j++;}bufferstep = !bufferstep;index += indexTable[delta];if (index < 0) index = 0;if (index > 88) index = 88;//取符号位 &(与运算)都为1才为1sign = delta & 8;//sing只会等于8或者0//取数据delta = delta & 7;//下边四则运算将vpdiff = (delta+0.5)*step/4四则运算转换成了二进制的与或运算(牛逼)vpdiff = step >> 3;if ((delta & 4) != 0) {vpdiff += step;}if ((delta & 2) != 0) {vpdiff += step >> 1;}if ((delta & 1) != 0) {vpdiff += step >> 2;}if (sign != 0) {valpred -= vpdiff;} else {valpred += vpdiff;}if (valpred > 32767)valpred = 32767;else if (valpred < -32768)valpred = -32768;step = stepsizeTable[index];fos.write(Hex2ByteDTX(valpred));} catch (IOException e) {e.printStackTrace();}}}private static byte[] Hex4ByteDTX(Long l) {int len = 4;byte[] b = new byte[len];for (int i = 0; i < len; i++) {b[i] = (byte) (l >> (i * 8) & 0x00ff);}return b;}private static byte[] Hex2ByteDTX(int l) {int len = 2;byte[] b = new byte[len];for (int i = 0; i < len; i++) {b[i] = (byte) (l >> (i * 8) & 0x00ff);}return b;}private static void writeHeard(long length) {long nBlock = length / 256;long dataSize=nBlock*505;long otherBytes = length % 256;if (otherBytes != 0) {dataSize +=(otherBytes-4)*2+1;}riff = new RIFF();format = new FORMAT("PCM");data = new DATA();data.setDATASize(dataSize * 2);riff.setRIFFSize(data.getDATASize() + 36);try {fos.write(riff.getRIFFID().getBytes());fos.write(Hex4ByteDTX(riff.getRIFFSize()));fos.write(riff.getRIFFType().getBytes());fos.write(format.getFORMATID().getBytes());fos.write(Hex4ByteDTX(format.getFORMATSize()));fos.write(Hex2ByteDTX(format.getFORMATAudioFormat()));fos.write(Hex2ByteDTX(format.getFORMATNumChannels()));fos.write(Hex4ByteDTX(format.getFORMATSampleRate()));fos.write(Hex4ByteDTX(format.getFORMATByteRate()));fos.write(Hex2ByteDTX(format.getFORMATBlockAlign()));fos.write(Hex2ByteDTX(format.getFORMATBitsPerSample()));fos.write(data.getDATAID().getBytes());fos.write(Hex4ByteDTX(data.getDATASize()));} catch (IOException e) {e.printStackTrace();}}
}

关于ADPCM编码和PCM编码的wave文件通过Java进行相互转换相关推荐

  1. 痞子衡嵌入式:PCM编码与Waveform音频文件(.wav)格式详解

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是PCM编码及Waveform音频文件格式. 嵌入式里有时候也会和音频打交道,比如最近特别火的智能音箱产品,离不开前端的音频信号采集.降噪 ...

  2. PCM编码及Waveform音频文件格式

    转载自 https://www.cnblogs.com/henjay724/p/9463296.html 嵌入式里有时候也会和音频打交道,比如最近特别火的智能音箱产品,离不开前端的音频信号采集.降噪, ...

  3. a律13折线pcm编码例题_a律13折线pcm编码例题

    信息举报 时间:2020-12-20 本页为您甄选多篇描写a律13折线pcm编码例题,a律13折线pcm编码例题精选,a律13折线pcm编码例题大全,有议论,叙事 ,想象等形式.文章字数有400字.6 ...

  4. wave文件(*.wav)格式、PCM数据格式介绍

    音频简介 经常见到这样的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等. 44100HZ 16bit stereo: 每秒钟有 44100 次采样, ...

  5. 嵌入式 wave文件(*.wav)格式、PCM数据格式收藏

    1.音频简介 经常见到这样的描述: 44100HZ16bit stereo 或者 22050HZ 8bit mono 等等. 44100HZ16bit stereo: 每秒钟有 44100 次采样, ...

  6. fwPlayer 支持最新浏览器在线播放adpcm pcm 编码的wav

    ​ fwPlayer 支持最新浏览器在线播放adpcm pcm 编码的wav 可以使用 fwPlayer 使用webassembly技术,在线转码avi flv为mp4 或者ogg等来播放 fwPla ...

  7. pcma和pcmu pcm编码_语音编码分类及编解码标准

    G.711类型:Audio 制定者:ITU-T 所需频宽:64Kbps 特性:算法复杂度小,音质一般 优点:算法复杂度低,压缩比小(CD音质>400kbps),编解码延时最短(相对其它技术) 缺 ...

  8. 基于 MATLAB 的 PCM 编码解码实现

    基于 MATLAB 的 PCM 编码解码实现_vlaser的小屋-CSDN博客_pcm编码matlab

  9. 基于FFmpeg的音频编码(PCM数据编码成AAC android)

    概述 在Android上实现录音,并利用 FFmpeg将PCM数据编码成AAC. 详细 代码下载:http://www.demodashi.com/demo/10512.html 之前做的一个demo ...

最新文章

  1. Nature指数发榜:中科院总榜夺冠,北大、清华列学术机构Top 10
  2. Windows Phone 7 Tips (1)
  3. Linux学习:shell 命令(压缩包管理)
  4. AWS s3访问权限
  5. Shareplex 错误 can't open or read object cache file
  6. SAP成都研究院数字创新空间基于SAP C4C开发的一个智能服务原型项目
  7. python 爬虫框架_Python实战:爬虫框架(6)
  8. PHP计算GPS路书,搜狗地图推出路书功能 免费而智能的GPS
  9. Python快速入门教材推荐!
  10. 七万字详解paddle-openVINO【CPU】-从环境配置-模型部署全流程
  11. SpringBoot Validation参数校验 详解自定义注解规则和分组校验
  12. [渝粤教育] 中国矿业大学 货币金融学 参考 资料
  13. 数字图像处理_Matlab——车牌识别分析
  14. Python爬取京东商品数据
  15. php scada,科远风场SCADA系统的应用
  16. 基于数字温度传感器的数字温度计 华氏度和摄氏度
  17. (第一个java爬虫)java爬取网页文本并抽取中英文关键词
  18. php框架审计,关于ThinkPHP框架的审计
  19. Corejava知识点
  20. Windows Terminal 主题配置

热门文章

  1. 杂文:创新,淘宝,马云,阿里,美国,工商局,假货
  2. 56道java基础必“背“面试题(备战2022金三银四)
  3. VTK学习-第一个多柱体生成
  4. xmind 8 pro Mac破解版(思维导图) 附xmind 8 序列号
  5. CDK【10元美团外卖通用红包】无门槛红包 2天内兑换 1天内可兑换5次 提示失败隔天兑换
  6. UnityHLSLShader 函数笔记
  7. mybatis 日志 Reader entry 乱码
  8. window10离线安装net3.5的三种方法
  9. numpy、pandas下载速度慢问题
  10. 好玩的Matlab 3D心形代码