wavファイルの波形を表示させる(3)

スポンサーリンク

wavファイルの内容を表示するプログラムを作っています。今の所「ウインドウの表示とグラフ領域の描画」「wavファイルからのデータ取得」までできました。今度はこれらを結びつける処理を作ります。

wavファイルの波形を表示させる(1)
wavファイルの波形を表示させる(2)

データ取得部分のメソッド化

前回処理だけ書いたのでこれをメソッドにしておきます。ファイルの情報と取得するサイズを引数で指定してデータを可変配列で取得できるようにします。データの他にサンプルサイズも取得しておきます。縦方向の座標の調整のために最大値を求めるにはサンプルサイズが必要です。ここではWavDataというクラス内クラスを定義しています。

public WavData readWavData(File wav_file, int size) throws IOException, UnsupportedAudioFileException{
  AudioInputStream input_stream = AudioSystem.getAudioInputStream(wav_file);
  AudioFormat format = input_stream.getFormat();
  format = new AudioFormat(format.getFrameRate(), format.getSampleSizeInBits(), format.getChannels(), true, true);
  input_stream = AudioSystem.getAudioInputStream(format, input_stream);

  int sample_size = format.getSampleSizeInBits() / 8;
  WavData data = new WavData();
  data.sample_size = sample_size;
  while (data.size() < size) {
    byte[] buffer = new byte[8];
    input_stream.read(buffer, 8 - sample_size, sample_size);
    if(buffer[8 - sample_size] < 0){
      for(int i = 0; i < 8 - sample_size;i++){
        buffer[i] = -1;
      }
    }
    data.add(ByteBuffer.wrap(buffer).getLong());
  }
  return data;
}
class WavData extends ArrayList {
  int sample_size;
}

注意が必要なのはこのファイルで取得するwavデータはモノラルしか想定していないということです。もしステレオであれば一つおきにデータを取るか描画を左右別々にするなど考慮が必要です。これは後々必要な時に心配することにします。

グラフの描画

前々回横800ピクセル縦600ピクセルのパネルにグラフ領域を作りました。グラフ領域が余白が10ピクセルずつ上下左右につきます。左右の座標は10〜790、上下の座標は10〜590までとなっていて左右方向は2ピクセルに1個ずつ点をうつことになり両はしを合わせると

(790 - 10) / 2 + 1

391個の点が必要です。x座標は0番目のデータの座標が10でその次が12になります。
for分を使って繰り返しを行います。

for(int i = 0;i < (width / 2);i++){

x座標は次のように求めます。

int x1 = 10 + i * 2;

縦方向を考えると最大値の座標が10で最小値の座標が590で無音を表す中央が300になります。実際の値はサンプルサイズにより変わってきます。

サンプルサイズに応じた最大値と最小値を取得する

2バイトの場合は

-32768.0 ~ 32767.0

の範囲でしたので最大値を計算で出します。

double max = Math.pow(2, sample_size * 8 - 1) - 1;

y座標は0の地点から(音量/最大値)の分をマイナスします。パネルのY座標は数値が増えるほど下に行くので注意が必要です。

int y1 = 10 + height / 2 - (int)(height / 2 * data.get(i) / max);

xとyの座標が求まりました。同じように次の値を元にのxとyの値を求めて線を引きます。

g.drawLine(x1, y1, x2, y2);

実装する

今までの処理をまとめると次のようなコードができます。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GraphTest extends JPanel {

  @Override
  public void paint(Graphics g) {
    Dimension d = getSize();

    g.setColor(Color.WHITE);
    g.fillRect(0, 0, (int) d.getWidth(), (int) d.getWidth());

    int width = (int) d.getWidth() - 20;
    int height = (int) d.getHeight() - 20;
    g.setColor(new Color(0xF0, 0xF0, 0xF0));
    g.fillRect(10, 10, width, height);
    g.setColor(new Color(0, 0, 0));
    g.drawLine(10, 10 + height / 2, width + 10, 10 + height / 2);
    WavData data;
    try {
      data = readWavData(new File("/Users/myaccount/mywork/square_440.wav"), 400);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    int sample_size = data.sample_size;
    double max = Math.pow(2, sample_size * 8 - 1) - 1;
    for (int i = 0; i < (width / 2); i++) {
      int x1 = 10 + i * 2;
      int y1 = 10 + height / 2 - (int) (height / 2 * data.get(i) / max);
      int x2 = 10 + (i + 1) * 2;
      int y2 = 10 + height / 2 - (int) (height / 2 * data.get(i + 1) / max);
      g.drawLine(x1, y1, x2, y2);
    }

  }

  public WavData readWavData(File wav_file, int size) throws IOException, UnsupportedAudioFileException {
    AudioInputStream input_stream = AudioSystem.getAudioInputStream(wav_file);
    AudioFormat format = input_stream.getFormat();
    format = new AudioFormat(format.getFrameRate(), format.getSampleSizeInBits(), format.getChannels(), true, true);
    input_stream = AudioSystem.getAudioInputStream(format, input_stream);

    int sample_size = format.getSampleSizeInBits() / 8;
    WavData data = new WavData();
    data.sample_size = sample_size;
    while (data.size() < size) {
      byte[] buffer = new byte[8];
      input_stream.read(buffer, 8 - sample_size, sample_size);
      if (buffer[8 - sample_size] < 0) {
        for (int i = 0; i < 8 - sample_size; i++) {
          buffer[i] = -1;
        }
      }
      data.add(ByteBuffer.wrap(buffer).getLong());
    }
    return data;
  }

  class WavData extends ArrayList {

    int sample_size;
  }

  public static void main(String[] args) {

    JFrame frame = new JFrame();
    frame.getContentPane().add(new GraphTest());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setVisible(true);
  }

}

これを実行すると次のようになウインドウが出てきます。

screen-shot-2016-11-09-at-18-00-56

矩形波の様子が表示されました。このコードはまだまだ改善の余地がありますがひとまずwavファイルを読み込みグラフを表示させるところまではできました。

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

%d人のブロガーが「いいね」をつけました。