wangtianbao

          pcm轉wav

          PCM轉WAV只需在PCM文件前面增加WAV頭即可,WAV文件頭中包含的信息有:采樣率、采樣的位數、文件大小等。頭文件的長度占44字節。

          采樣的位數指的是描述數字信號所使用的位數。8位(8bit)代表2的8次方=256,16 位(16bit)則代表2的16次方=65536 / 1024 =64K

          采樣率是一秒鐘內對聲音信號的采樣次數

          網絡接收一個音頻的時長是20ms, 已知音頻采樣率是8kHz,采樣的位數是16bit。
          [時長]20ms * [采樣率]8kHz * [采樣的位數]16bit = 320 byte

          例如,CD碟采用16位的采樣精度,44.1KHz的采樣頻率,為雙聲道,它每秒所需要的數據量為16×44100×2÷8=176400字節。這樣算下來,比特率應該是1400多Kbps,如果采用MP3、WMA編碼格式,比特率能夠更小。


          WAV文件的基本格式
          類型內容變量名大小取值
          RIFF頭 文件標識符串 fileId 4B "RIFF"
          頭后文件長度 fileLen 4B 非負整數(=文件長度-8)
          數據類型標識符 波形文件標識符 waveId 4B "WAVE"
          格式塊 塊頭 格式塊標識符 chkId 4B "fmt"
          頭后塊長度 chkLen 4B 非負整數(=16或18)
          塊數據 格式標記 wFormatTag 2B 非負短整數(PCM=1)
          聲道數 wChannels 2B 非負短整數(=1或2)
          采樣率 dwSampleRate 4B 非負整數(單聲道采樣數/秒)
          平均字節率 dwAvgBytesRate 4B 非負整數(字節數/秒)
          數據塊對齊 wBlockAlign 2B 非負短整數(不足補零)
          采樣位數 wBitsPerSample 2B 非負短整數(PCM時才有)
          擴展域大小 wExtSize 2B 非負短整數 可選(根據chkLen=16或18判斷)
          擴展域 extraInfo extSize B 擴展信息
          數據塊 塊頭 數據塊標識符串 chkId 4B "data"
          頭后塊長度 chkLen 4B 非負整數
          塊數據 波形采樣數據 x 或 xl、xr chkLen B 左右聲道樣本交叉排列
          樣本值為整數(整字節存儲,不足位補零),整個數據塊按blockAlign對齊


          示例:
          package com.pvcp.common.utils;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;

          public class PcmToWavUtil {

              public static boolean convert(String pcmFilePath, String wavFilePath, int bitsPerSample, int samplesPerSec) {
                  FileInputStream fis = null;
                  FileOutputStream fos = null;
                  try {
                      fis = new FileInputStream(pcmFilePath);
                      fos = new FileOutputStream(wavFilePath);
                      // 計算長度
                      int pcmSize = fis.available();// 由于音頻文件一般不會大于 Int 最大值,所以使用 available
                      
          // 填入參數,比特率等等。這里用的是 16位 單聲道 8000 hz
                      WavHeader header = new WavHeader();
                      // 長度字段 = 內容的大小(PCMSize) + 頭部字段的大小(不包括前面4字節的標識符RIFF以及fileLength本身的4字節)
                      header.fileLength = pcmSize + (44 - 8);
                      header.fmtHdrLeth = 16;
                      header.bitsPerSample = (short)bitsPerSample;
                      header.channels = 1;
                      header.formatTag = 0x0001;
                      // header.samplesPerSec = 8000;
                      header.samplesPerSec = samplesPerSec;
                      header.blockAlign = (short) (header.channels * header.bitsPerSample / 8);
                      header.avgBytesPerSec = header.blockAlign * header.samplesPerSec;
                      header.dataHdrLeth = pcmSize;
                      byte[] h = header.getHeader();
                      assert h.length == 44;// WAV標準,頭部應該是44字節
                      
          // write header
                      fos.write(h, 0, h.length);
                      // write data stream
                      SourceUtils.write(fis, fos);
                      return true;
                  } catch (Exception e) {
                      e.printStackTrace();
                      return false;
                  } finally {
                      SourceUtils.close(fis, fos);
                  }

              }

          }


          package com.pvcp.common.utils;

          import java.io.Closeable;
          import java.io.InputStream;
          import java.io.OutputStream;
          import java.lang.reflect.Method;

          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;

          public class SourceUtils {
              private static Log logging = LogFactory.getLog(SourceUtils.class);
              public static void runMethod(String methodName,Object objs){
                  if(objs == null){
                      return;
                  }
                  for(Object obj:objs){
                      if(obj == null){
                          return;
                      }
                      try {
                          Method m = obj.getClass().getDeclaredMethod(methodName);
                          m.invoke(obj);
                      } catch (Exception e) {
                          logging.error("執行["+methodName+"]方法異常!對象:"+obj+";異常:"+e.getMessage());
                      }
                  }
              }
              public static void write(InputStream in,OutputStream out){
                  try {
                      byte[] buff = new byte[1024*5];
                      int len = 0;
                      while((len=in.read(buff)) != -1){
                          try {
                              out.write(buff,0,len);
                              out.flush();
                          } catch (Exception e) {
                              
                          }
                      }
                  } catch (Exception e) {
                      
                  }
              }
              public static void close(Object objs){
                  if(objs == null){
                      return;
                  }
                  for(Object obj:objs){
                      if(obj == null){
                          return;
                      }
                      try {
                          if(obj instanceof Closeable){
                              ((Closeable) obj).close();
                          }else if(obj instanceof AutoCloseable){
                              ((AutoCloseable) obj).close();
                          }else{
                              runMethod("close", obj);
                          }
                      } catch (Exception e) {
                          logging.error("關閉資源異常!對象:"+obj+";異常:"+e.getMessage(), e);
                      }
                  }
              }
              
          }

          package com.pvcp.common.utils;

          import java.io.ByteArrayOutputStream;
          import java.io.IOException;

          public class WavHeader {

              /**
               * 4 資源交換文件標志(RIFF)
               
          */
              public final char fileID[] = { 'R', 'I', 'F', 'F' };
              /**
               * 4 總字節數
               
          */
              public int fileLength;
              /**
               * 4 WAV文件標志(WAVE)
               
          */
              public char wavTag[] = { 'W', 'A', 'V', 'E' };
              /**
               * 4 波形格式標志(fmt ),最后一位空格
               
          */
              public char fmtHdrID[] = { 'f', 'm', 't', ' ' };
              /**
               * 4 過濾字節(一般為00000010H),若為00000012H則說明數據頭攜帶附加信息
               
          */
              public int fmtHdrLeth;
              /**
               * 2 格式種類(值為1時,表示數據為線性PCM編碼)
               
          */
              public short formatTag;
              /**
               * 2 通道數,單聲道為1,雙聲道為2
               
          */
              public short channels;
              /**
               * 4 采樣頻率
               
          */
              public int samplesPerSec;
              /**
               * 4 波形數據傳輸速率(每秒平均字節數)
               
          */
              public int avgBytesPerSec;
              /**
               * 2 DATA數據塊長度,字節
               
          */
              public short blockAlign;
              /**
               * 2 PCM位寬
               
          */
              public short bitsPerSample;
              /**
               * 4 數據標志符(data)
               
          */
              public char dataHdrID[] = { 'd', 'a', 't', 'a' };
              /**
               * 4 DATA總數據長度字節
               
          */
              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);
                  }
              }

          }

          posted on 2018-05-08 10:02 王添寶 閱讀(65) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 赤水市| 宜都市| 乌拉特后旗| 芮城县| 新巴尔虎右旗| 临沂市| 闸北区| 麻栗坡县| 张家港市| 西乌| 闽清县| 丽江市| 福州市| 无棣县| 浦江县| 南康市| 曲麻莱县| 循化| 凤阳县| 泰州市| 乌鲁木齐市| 全南县| 洛南县| 虎林市| 农安县| 尚志市| 扬中市| 白沙| 大城县| 凤山县| 伊宁县| 沙田区| 合作市| 广德县| 桂阳县| 江达县| 微山县| 喀喇沁旗| 张家口市| 武功县| 进贤县|