转载-java将pcm音频转换成wav格式
原文链接:https://blog.csdn.net/qq_25925973/article/details/90441386
PCM(Pulse Code Modulation)脉冲编码调制是数字通信的编码方式之一。主要过程是将话音、图像等模拟信号每隔一定时间进行取样,使其离散化,同时将抽样值按分层单位四舍五入取整量化,同时将抽样值按一组二进制码来表示抽样脉冲的幅值。
pcm音频想要直接听需要专业的软件才可以,这里我需要把pcm的音频转化为wav这种无损的格式,也就是需要在pcm文件添加wav的音频头,这样就可以直接使用音频软件打开了。使用Java实现的方式见下文
1 package com.test.shell; 2 3 import java.io.*; 4 import com.alibaba.druid.util.StringUtils; 5 6 public class ShellUtils { 7 public static File tranPcmToWavFile(File pcmFile) { 8 FileInputStream fis = null; 9 FileOutputStream fos = null; 10 try { 11 fis = new FileInputStream(pcmFile); 12 String wavfilepath = pcmFile.getAbsolutePath().substring(0, pcmFile.getAbsolutePath().lastIndexOf(".")) + "." + SysConstants.IVR_SPEAK_TYPE_WAV.toLowerCase(); 13 14 15 File file = new File(wavfilepath); 16 if (!file.exists()) { 17 file.createNewFile(); 18 } 19 fos = new FileOutputStream(wavfilepath); 20 21 22 int PCMSize = 0; 23 byte[] buf = new byte[1024 * 4]; 24 int size = fis.read(buf); 25 26 while (size != -1) { 27 PCMSize += size; 28 size = fis.read(buf); 29 } 30 fis.close(); 31 32 //填入参数,比特率等等。这里用的是16位单声道 8000 hz 33 34 WaveHeader header = new WaveHeader(); 35 //长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节) 36 header.fileLength = PCMSize + (44 - 8); 37 header.FmtHdrLeth = 16; 38 header.BitsPerSample = 16; 39 header.Channels = 1; 40 header.FormatTag = 0x0001; 41 header.SamplesPerSec = 8000; 42 header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8); 43 header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec; 44 header.DataHdrLeth = PCMSize; 45 46 byte[] h = header.getHeader(); 47 48 assert h.length == 44; //WAV标准,头部应该是44字节 49 //write header 50 fos.write(h, 0, h.length); 51 //write data stream 52 fis = new FileInputStream(pcmFile); 53 size = fis.read(buf); 54 while (size != -1) { 55 fos.write(buf, 0, size); 56 size = fis.read(buf); 57 } 58 fis.close(); 59 fos.close(); 60 return new File(wavfilepath); 61 } catch (Exception e) { 62 e.printStackTrace(); 63 } finally { 64 if (fis != null) { 65 try { 66 fis.close(); 67 } catch (IOException e) { 68 e.printStackTrace(); 69 } 70 } 71 if (fos != null) { 72 try { 73 fos.close(); 74 } catch (IOException e) { 75 e.printStackTrace(); 76 } 77 } 78 } 79 return null; 80 } 81 }
2、其中用到的WaveHeader
如下:
package com.test.shell; import java.io.ByteArrayOutputStream; import java.io.IOException; public class WaveHeader { public final char fileID[] = {'R', 'I', 'F', 'F'}; public int fileLength; public char wavTag[] = {'W', 'A', 'V', 'E'};; public char FmtHdrID[] = {'f', 'm', 't', ' '}; public int FmtHdrLeth; public short FormatTag; public short Channels; public int SamplesPerSec; public int AvgBytesPerSec; public short BlockAlign; public short BitsPerSample; public char DataHdrID[] = {'d','a','t','a'}; public int DataHdrLeth; public byte[] getHeader() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); WriteChar(bos, fileID); WriteInt(bos, fileLength); WriteChar(bos, wavTag); WriteChar(bos, FmtHdrID); WriteInt(bos,FmtHdrLeth); WriteShort(bos,FormatTag); WriteShort(bos,Channels); WriteInt(bos,SamplesPerSec); WriteInt(bos,AvgBytesPerSec); WriteShort(bos,BlockAlign); WriteShort(bos,BitsPerSample); WriteChar(bos,DataHdrID); WriteInt(bos,DataHdrLeth); bos.flush(); byte[] r = bos.toByteArray(); bos.close(); return r; } private void WriteShort(ByteArrayOutputStream bos, int s) throws IOException { byte[] mybyte = new byte[2]; mybyte[1] =(byte)( (s << 16) >> 24 ); mybyte[0] =(byte)( (s << 24) >> 24 ); bos.write(mybyte); } private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException { byte[] buf = new byte[4]; buf[3] =(byte)( n >> 24 ); buf[2] =(byte)( (n << 8) >> 24 ); buf[1] =(byte)( (n << 16) >> 24 ); buf[0] =(byte)( (n << 24) >> 24 ); bos.write(buf); } private void WriteChar(ByteArrayOutputStream bos, char[] id) { for (int i=0; i<id.length; i++) { char c = id[i]; bos.write(c); } } }