java切割wav音頻文件

  1. import it.sauronsoftware.jave.Encoder;  
  2. import it.sauronsoftware.jave.MultimediaInfo;  
  3.   
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.nio.ByteBuffer;  
  9.   
  10. /** 
  11.  * wav音頻文件截取工具 
  12.  * (適用於比特率爲128kbps的wav音頻文件,此類音頻文件的頭部信息佔用長度44字節) 
  13.  * @author lwj 
  14.  * 
  15.  */  
  16. public class WavCut {  
  17.       
  18.     /** 
  19.      * 截取wav音頻文件 
  20.      * @param sourcepath  源文件地址 
  21.      * @param targetpath  目標文件地址 
  22.      * @param start  截取開始時間(秒) 
  23.      * @param end  截取結束時間(秒) 
  24.      *  
  25.      * return  截取成功返回true,否則返回false 
  26.      */  
  27.     public static boolean cut(String sourcefile, String targetfile, int start, int end) {  
  28.         try{  
  29.             if(!sourcefile.toLowerCase().endsWith(".wav") || !targetfile.toLowerCase().endsWith(".wav")){  
  30.                 return false;  
  31.             }  
  32.             File wav = new File(sourcefile);  
  33.             if(!wav.exists()){  
  34.                 return false;  
  35.             }  
  36.             long t1 = getTimeLen(wav);  //總時長(秒)  
  37.             if(start<0 || end<=0 || start>=t1 || end>t1 || start>=end){  
  38.                 return false;  
  39.             }  
  40.             FileInputStream fis = new FileInputStream(wav);  
  41.             long wavSize = wav.length()-44;  //音頻數據大小(44爲128kbps比特率wav文件頭長度)  
  42.             long splitSize = (wavSize/t1)*(end-start);  //截取的音頻數據大小  
  43.             long skipSize = (wavSize/t1)*start;  //截取時跳過的音頻數據大小  
  44.             int splitSizeInt = Integer.parseInt(String.valueOf(splitSize));  
  45.             int skipSizeInt = Integer.parseInt(String.valueOf(skipSize));  
  46.               
  47.             ByteBuffer buf1 = ByteBuffer.allocate(4);  //存放文件大小,4代表一個int佔用字節數  
  48.             buf1.putInt(splitSizeInt+36);  //放入文件長度信息  
  49.             byte[] flen = buf1.array();  //代表文件長度  
  50.             ByteBuffer buf2 = ByteBuffer.allocate(4);  //存放音頻數據大小,4代表一個int佔用字節數  
  51.             buf2.putInt(splitSizeInt);  //放入數據長度信息  
  52.             byte[] dlen = buf2.array();  //代表數據長度  
  53.             flen = reverse(flen);  //數組反轉  
  54.             dlen = reverse(dlen);  
  55.             byte[] head = new byte[44];  //定義wav頭部信息數組  
  56.             fis.read(head, 0, head.length);  //讀取源wav文件頭部信息  
  57.             for(int i=0; i<4; i++){  //4代表一個int佔用字節數  
  58.                 head[i+4] = flen[i];  //替換原頭部信息裏的文件長度  
  59.                 head[i+40] = dlen[i];  //替換原頭部信息裏的數據長度  
  60.             }  
  61.             byte[] fbyte = new byte[splitSizeInt+head.length];  //存放截取的音頻數據  
  62.             for(int i=0; i<head.length; i++){  //放入修改後的頭部信息  
  63.                 fbyte[i] = head[i];  
  64.             }  
  65.             byte[] skipBytes = new byte[skipSizeInt];  //存放截取時跳過的音頻數據  
  66.             fis.read(skipBytes, 0, skipBytes.length);  //跳過不需要截取的數據  
  67.             fis.read(fbyte, head.length, fbyte.length-head.length);  //讀取要截取的數據到目標數組  
  68.             fis.close();  
  69.               
  70.             File target = new File(targetfile);  
  71.             if(target.exists()){  //如果目標文件已存在,則刪除目標文件  
  72.                 target.delete();  
  73.             }  
  74.             FileOutputStream fos = new FileOutputStream(target);  
  75.             fos.write(fbyte);  
  76.             fos.flush();  
  77.             fos.close();  
  78.         }catch(IOException e){  
  79.             e.printStackTrace();  
  80.             return false;  
  81.         }  
  82.         return true;  
  83.     }  
  84.       
  85.     /** 
  86.      * 獲取音頻文件總時長 
  87.      * @param filePath  文件路徑 
  88.      * @return 
  89.      */  
  90.     public static long getTimeLen(File file){  
  91.         long tlen = 0;  
  92.         if(file!=null && file.exists()){  
  93.             Encoder encoder = new Encoder();  
  94.             try {  
  95.                  MultimediaInfo m = encoder.getInfo(file);  
  96.                  long ls = m.getDuration();  
  97.                  tlen = ls/1000;  
  98.             } catch (Exception e) {  
  99.                 e.printStackTrace();  
  100.             }  
  101.         }  
  102.         return tlen;  
  103.     }  
  104.       
  105.     /** 
  106.     * 數組反轉 
  107.     * @param array 
  108.     */  
  109.     public static byte[] reverse(byte[] array){  
  110.         byte temp;  
  111.         int len=array.length;  
  112.         for(int i=0;i<len/2;i++){  
  113.             temp=array[i];  
  114.             array[i]=array[len-1-i];  
  115.             array[len-1-i]=temp;  
  116.         }  
  117.         return array;  
  118.     }  
  119.       
  120.     public static void main(String[] args){  
  121.         System.out.println(cut("f:\\111.wav","f:\\111-cut_0_10.wav",0,10));  
  122.         System.out.println(cut("f:\\111.wav","f:\\111-cut_10_20.wav",10,20));  
  123.         System.out.println(cut("f:\\111.wav","f:\\111-cut_20_28.wav",20,28));  
  124.     }  
  125.   

  1. }  

