(これは古くてバグ入りだが、卒研の記録として残しておく。 既に紹介した『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 }