在本篇文章中,我們將學習如何用Java播放音樂,Java 聲音 API 的設計是為了流暢和連續地播放聲音,甚至是很長的聲音。我們將使用 Java 提供的 Clip
和 SourceDataLine
聲音API播放一個音頻文件。
播放聲音的Java APIs
一般來說,javax.sound
包中的Java Sound APIs提供了兩種播放音頻的方法。在這兩種方法之間,在如何指定聲音文件數據方面有區別。Java Sound APIs可以以流式、緩沖方式和內存、非緩沖方式處理音頻傳輸。Java的兩個最著名的聲音API是 Clip
和 SourceDataLine
。
Clip API
Clip
API是Java的一個非緩沖或內存聲音API。Clip
類是javax.sound.sampled
包的一部分,它在讀取和播放短的聲音文件時有用。在播放之前,整個音頻文件被加載到內存中,用戶可以完全控制播放。除了循環播放聲音外,它還允許用戶在一個隨機的位置開始播放。
讓我們首先創建一個示例類,SoundPlayerWithClip
,它實現了LineListener
接口,以便接收播放的線事件(OPEN
、CLOSE
、START
和STOP
)。我們將從LineListener
實現update()
方法來檢查播放狀態。
public class SoundPlayerUsingClip implements LineListener {
boolean isPlaybackCompleted;
@Override
public void update(LineEvent event) {
if (LineEvent.Type.START == event.getType()) {
System.out.println("Playback started.");
} else if (LineEvent.Type.STOP == event.getType()) {
isPlaybackCompleted = true;
System.out.println("Playback completed.");
}
}
}
其次,讓我們從我們項目的資源文件夾中讀取音頻文件。我們的資源文件夾包含三個不同格式的音頻文件--即WAV、MP3和MPEG。
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(audioFilePath);
第三,從文件流中,我們將創建一個AudioInputStream
。
AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);
現在,我們將創建一個DataLine.Info
對象。
AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);
讓我們從這個DataLine.Info
創建一個Clip
對象,并打開流,然后調用start
來開始播放音頻。
Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.addLineListener(this);
audioClip.open(audioStream);
audioClip.start();
最后,我們需要關閉任何開放的資源。
audioClip.close();
audioStream.close();
一旦代碼運行,音頻文件就會播放。
由于音頻被預裝在內存中,我們有許多其他有用的API,我們可以從中受益。
我們可以使用Clip.loop
方法來連續循環播放音頻片段。
例如,我們可以把它設置為播放五次音頻。
audioClip.loop(4);
或者,我們可以設置它無限期地播放音頻(或直到中斷)。
audioClip.loop(Clip.LOOP_CONTINUUSLY);
Clip.setMicrosecondPosition
設置媒體位置。當剪輯下次開始播放時,它將從這個位置開始。例如,要從第30秒開始,我們可以這樣設置。
audioClip.setMicrosecondPosition(30_000_000);
SourceDataLine API
SourceDataLine
API是java的一個緩沖或流式聲音API。SourceDataLine
類是javax.sound.sampled
包的一部分,它可以播放無法預裝到內存中的長聲音文件。
當我們希望優化大的音頻文件的內存時,或者在流傳實時音頻數據時,使用SourceDataLine
更有效。如果我們事先不知道聲音有多長,何時結束,它也很有用。
讓我們首先創建一個示例類,從我們項目的資源文件夾中讀取音頻文件。我們的資源文件夾包含三個不同格式的音頻文件--即WAV、MP3和MPEG。
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(audioFilePath);
第二,從文件輸入流中,我們將創建一個AudioInputStream
。
AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);
現在,我們將創建一個DataLine.Info
對象。
AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);
讓我們從這個DataLine.Info
創建一個SourceDataLine
對象,打開流,并調用start
來開始播放音頻。
SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
現在,在SourceDataLine
的情況下,的音頻數據是分塊加載的,我們需要提供緩沖區的大小。
private static final int BUFFER_SIZE = 4096;
現在,讓我們從AudioInputStream
讀取音頻數據,并將其發送到SourceDataLine的
播放緩沖區,直到它到達流的末端。
byte[] bufferBytes = new byte[BUFFER_SIZE];
int readBytes = -1;
while ((readBytes = audioStream.read(bufferBytes)) != -1) {
sourceDataLine.write(bufferBytes, 0, readBytes);
}
最后,讓我們關閉任何開放的資源。
sourceDataLine.drain();
sourceDataLine.close();
audioStream.close();
一旦代碼運行,音頻文件就會播放。在這里,我們不需要實現任何LineListener
接口。
Clip
和SourceDataLine
之間的比較
讓我們來討論一下兩者的優點和缺點。
Clip | SourceDataLine |
---|---|
支持從音頻的任何位置播放。參見setMicrosecondPosition(long) 或setFramePosition(int). | 不能從聲音中的任意位置開始播放。 |
支持在循環中播放(全部或部分的聲音)。 參見setLoopPoints(int, int) 和loop(int). | 不能播放(循環)全部或部分聲音。 |
可以在播放前知道聲音的持續時間。參見getFrameLength() 或getMicrosecondLength(). | 在播放前不能知道聲音的持續時間。 |
可以在當前位置停止播放,稍后繼續播放。請看stop() 和start() | 不能在中間停止和恢復播放。 |
不適合播放大的音頻文件,也沒有效率,因為它是在內存中的。 | 適合播放長的聲音文件或實時的聲音流。 |
Clip的start()方法確實在播放聲音,但它不會阻塞當前線程(它立即返回),所以它需要實現LineListener接口來了解播放狀態。 | 與Clip不同,我們不需要實現LineListener接口來知道什么時候播放完成。 |
不可能控制什么聲音數據被寫入音頻線的播放緩沖區。 | 可以控制哪些聲音數據要被寫入音頻線的播放緩沖區。 |
Java API對MP3格式的支持
目前,Clip
和SourceDataLine
都可以播放AIFC、AIFF、AU、SND和WAV格式的音頻文件。
我們可以使用AudioSystem
檢查支持的音頻格式。
Type[] list = AudioSystem.getAudioFileTypes();
StringBuilder supportedFormat = new StringBuilder("Supported formats:");
for (Type type : list) {
supportedFormat.append(", " + type.toString());
}
System.out.println(supportedFormat.toString());
然而,我們不能用Java Sound APIs Clip
和 SourceDataLine
播放流行的音頻格式MP3/MPEG。`我們需要尋找一些能播放MP3格式的第三方庫。
如果我們向 Clip
或 SourceDataLine
API提供MP3格式的文件,我們會得到UnsupportedAudioFileException
。
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1189)
總結
在這篇文章中,我們學習了如何用Java播放聲音。我們還了解了兩個不同的Java聲音API - Clip
和 SourceDataLine
。我們了解了 Clip
和 SourceDataLine
API之間的區別。
-
音頻
+關注
關注
29文章
2877瀏覽量
81553 -
緩沖
+關注
關注
0文章
52瀏覽量
17823 -
內存
+關注
關注
8文章
3025瀏覽量
74056 -
JAVA
+關注
關注
19文章
2967瀏覽量
104759 -
API
+關注
關注
2文章
1501瀏覽量
62026
發布評論請先 登錄
相關推薦
評論