(これは古くてバグ入りだが、卒研の記録として残しておく。 既に紹介した『JavaでHelloWorldサウンド編』を参考にしたのだが、 卒研が終ってから、赤間 [7] という本を見つけて、 それを見れば楽だったはず。)
http://nalab.mind.meiji.ac.jp/~mk/program/sound/ReadWave.java
ReadWave.java は、 Waveファイルを読み込んで、音を鳴らしながら、 音声データを数値表示するプログラムである。 オーディオ・データの形式は、 Java のクラス・ライブラリィが調べてくれるので、 自前で解析する手間は省けている (Cf: readwave.c)。
| コンパイル&実行 |
knoppix$ javac ReadWave.java knoppix$ java ReadWave piano.wav > piano.txt |
チェック用に http://nalab.mind.meiji.ac.jp/~mk/labo/2007/piano.wav と http://nalab.mind.meiji.ac.jp/~mk/labo/2007/piano.txt を公開しておく。
ソース・プログラムは案外長いが、 (i) 16ビット・ステレオ、(ii) 8ビット・ ステレオ、 (iii) 16ビット・モノラル、(iv) 8ビット・モノラル、と4つに場合 分けしてあるからである (本当はこれにエンディアンの違いと、 符号の有無の違いで、さらに場合分けする必要があるが、それは無視した -- と書いたのだけど、これは誤解かも知れない (2013/10)。)。
1 //
2 // ReadWave.java
3 // 2008/1/30 初めて作成
4 // 2008/2/13 一木君にバグを指摘される。Byte は符号付きだった。
5 // 2008/2/15 やはりビット演算だけで記述することにした。
6 //
7
8 import java.io.File;
9 import javax.sound.sampled.*;
10
11 public class ReadWave {
12 private static final int EXTERNAL_BUFFER_SIZE = 128000;
13 public static void main(String[] args) {
14 int frameSize; //
15 int sampleSizeInBits; // 音声データの数値のビット数 (16または8)
16 int channels; // チャンネルの数 (2がステレオ, 1がモノラル)
17 float sampleRate; // サンプリングレート (1秒間の...)
18 boolean isStereo; // ステレオか
19 boolean isBigEndian; // ビッグエンディアンか (上位バイトが先か)
20 if (args.length == 0) System.exit(0);
21 try {
22 // Fileクラスのインスタンスを生成する
23 File soundFile = new File(args[0]);
24 // オーディオ入力ストリームを取得する
25 AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile);
26 // オーディオフォーマットを取得する
27 AudioFormat audioFormat = audioInputStream.getFormat();
28
29 // データラインの情報オブジェクトを生成する
30 DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
31 // 指定されたデータライン情報に一致するラインを取得する
32 SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
33 // 指定されたオーディオ形式でラインを開きます
34 line.open(audioFormat);
35 // ラインでのデータ入出力を可能にします
36 line.start();
37
38 // データの形式を読み取る
39 channels = audioFormat.getChannels();
40 isStereo = (channels == 2);
41 isBigEndian = audioFormat.isBigEndian();
42 frameSize = audioFormat.getFrameSize();
43 sampleSizeInBits = audioFormat.getSampleSizeInBits();
44 sampleRate = audioFormat.getSampleRate();
45 System.out.println("#original file: " + args[0]);
46 System.out.println("#number of channels: " + channels);
47 System.out.println("#sampling rate: " + sampleRate);
48 System.out.println("#number of bits per sample: " + sampleSizeInBits);
49 System.out.println("#FrameSize: " + frameSize);
50 System.out.println("#isBigEndian: " + isBigEndian);
51 if (audioFormat.getEncoding() == AudioFormat.Encoding.PCM_SIGNED) {
52 System.out.println("#PCM Signed");
53 }
54 else if (audioFormat.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED) {
55 System.out.println("#PCM Unsigned!!!");
56 System.exit(0);
57 }
58 else {
59 System.out.println("#NO PCM!!");
60 System.exit(0);
61 }
62
63 // 音声データを読み取り、鳴らして、数値を表示
64 int nBytesRead = 0;
65 byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
66 if (isStereo) {
67 if (sampleSizeInBits == 16) {
68 // 16ビットステレオ (フツー)
69 while (nBytesRead != -1) {
70 // オーディオストリームからデータを読み込みます
71 nBytesRead = audioInputStream.read(abData, 0, abData.length);
72 if (nBytesRead >= 0) {
73 // オーディオデータをミキサーに書き込みます
74 int nBytesWritten = line.write(abData, 0, nBytesRead);
75 for (int i = 0; i < nBytesRead; i += 4) {
76 short left, right;
77 left = (short)(abData[i] & 0xff | (abData[i+1] << 8));
78 right = (short)(abData[i+2] & 0xff | (abData[i+3] << 8));
79 System.out.println("" + left + " " + right);
80 }
81 }
82 }
83 }
84 else { // sampleSizeInBits == 8
85 // 8ビットステレオ (フツー)
86 while (nBytesRead != -1) {
87 // オーディオストリームからデータを読み込みます
88 nBytesRead = audioInputStream.read(abData, 0, abData.length);
89 if (nBytesRead >= 0) {
90 // オーディオデータをミキサーに書き込みます
91 int nBytesWritten = line.write(abData, 0, nBytesRead);
92 for (int i = 0; i < nBytesRead; i += 2) {
93 short left, right;
94 left = (short)(abData[i] & 0xff);
95 right = (short)(abData[i+1] & 0xff);
96 System.out.println("" + left + " " + right);
97 }
98 }
99 }
100 }
101 }
102 else {
103 // モノラル
104 if (sampleSizeInBits == 16) {
105 // 16ビットモノラル
106 while (nBytesRead != -1) {
107 // オーディオストリームからデータを読み込みます
108 nBytesRead = audioInputStream.read(abData, 0, abData.length);
109 if (nBytesRead >= 0) {
110 // オーディオデータをミキサーに書き込みます
111 int nBytesWritten = line.write(abData, 0, nBytesRead);
112 for (int i = 0; i < nBytesRead; i += 2) {
113 short c;
114 c = (short)(abData[i] & 0xff | (abData[i+1] << 8));
115 System.out.println("" + c);
116 }
117 }
118 }
119 }
120 else { // sampleSizeInBits == 8
121 // 8ビットモノラル
122 while (nBytesRead != -1) {
123 // オーディオストリームからデータを読み込みます
124 nBytesRead = audioInputStream.read(abData, 0, abData.length);
125 if (nBytesRead >= 0) {
126 // オーディオデータをミキサーに書き込みます
127 int nBytesWritten = line.write(abData, 0, nBytesRead);
128 for (int i = 0; i < nBytesRead; i++) {
129 short c;
130 c = (short)(abData[i] & 0xff);
131 System.out.println("" + c);
132 }
133 }
134 }
135 }
136 }
137 // ラインからキューに入っているデータを排出します
138 line.drain();
139 // ラインを閉じます
140 line.close();
141
142 System.exit(0);
143 } catch (Exception e) {
144 e.printStackTrace();
145 System.exit(1);
146 }
147 }
148 }