wave類型的音頻文件切割時必須注意頭信息,128kbps比特率的wave文件頭信息佔用44字節。

可以把頭信息作爲一個對象,用ByteBuffer獲取頭信息。


注意:wave文件的頭信息字節數組中每個屬性都進行了數組反轉

wave頭信息對象模型如下:


  1. /** 
  2.  * wave文件頭信息 
  3.  * @author lwj 
  4.  * 
  5.  */  
  6. public class Head {  
  7.       
  8.     public int riff_id;           //4 byte , 'RIFF'  
  9.     public int file_size;         //4 byte , 文件長度(數據長度+36)  
  10.     public int riff_type;         //4 byte , 'WAVE'  
  11.   
  12.     public int fmt_id;            //4 byte , 'fmt'  
  13.     public int fmt_size;          //4 byte , 數值爲16或18,18則最後又附加信息  
  14.     public short fmt_tag;          //2 byte , 編碼方式,一般爲0x0001  
  15.     public short fmt_channel;     //2 byte , 聲道數目,1--單聲道;2--雙聲道  
  16.     public int fmt_samplesPerSec;//4 byte , 採樣頻率  
  17.     public int avgBytesPerSec;   //4 byte , 每秒所需字節數,記錄每秒的數據量  
  18.     public short blockAlign;      //2 byte , 數據塊對齊單位(每個採樣需要的字節數)  
  19.     public short bitsPerSample;   //2 byte , 每個採樣需要的bit數  
  20.   
  21.     public int data_id;           //4 byte , 字符data  
  22.     public int data_size;         //4 byte , 數據長度  
  23.       
  24.     public int getRiff_id() {  
  25.         return riff_id;  
  26.     }  
  27.     public void setRiff_id(int riff_id) {  
  28.         this.riff_id = riff_id;  
  29.     }  
  30.     public int getFile_size() {  
  31.         return file_size;  
  32.     }  
  33.     public void setFile_size(int file_size) {  
  34.         this.file_size = file_size;  
  35.     }  
  36.     public int getRiff_type() {  
  37.         return riff_type;  
  38.     }  
  39.     public void setRiff_type(int riff_type) {  
  40.         this.riff_type = riff_type;  
  41.     }  
  42.     public int getFmt_id() {  
  43.         return fmt_id;  
  44.     }  
  45.     public void setFmt_id(int fmt_id) {  
  46.         this.fmt_id = fmt_id;  
  47.     }  
  48.     public int getFmt_size() {  
  49.         return fmt_size;  
  50.     }  
  51.     public void setFmt_size(int fmt_size) {  
  52.         this.fmt_size = fmt_size;  
  53.     }  
  54.     public short getFmt_tag() {  
  55.         return fmt_tag;  
  56.     }  
  57.     public void setFmt_tag(short fmt_tag) {  
  58.         this.fmt_tag = fmt_tag;  
  59.     }  
  60.     public short getFmt_channel() {  
  61.         return fmt_channel;  
  62.     }  
  63.     public void setFmt_channel(short fmt_channel) {  
  64.         this.fmt_channel = fmt_channel;  
  65.     }  
  66.     public int getFmt_samplesPerSec() {  
  67.         return fmt_samplesPerSec;  
  68.     }  
  69.     public void setFmt_samplesPerSec(int fmt_samplesPerSec) {  
  70.         this.fmt_samplesPerSec = fmt_samplesPerSec;  
  71.     }  
  72.     public int getAvgBytesPerSec() {  
  73.         return avgBytesPerSec;  
  74.     }  
  75.     public void setAvgBytesPerSec(int avgBytesPerSec) {  
  76.         this.avgBytesPerSec = avgBytesPerSec;  
  77.     }  
  78.     public short getBlockAlign() {  
  79.         return blockAlign;  
  80.     }  
  81.     public void setBlockAlign(short blockAlign) {  
  82.         this.blockAlign = blockAlign;  
  83.     }  
  84.     public short getBitsPerSample() {  
  85.         return bitsPerSample;  
  86.     }  
  87.     public void setBitsPerSample(short bitsPerSample) {  
  88.         this.bitsPerSample = bitsPerSample;  
  89.     }  
  90.     public int getData_id() {  
  91.         return data_id;  
  92.     }  
  93.     public void setData_id(int data_id) {  
  94.         this.data_id = data_id;  
  95.     }  
  96.     public int getData_size() {  
  97.         return data_size;  
  98.     }  
  99.     public void setData_size(int data_size) {  
  100.         this.data_size = data_size;  
  101.     }  
  102.       }



需要外部jar包


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章