在開發應用程式或是遊戲的時候,常常會需要加入一些音樂或是音效來提示或是取悅使用者。那麼如果是使用Java程式語言的話該如何播放出聲音呢?難不成要像是Csound一樣需要使用振盪器來振盪出不同波形、振幅、頻率的訊號嗎?不用!實際上,Java有提供音樂播放的相關套件,可以直接讀取網路上或是電腦內的音訊檔案(Audio File)。
在Javax函式庫中,提供了AudioInputStream可以用來讀取音訊檔案,但它只能支援WAV、AIFF、AU等PCM(Pulse-code modulation)格式,如果要能播放如MP2、MP3等其他有編碼壓縮過音訊格式的話,可以使用JavaFX提供的MediaPlayer或AudioClip,或是第三方的Java函式庫。
使用MediaPlayer或AudioClip播放音訊
AudioClip能播放的音訊格式有非常多種,如果想要知道有哪幾種的話,可以使用MediaManager的getSupportedContentTypes方法來取得。
MediaManager.getSupportedContentTypes();
AudioClip使用方式十分簡單,只要將其實體化後再使用play方法即可。
AudioClip plonkSound = new AudioClip(url);
plonkSound.play();
MediaPlayer是AudioClip的進階版本,提供多種取得媒體資訊及播放控制的方法。
MediaPlayer plonkSound = new MediaPlayer(new Media(uri));
plonkSound.play();
雖然使用MediaPlayer或AudioClip來播放聲音十分方便,但是MediaPlayer或AudioClip的跨平台性實在不怎麼好,因為它的音樂解碼器仰賴於執行的作業系統上的音訊解碼器(函式庫),所以可能會在某些平台下無法播放某些特定的格式。因此,最保險的作法,還是將Java要播放的音樂都轉成WAV、AIFF或是AU格式,然後使用以下提到的AudioInputStream來播放。
使用AudioInputStream播放音訊
AudioInputStream會使用JDK Service提供的AudioFileReader來讀取音訊檔案,建立AudioInputStream實體可以透過AudioSystem的getAudioInputStream方法,程式如下:
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
由於AudioInputStream只是一個輸入串流,並有沒辦法控制聲音的播放與輸出,因此我們必須要有一個時間軸。要產生出一個時間軸前,我們必須要先知道音訊的SampleRate、Bitrate、Size等等重要的資訊,可以透過AudioInputStream的getFormat方法來取得。
AudioFormat audioFormat = audioInputStream.getFormat();
再來就是利用這些資訊,建立出時間軸,時間軸可以使用繼承DataLine的Clip物件。要建立出Clip物件,可以先建立出DataLine的Info物件後,再使用AudioSystem的getLine方法取得Clip物件,然後再用這個擁有audioFormat資訊的Clip物件去開啟audioInputStream。javax把這個部份搞得有點複雜,程式如下:
int bufferSize = (int) Math.min(audioInputStream.getFrameLength() * audioFormat.getFrameSize(), Integer.MAX_VALUE); //緩衝大小,如果音訊檔案不大,可以全部存入緩衝空間。這個數值應該要按照用途來決定
DataLine.Info dataLineInfo = new DataLine.Info(Clip.class, audioFormat, bufferSize);
Clip clip = (Clip) AudioSystem.getLine(dataLineInfo);
clip.open(audioInputStream);
再來就可以使用Clip物件的start、stop等等的方法來控制聲音的播放了!
使用MagicAudioPlayer播放音訊
MagicAudioPlayer是一個基於AudioInputStream和MediaPlayer所實作出來的聲音播放器,因此除了能支援WAV、AIFF或是AU等未壓縮音訊格式之外,還可以藉由系統函式庫的幫助來支援MP3、AAC等音訊格式。
取得MagicAudioPlayer
GitHub:
使用MagicAudioPlayer
MagicAudioPlayer的使用方法十分容易,只要將其實體化後再使用play方法即可。讀取音訊檔案的方式如下:
File audioFile = new File("/home/magiclen/test.wav");
AudioPlayer player = AudioPlayer.createPlayer(audioFile);
player.play();
也可以用URL當作音訊來源:
AudioPlayer player = AudioPlayer.createPlayer(url);
player.play();
如果要暫停、停止播放的話,可以使用pause與stop方法。
player.pause();
player.stop();
如果要設定播放次數以及播放完成後自動關閉並釋放資源的話,可以使用setPlayCount和setAutoClose方法,程式如下:
player.setPlayCount(2);
player.setAutoClose(true);
另外還可以使用setVolume和setBalance方法設定播放的音量以及左右聲道的平衡,程式如下:
player.setVolume(100);
player.setBalance(100);
如果要取得AudioPlayer目前的狀態,可以使用getStatus方法,如下:
AudioPlayer.Status status = player.getStatus();
如果要監聽AudioPlayer的狀態改變事件,可以使用setStatusChangedListener方法,如下:
player.setStatusChangedListener((previousStatus, currentStatus) -> {
switch (currentStatus) {
case OPEN:
break;
case START:
break;
case STOP:
break;
case CLOSE:
break;
}
});
當然也可以取得與設定目前播放的位置,如下:
long position = player.getAudioPosition();
//往前一秒
player.setAudioPosition(position + 1000000);