本文实例讲述了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
for(int n=0; 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
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程序设计有所帮助。
希望与广大网友互动??
点此进行留言吧!