1. 程式人生 > >Java 音樂播放器開發學習之——音訊檔案的播放

Java 音樂播放器開發學習之——音訊檔案的播放

Java Sound API是javaSE平臺提供底層的(low-level)處理聲音介面,可以實現音訊檔案的播放。

其核心包括:

 

  • AudioSystem
  • AudioInputStream
  • AudioFormat
  • DataLine.Info
  • SourceDataLine
  • TargetDataLine等

AudioSystem的預設輸入裝置是麥克風,預設輸出裝置是揚聲器:

  1. SourceDataLine:源資料流,指AudioSystem的輸入流,把音訊檔案寫入到AudioSystem中
  2. TargetDataLine:目標資料流,指AudioSystem的輸出流
  3. 當播放檔案時,把檔案內容寫入AudioSystem的SourceDataLine
  4. 當錄音時,把AudioSystem的TargetDataLine中的內容讀入記憶體

 

關於該API的基礎知識,請各位自行查閱API,以下給出一個用來播放音訊檔案的Demo

 

 
  1. package com.ywq3;

  2.  
  3. import java.io.File;

  4. import java.io.IOException;

  5.  
  6. import javax.sound.sampled.AudioFormat;

  7. import javax.sound.sampled.AudioInputStream;

  8. import javax.sound.sampled.AudioSystem;

  9. import javax.sound.sampled.DataLine;

  10. import javax.sound.sampled.SourceDataLine;

  11.  
  12. public class Test {

  13. public static void main(String[] args) throws Exception, IOException {

  14. AudioInputStream audioInputStream;// 檔案流

  15. AudioFormat audioFormat;// 檔案格式

  16. SourceDataLine sourceDataLine;// 輸出裝置

  17. File file = new File("D:\\music.wav");

  18.  
  19.  
  20. // 取得檔案輸入流

  21. audioInputStream = AudioSystem.getAudioInputStream(file);

  22. audioFormat = audioInputStream.getFormat();

  23. // 轉換檔案編碼

  24. if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {

  25. audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,

  26. audioFormat.getSampleRate(), 16, audioFormat.getChannels(),

  27. audioFormat.getChannels() * 2, audioFormat.getSampleRate(),

  28. false);

  29. audioInputStream = AudioSystem.getAudioInputStream(audioFormat,

  30. audioInputStream);

  31. }

  32.  
  33. // 開啟輸出裝置

  34. DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class,

  35. audioFormat, AudioSystem.NOT_SPECIFIED);

  36. sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);

  37. sourceDataLine.open(audioFormat); // 開啟具有指定格式的行,這樣可以使行獲得所有所需的系統資源並變得可操作

  38. sourceDataLine.start(); // 允許某一資料行執行資料I/O

  39.  
  40. byte tempBuffer[] = new byte[320];

  41. try {

  42. int cnt;

  43. // 讀取資料到快取區

  44. // 從音訊流讀取指定的最大數量的資料位元組,並將其放入給定的位元組陣列中。

  45. // return: 讀入緩衝區的總位元組數;如果因為已經到達流末尾而不再有更多資料,則返回-1

  46. while ((cnt = audioInputStream.read(tempBuffer, 0,

  47. tempBuffer.length)) != -1) {

  48. if (cnt > 0) {

  49. // 寫入快取資料

  50. sourceDataLine.write(tempBuffer, 0, cnt); // 通過此源資料行將音訊資料寫入混頻器

  51. }

  52. }

  53. // Block等待臨時資料被輸出為空

  54. // 通過在清空資料行的內部緩衝區之前繼續資料I/O,排空資料行中的列隊資料

  55. sourceDataLine.drain();

  56. // 關閉行,指示可以釋放的該行使用的所有系統資源。如果此操作成功,則將行標記為 closed,並給行的偵聽器指派一個 CLOSE 事件。

  57. sourceDataLine.close();

  58. } catch (Exception e) {

  59. e.printStackTrace();

  60. System.exit(0);

  61. }

  62. }

  63. }


若程式正常執行,我們應該可以聽到D盤下的一個叫做music.wav的音訊檔案被播放。

 

若程式報錯:

Exception in thread "main" javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1189)
at com.ywq3.Test.main(Test.java:21)

 

異常資訊是說,不支援的格式,即該音訊檔案不支援,得不到該檔案的輸入流。

 

原因分析:

 

      Javax sound API預設支援的格式通過AudioFileFormate原始碼可以看出,是支援wav檔案的,如下所示:

 

 

開始我百思不得其解,後來發現wav格式的音訊檔案是有其固定格式的,若明明是wav檔案,卻報錯說不支援該格式,則可能是該wav檔案內部格式有錯誤。

 

關於wav內部格式請詳見:http://blog.csdn.net/y96q1023/article/details/70307753

 

我先前使用的一個wav檔案是直接通過io流合成的,所以一直報不支援的錯誤。後來使用了一個正確的wav檔案,則可以播放。

 

下邊給出一段如何使用javax sound合成wav音訊檔案的Demo,希望可以幫到各位小夥伴~

 
  1. import java.io.File;

  2. import java.io.IOException;

  3. import java.io.SequenceInputStream;

  4. import javax.sound.sampled.AudioFileFormat;

  5. import javax.sound.sampled.AudioInputStream;

  6. import javax.sound.sampled.AudioSystem;

  7.  
  8. public class WavAppender {

  9. public static void main(String[] args) {

  10. String wavFile1 = "D:\\wav1.wav";

  11. String wavFile2 = "D:\\wav2.wav";

  12.  
  13. try {

  14. AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));

  15. AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));

  16.  
  17. AudioInputStream appendedFiles =

  18. new AudioInputStream(

  19. new SequenceInputStream(clip1, clip2),

  20. clip1.getFormat(),

  21. clip1.getFrameLength() + clip2.getFrameLength());

  22.  
  23. AudioSystem.write(appendedFiles,

  24. AudioFileFormat.Type.WAVE,

  25. new File("D:\\wavAppended.wav"));

  26. } catch (Exception e) {

  27. e.printStackTrace();

  28. }

  29. }

  30. }


 

如果對你有幫助,記得點贊哦~歡迎大家關注我的部落格,可以進群366533258一起交流學習哦~

 

本群給大家提供一個學習交流的平臺,內設菜鳥Java管理員一枚、精通演算法的金牌講師一枚、Android管理員一枚、藍芽BlueTooth管理員一枚、Web前端管理一枚以及C#管理一枚。歡迎大家進來交流技術。