java读取wav文件(波形文件)并绘制波形图的方法
程序员文章站
2024-03-04 11:17:41
本文实例讲述了java读取wav文件(波形文件)并绘制波形图的方法。分享给大家供大家参考。具体如下:
因为最近有不少网友询问我波形文件读写方面的问题,出于让大家更方便以及...
本文实例讲述了java读取wav文件(波形文件)并绘制波形图的方法。分享给大家供大家参考。具体如下:
因为最近有不少网友询问我波形文件读写方面的问题,出于让大家更方便以及让代码能够得到更好的改进,我将这部分(波形文件的读写)代码开源在github上面。
地址为https://github.com/sintrb/waveaccess/,最新的代码、例子、文档都在那上面,我会在我时间精力允许的前提下对该项目进行维护,同时也希望对这方面有兴趣的网友能够加入到该开源项目上。
以下内容基本都过期了,你可以直接去github上面阅读、下载该项目。
因项目需要读取.wav文件(波形文件)并绘制波形图,因此简单的做了这方面的封装。
其实主要是对wav文件读取的封装,下面是一个wav文件读取器的封装:
// filename: wavefilereader.java // robintang // 2012-08-23 import java.io.*; public class wavefilereader { private string filename = null; private int[][] data = null; private int len = 0; private string chunkdescriptor = null; static private int lenchunkdescriptor = 4; private long chunksize = 0; static private int lenchunksize = 4; private string waveflag = null; static private int lenwaveflag = 4; private string fmtubchunk = null; static private int lenfmtubchunk = 4; private long subchunk1size = 0; static private int lensubchunk1size = 4; private int audioformat = 0; static private int lenaudioformat = 2; private int numchannels = 0; static private int lennumchannels = 2; private long samplerate = 0; static private int lensamplerate = 2; private long byterate = 0; static private int lenbyterate = 4; private int blockalign = 0; static private int lenblockling = 2; private int bitspersample = 0; static private int lenbitspersample = 2; private string datasubchunk = null; static private int lendatasubchunk = 4; private long subchunk2size = 0; static private int lensubchunk2size = 4; private fileinputstream fis = null; private bufferedinputstream bis = null; private boolean issuccess = false; public wavefilereader(string filename) { this.initreader(filename); } // 判断是否创建wav读取器成功 public boolean issuccess() { return issuccess; } // 获取每个采样的编码长度,8bit或者16bit public int getbitpersample(){ return this.bitspersample; } // 获取采样率 public long getsamplerate(){ return this.samplerate; } // 获取声道个数,1代表单声道 2代表立体声 public int getnumchannels(){ return this.numchannels; } // 获取数据长度,也就是一共采样多少个 public int getdatalen(){ return this.len; } // 获取数据 // 数据是一个二维数组,[n][m]代表第n个声道的第m个采样值 public int[][] getdata(){ return this.data; } private void initreader(string filename){ this.filename = filename; try { fis = new fileinputstream(this.filename); bis = new bufferedinputstream(fis); this.chunkdescriptor = readstring(lenchunkdescriptor); if(!chunkdescriptor.endswith("riff")) throw new illegalargumentexception("riff miss, " + filename + " is not a wave file."); this.chunksize = readlong(); this.waveflag = readstring(lenwaveflag); if(!waveflag.endswith("wave")) throw new illegalargumentexception("wave miss, " + filename + " is not a wave file."); this.fmtubchunk = readstring(lenfmtubchunk); if(!fmtubchunk.endswith("fmt ")) throw new illegalargumentexception("fmt miss, " + filename + " is not a wave file."); this.subchunk1size = readlong(); this.audioformat = readint(); this.numchannels = readint(); this.samplerate = readlong(); this.byterate = readlong(); this.blockalign = readint(); this.bitspersample = readint(); this.datasubchunk = readstring(lendatasubchunk); if(!datasubchunk.endswith("data")) throw new illegalargumentexception("data miss, " + filename + " is not a wave file."); this.subchunk2size = readlong(); this.len = (int)(this.subchunk2size/(this.bitspersample/8)/this.numchannels); this.data = new int[this.numchannels][this.len]; for(int i=0; i<this.len; ++i){ for(int n=0; n<this.numchannels; ++n){ if(this.bitspersample == 8){ this.data[n][i] = bis.read(); } else if(this.bitspersample == 16){ this.data[n][i] = this.readint(); } } } issuccess = true; } catch (exception e) { e.printstacktrace(); } finally{ try{ if(bis != null) bis.close(); if(fis != null) fis.close(); } catch(exception e1){ e1.printstacktrace(); } } } private string readstring(int len){ byte[] buf = new byte[len]; try { if(bis.read(buf)!=len) throw new ioexception("no more data!!!"); } catch (ioexception e) { e.printstacktrace(); } return new string(buf); } private int readint(){ byte[] buf = new byte[2]; int res = 0; try { if(bis.read(buf)!=2) throw new ioexception("no more data!!!"); res = (buf[0]&0x000000ff) | (((int)buf[1])<<8); } catch (ioexception e) { e.printstacktrace(); } return res; } private long readlong(){ long res = 0; try { long[] l = new long[4]; for(int i=0; i<4; ++i){ l[i] = bis.read(); if(l[i]==-1){ throw new ioexception("no more data!!!"); } } res = l[0] | (l[1]<<8) | (l[2]<<16) | (l[3]<<24); } catch (ioexception e) { e.printstacktrace(); } return res; } private byte[] readbytes(int len){ byte[] buf = new byte[len]; try { if(bis.read(buf)!=len) throw new ioexception("no more data!!!"); } catch (ioexception e) { e.printstacktrace(); } return buf; } }
为了绘制波形,因此做了一个从jpanel教程而来的波形绘制面板:
// filename: drawpanel.java // robintang // 2012-08-23 import java.awt.color; import java.awt.graphics; import javax.swing.jpanel; @suppresswarnings("serial") public class drawpanel extends jpanel { private int[] data = null; public drawpanel(int[] data) { this.data = data; } @override protected void paintcomponent(graphics g) { int ww = getwidth(); int hh = getheight(); g.setcolor(color.white); g.fillrect(0, 0, ww, hh); int len = data.length; int step = len/ww; if(step==0) step = 1; int prex = 0, prey = 0; //上一个坐标 int x = 0, y = 0; g.setcolor(color.red); double k = hh/2.0/32768.0; for(int i=0; i<ww; ++i){ x = i; // 下面是个三点取出并绘制 // 实际中应该按照采样率来设置间隔 y = hh-(int)(data[i*3]*k+hh/2); system.out.print(y); system.out.print(" "); if(i!=0){ g.drawline(x, y, prex, prey); } prex = x; prey = y; } } }
有了这些之后就可以调用绘制了,简单的:
// wavefilereaddemo.java // robintang // 2012-08-23 import javax.swing.jframe; public class wavefilereaddemo { /** * @param args */ public static void main(string[] args) { // todo auto-generated method stub string filename = "file.wav"; jframe frame = new jframe(); wavefilereader reader = new wavefilereader(filename); if(reader.issuccess()){ int[] data = reader.getdata()[0]; //获取第一声道 drawpanel drawpanel = new drawpanel(data); // 创建一个绘制波形的面板 frame.add(drawpanel); frame.settitle(filename); frame.setsize(800, 400); frame.setlocationrelativeto(null); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.setvisible(true); } else{ system.err.println(filename + "不是一个正常的wav文件"); } } }
工程的源代码可以在我的百度网盘上找到,直接到开源java
放上效果图一张:
希望本文所述对大家的java程序设计有所帮助。