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包


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