今回はwavファイルから必要なデータを抜き出す処理を作ります。前回ウィンドウを作りました。グラフの領域は横が余白をのぞいて780ピクセルあります。ここに波形を表示したいと思います。問題はサンプルしている全てのデータを表示しきれないことです。サンプルレートが48000、長さが3秒なので14万以上のサンプル数、これを780ピクセルに表示するには間引きが必要です。また3秒間全てを表示したいわけではなく波形を見たいので前後3周期で純分でしょう。440Hzの音の1周期の長さは1/440秒ですから3周期のサンプル数は
48000 / 440 x 3
で327と少し。これであれば2ピクセルごとに1サンプルを描画すれば良いでしょう。780ピクセルなので余裕をもって400サンプル取ります。
今回は処理の流れのみ見ていきます。
処理の説明
インポートは以下の通りです。
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;
次に前回作ったファイルを読み込む準備をします。
AudioInputStream input_stream = AudioSystem.getAudioInputStream(new File("/Users/myaccount/mywork/square_440.wav"));
こちらで動かして見たところ読み込みフォーマットのうちBigEndienではなくLittleEndienになっていました。このため他の項目を変えずBigEndienにして開き直します。
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;
データを保持する可変の配列を準備します。
ArrayList data = new ArrayList<>();
とりあえず400個のサンプリングを取るように取得サイズを決めておきます。
int size = 400;
サイズ通り取得できるようにwhile文を使います。
while (data.size() < size) { //取得処理 }
ここから取得処理の詳細です。まずlongに変換できるように8つのバイト配列を作ります。実際には2バイトしか読みませんが下段の処理で8個の配列が用意されていないと変換できません。
byte[] buffer = new byte[8];
2バイト分を下二桁に読み込みます。
input_stream.read(buffer, 8 - sample_size, sample_size);
このままでは負の数字の処理がうまくいきません。今のままでは2バイトであれば
11111111 00000001
となり-32767になるのですがbyte配列の上6桁は未設定のため0になります。すると
00000000 00000000 00000000 00000000 00000000 00000000 11111111 00000001
となりlong値では32769という正の数字になってしまいます。long値で同じ値にするには以下のように上6桁のビット全てを立てます。
11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000001
以下のような処理を追加します。
if(buffer[8 - sample_size] < 0){ for(int i = 0; i < 8 - sample_size;i++){ buffer[i] = -1; } }
これをlong値にして配列に追加すれば取得処理は終わりです。
data.add(ByteBuffer.wrap(buffer).getLong());
表示確認
最後に取得したデータが正しいか確かめます。
for(long value:data){ System.out.println(value); }
結果は以下の通り、正しい値が取れました。
32767 32767 (中略) 32767 -32767 -32767 (中略) -32767 32767 32767 (中略)