前回のJavaでWAVファイルを再生するでは、あまりにもとりあえず過ぎたので、ちょっとはましなコードにしてみました。今回は、再生を一時停止しても読み込んだデータをスキップせずにちゃんと出力するようにしました。なお、LineListenerは今回ははずしました。必要があれば、前回のソースを参照してください。
public class RenderAudioFile implements Runnable { protected AudioInputStream fileStream = null; protected SourceDataLine sourceDataLine = null; private byte sampleBuffer[]; //データ受け渡し用のバッファ private ByteBuffer sampleByteBuffer; //バッファ参照用のByteBuffer public void openFile(File file) throws UnsupportedAudioFileException, IOException, LineUnavailableException { //出力するファイルを受け取るメソッド fileStream = AudioSystem.getAudioInputStream(file); AudioFormat format = fileStream.getFormat(); sourceDataLine = AudioSystem.getSourceDataLine(format); sourceDataLine.addLineListener(this); sourceDataLine.open(format); sampleBuffer = new byte[sourceDataLine.getBufferSize()]; sampleByteBuffer.wrap(sampleBuffer); } public void close() { //ファイルを閉じるメソッド fileStream.close(); fileStream = null; } public void play() { // 再生開始、再開用メソッド if(sourceDataLine == null || fileStream == null) { return; } sourceDataLine.start(); new Thread(this).start(); } public void pause() { // 一時停止メソッド if(sourceDataLine == null || fileStream == null) { return; } sourceDataLine.stop(); } public void run() { //再生スレッドのメソッド do { if (sampleByteBuffer.position() == 0) { try { int readSize = inputStream.read(sampleBuffer); if (readSize <= 0) { sourceDataLine.stop(); break; } sampleByteBuffer.position(readSize); } catch (IOException e) { sourceDataLine.stop(); break; } } soundByteBuffer.flip(); int writeSize = dataLine.write(sampleBuffer, 0, sampleByteBuffer.remaining()); if (writeSize >0) { putSampleData(sampleBuffer, writeSize); sampleByteBuffer.position(writeSize); } sampleByteBuffer.compact(); } while (sourceDataLine.isRunning()); } }
とりあえず、普通に再生するには問題ないのですが、まだ、手を抜いてあるところがあります。
- ファイルをすべて再生しきったときの処理
- 再生位置の変更
いずれも、自由に再生を開始する位置を変更できればよいのですが、これらを実現するために使えそうなメソッドとして、AudioInputStream.mark()とAudioInputStream.reset()というのがあります。これは、mark()で再生位置を保存しておいて、reset()でその位置に移動するというものです。 ただし、これらのメソッドはInputStreamによって、使えたり使えなかったりしますが、それを調べるためにAudioInputStream.markSupported()というメソッドがあります。再生しようとするファイルや環境に依存するかもしれませんが作ったプログラムでは、markSupported()はfalseを返してきます。すなわち、mark(),reset()が使えないということです。
とすると、どうすればいいかというと、再生位置を先頭に戻すには、一度close()してから再度open()するという処理しかなさそうです。さらに任意の位置に移動させるには、skip()を使うという方法しかないようです。