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程序设计有所帮助。

(0)

相关推荐

  • Java实现按行读取大文件

    Java实现按行读取大文件 String file = "F:" + File.separator + "a.txt"; FileInputStream fis = new FileInputStream(file); RandomAccessFile raf = new RandomAccessFile(new File(file),"r"); String s ; while((s =raf.readLine())!=null){ Syste

  • java读取解析xml文件实例

    读取本地的xml文件,通过DOM进行解析,DOM解析的特点就是把整个xml文件装载入内存中,形成一颗DOM树形结构,树结构是方便遍历和和操纵. DOM解析的特性就是读取xml文件转换为 dom树形结构,通过节点进行遍历. 这是W3c关于节点的概念 如果xml中包含有大量的数据,由于dom一次性把xml装入内存中的特性,所以dom不适合于包含大量数据的xml解析.当包含有大量xml的时候,用SAX进行解析比较节省内存. 下面是一个运用DOM进行解析xml文件的例子: xml文件结构如下: <?xm

  • java实现读取、删除文件夹下的文件

    java实现读取.删除文件夹下的文件 package test.com; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; public class ReadFile { public ReadFile() { } /** * 读取某个文件夹下的所有文件 */ public static boolean readfile(String filepath) throws Fi

  • Java基于IO流读取文件的方法

    本文实例讲述了Java基于IO流读取文件的方法.分享给大家供大家参考,具体如下: public static void readFile(){ String pathString = TEST.class.getResource("/simu").getFile(); try { pathString = URLDecoder.decode(pathString, "utf-8"); } catch (UnsupportedEncodingException e1)

  • java实现分段读取文件并通过HTTP上传的方法

    本文实例讲述了java实现分段读取文件并通过HTTP上传的方法.分享给大家供大家参考.具体如下: 1.首先将文件分段,用RandomAccessFile 2.分段后将分出的内容上传到http URL url = new URL(actionUrl); HttpURLConnection con = (HttpURLConnection) url.openConnection(); /** 允许Input.Output,不使用Cache */ con.setDoInput(true); con.s

  • java读取properties配置文件的方法

    本文实例讲述了java读取properties配置文件的方法.分享给大家供大家参考.具体分析如下: 这两天做java项目,用到属性文件,到网上查资料,好半天也没有找到一个满意的方法能让我读取到.properties文件中属性值,很是郁闷,网上讲的获取属性值大概有以下方法,以下三种方法逐渐优化,以达到最好的效果以下都以date.properties文件为例,该文件放在src目录下,文件内容为: startdate=2011-02-07 totalweek=25 方法一: public class

  • JavaScript操作XML文件之XML读取方法

    本文实例讲述了JavaScript操作XML文件之XML读取方法.分享给大家供大家参考.具体分析如下: 假设我们现在要读取下面的 info.xml 文件 <?xml version="1.0" encoding="gb2312"?> <root> <data id="1"> <name>ceun</name> <age>21</age> </data>

  • Java数据导入功能之读取Excel文件实例

    在编程中经常需要使用到表格(报表)的处理主要以Excel表格为主.下面给出用java读取excel表格方法: 1.添加jar文件 java导入导出Excel文件要引入jxl.jar包,最关键的是这套API是纯Java的,并不依赖Windows系统,即使运行在Linux下,它同样能够正确的处理Excel文件.下载地址:http://www.andykhan.com/jexcelapi/ 2.jxl对Excel表格的认识 (1)每个单元格的位置认为是由一个二维坐标(i,j)给定,其中i表示列,j表示

  • java读取wav文件(波形文件)并绘制波形图的方法

    本文实例讲述了java读取wav文件(波形文件)并绘制波形图的方法.分享给大家供大家参考.具体如下: 因为最近有不少网友询问我波形文件读写方面的问题,出于让大家更方便以及让代码能够得到更好的改进,我将这部分(波形文件的读写)代码开源在GitHub上面. 地址为https://github.com/sintrb/WaveAccess/,最新的代码.例子.文档都在那上面,我会在我时间精力允许的前提下对该项目进行维护,同时也希望对这方面有兴趣的网友能够加入到该开源项目上. 以下内容基本都过期了,你可以

  • Java读取Properties文件的七种方法的总结

    Java读取Properties文件的方法总结 读取.properties配置文件在实际的开发中使用的很多,总结了一下,有以下几种方法: 其实很多都是大同小异,概括起来就2种: 先构造出一个InputStream来,然后调用Properties#load() 利用ResourceBundle,这个主要在做国际化的时候用的比较多. 例如:它能根据系统语言环境自动读取下面三个properties文件中的一个: resource_en_US.properties resource_zh_CN.prop

  • Java读取txt文件和写入txt文件的简单实例

    写Java程序时经常碰到要读如txt或写入txt文件的情况,但是由于要定义好多变量,经常记不住,每次都要查,特此整理一下,简单易用,方便好懂! package edu.thu.keyword.test; import java.io.File; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream;

  • java读取properties文件的方法实例分析

    本文实例讲述了java读取properties文件的方法.分享给大家供大家参考.具体分析如下: 1.不在项目中读取: Properties properties = new Properties(); BufferedReader read = new BufferedReader(new InputStreamReader(new FileInputStream("文件的路径"),"utf-8")); properties.load(read); properti

  • java读取properties文件的方法

    本文实例讲述了java读取properties文件的方法.分享给大家供大家参考.具体实现方法如下: package com.test.demo; import java.util.Properties; import java.io.InputStream; import java.io.IOException; /** * 读取Properties文件的例子 * File: TestProperties.java */ public final class TestProperties { p

  • 完美解决java读取大文件内存溢出的问题

    1. 传统方式:在内存中读取文件内容 读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法: Files.readLines(new File(path), Charsets.UTF_8); FileUtils.readLines(new File(path)); 实际上是使用BufferedReader或者其子类LineNumberReader来读取的. 传统方式的问题: 是文件的所有行都被存放在内存中,当文件足够大时很快就会

  • java读取txt文件代码片段

    本文实例为大家分享了java读取txt文件的具体代码,供大家参考,具体内容如下 学习小记: 1.首先要根据路径获取你的 txt 文本文件.File file = new File(path); 2.将获取到的这个字节码流读进缓存.new FileInputStream(file) ; 3.然后对刚才读进缓存的输入流进行解读,生成对应字节流.InputStreamReader(readIn) 4.再然后通过 BufferedReader 这个类进行一行一行的输出.bufferedReader.re

  • Java读取txt文件的方法

    java读取txt文件内容.可以作如下理解: 首先获得一个文件句柄.File file = new File(); file即为文件句柄.两人之间连通电话网络了.接下来可以开始打电话了. 通过这条线路读取甲方的信息:new FileInputStream(file) 目前这个信息已经读进来内存当中了.接下来需要解读成乙方可以理解的东西 既然你使用了FileInputStream().那么对应的需要使用InputStreamReader()这个方法进行解读刚才装进来内存当中的数据 解读完成后要输出

  • Java读取TXT文件内容的方法

    Java读取txt文件内容.可以作如下理解: 首先获得一个文件句柄.File file = new File(); file即为文件句柄.两人之间连通电话网络了.接下来可以开始打电话了. 通过这条线路读取甲方的信息:new FileInputStream(file) 目前这个信息已经读进来内存当中了.接下来需要解读成乙方可以理解的东西 既然你使用了FileInputStream().那么对应的需要使用InputStreamReader()这个方法进行解读刚才装进来内存当中的数据 解读完成后要输出

  • 详解Java读取本地文件并显示在JSP文件中

    详解Java读取本地文件并显示在JSP文件中 当我们初学IMG标签时,我们知道通过设置img标签的src属性,能够在页面中显示想要展示的图片.其中src的值,可以是磁盘目录上的绝对,也可以是项目下的相对路径,还可以是网络上的图片路径.在存取少量图片的情况下,采用相对路径存储图片的情况下最方便,也最实用.但是当图片数量过多时,这种方式就显的有些掣肘了. 当系统的图片数量过多时,如果仍把这些图片当做项目的一部分去发布,势必会大大延长项目的发布时间及更新时间.对于某些对于时限性要求特别高的系统来说,采

随机推荐