top

JavaFX多媒體(1)使用Audio Clip播放音訊

分享:

JavaFX 程式架構 << 前情

在Java Swing中欲處理音訊與影像,需額外安裝Java Media Framework (JMF),JMF為Java S.E.的選項套件,目前版本為JMF 2.1.1.e,支援以下之應用:

  • 播放音訊與影像。
  • 複製及合併音訊與影像。
  • 編碼、解碼與轉碼音訊與影像。
  • 擷取音訊與影像。
  • 支援RTP (Real-Time Transfer Protocol) 即時傳輸通訊協定。

JMF並支援以下的音訊與影像格式:

  • Adobe Shockwave Flash (*.swf)
  • Audio CD Track (*.cda)
  • Audio Interchange File Format (*.aif, *.aiff)
  • Microsoft Audio/Video Interleave (*.avi)
  • Microsoft Windows Waveform Audio (*.wav)
  • MPEG Layer-2 Audio (*.mp2)
  • MPEG Layer-3 Audio (*.mp3)
  • MPEG Video (*.mpeg、*.mpg)
  • Musical Instrument Digital Interface Audio (*.midi)
  • QuickTime (*.mov)
  • Sun Audio (*.au)
  • RMF (*.rmf)

但JMF 2.1.1.e自2003年5月發表以來則沒有任何更新,因此許多新的媒體格式均無法正常運作。此外,由於JMF屬於Java S.E.的選項套件,因此在使用之前必須安裝與設定。

JavaFX內建支援處理音訊與影像的API,分為Audio Clip與Media,前者僅處理播放簡短音訊;後者則類似於Java Media Framework,可播放音訊與影像。

JavaFX支援以下的音訊與影像編碼:

  • AAC:進階音訊編碼 (Advanced Audio Coding)。
  • MP3:MPEG-1、MPEG-2、MPEG-2.5與Layer-1、Layer-2與Layer-3音訊。
  • PCM:非壓縮音訊資料格式。
  • H.264/AVC:H.264、MPEG-4 Part 10、AVC (Advanced Video Coding) 影像。
  • VP6:TrueMotion VP6是由On2 Technologies所推出的影像壓縮編碼器,目前廣泛應用於Adobe Flash影像。

JavaFX支援以下的音訊與影像格式:

  • Audio Interchange File Format (*.aif, *.aiff)
  • Microsoft Windows Waveform Audio (*.wav)
  • MPEG Layer-3 Audio (*.mp3)
  • Flash Video (*.flv)
  • FX Media (*.fxm)
  • MP2T HTTP Live Streaming (*.m3u8)
  • MP3 HTTP Live Streaming (*.m3u8)
  • MPEG-4 Video (*.mp4, *.m4a, *.m4v)

分別由以下類別處理:

  • javafx.scene.media.AudioClip
  • javafx.scene.media.Media
  • javafx.scene.media.MediaPlayer
  • javafx.scene.media.MediaView

以下類別處理音訊等化器 (Audio Equalizer):

  • javafx.scene.media.AudioEqualizer
  • javafx.scene.media.EqualizerBand

以下類別處理媒體事件:

  • javafx.scene.media.MediaErrorEvent
  • javafx.scene.media.MediaMarkerEvent

在JavaFX中欲播放簡短音訊,可使用javafx.scene.media.AudioClip類別,類似於Java AWT的AudioClip介面。

AudioClip類別定義以下的屬性值:

  • balance:音量平衡,範圍由-1.0至1.0,-1.0代表完全左音量、0.0代表左右平衡、1.0代表完全右音量。
  • cycleCount:重覆播放次數,若為AudioClip.INDEFINITE,將一直重覆播放至執行stop()方法為止。
  • pan:音量平移,範圍由-1.0至1.0,-1.0代表完全左聲道、0.0代表正常聲道、1.0代表完全右聲道。
  • priority:音訊的優先順序。
  • rate:播放速率,範圍由0.125至8.0,0.125代表1/8倍播放速率、1.0代表正常播放速率、8.0代表8倍播放速率。
  • volume:音量大小,範圍由0.0至1.0,0.0代表靜音、1.0代表最大音量。

AudioClip類別的方法包括:

  • play():播放音訊。
  • isPlaying():判斷是否正在播放音訊中。
  • stop():停止播放音訊。
  • getBalance():取得音量平衡,範圍由-1.0至1.0,-1.0代表完全左音量、0.0代表左右平衡、1.0代表完全右音量。
  • setBalance():設定音量平衡。
  • getCycleCount():取得重覆播放次數。
  • setCycleCount():設定重覆播放次數,若設定為AudioClip.INDEFINITE,將一直重覆播放至執行stop()方法為止。
  • getPan():取得音量平移,範圍由-1.0至1.0,-1.0代表完全左聲道、0.0代表正常聲道、1.0代表完全右聲道。
  • setPan():設定音量平移。
  • getPriority():取得音訊的優先順序。
  • setPriority():設定音訊的優先順序。
  • getRate():取得播放速率,範圍由0.125至8.0,0.125代表1/8倍播放速率、1.0代表正常播放速率、8.0代表8倍播放速率。
  • setRate():設定播放速率。
  • getVolume():取得音量大小,範圍由0.0至1.0,0.0代表靜音、1.0代表最大音量。
  • setVolume():設定音量大小。

須注意的是上述設定方法,其設定值並不會影響正在播放中的音訊,只有在下一次執行play()方法播放音訊時才會生效。

請參考以下範例示範以滑動軸與核取方塊設定音量平衡、重覆播放次數、音量平移、播放速率與音量大小。當移動滑動軸時,則以滑動軸目前的值分別設定上述屬性。當點選核取方塊時,則設定重覆播放次數為AudioClip.INDEFINITE,代表無限次數:

CheckBox checkbox;
Slider slider1, slider2, slider3, slider4, slider5;
...

// 設定音量平衡
slider1 = new Slider();
...
slider1.valueProperty().addListener(new ChangeListener<Number>() {
  @Override public void changed(
    ObservableValue<? extends Number> observable,
    Number oldValue, Number newValue) {

    // 設定音量平衡
    audioclip.setBalance(slider1.getValue());
    lblValue1.setText(new DecimalFormat("0.0").format(
    slider1.getValue()));
  }
});

// 設定重覆播放次數
slider2 = new Slider();
...
slider2.valueProperty().addListener(new ChangeListener<Number>() {
  @Override public void changed(
  ObservableValue<? extends Number> observable,
  Number oldValue, Number newValue) {

    // 設定重覆播放次數
    audioclip.setCycleCount((int)slider2.getValue());
    lblValue2.setText(new DecimalFormat("0").format(
    slider2.getValue()));
  }
});

checkbox = new CheckBox("Indefinite");
checkbox.selectedProperty().addListener(new ChangeListener<Boolean>() {
  @Override public void changed(ObservableValue observable, 
  Boolean oldValue, Boolean newValue) {

    // 設定重覆播放次數
    audioclip.setCycleCount(
    newValue? AudioClip.INDEFINITE : (int)slider2.getValue());
    slider2.setDisable(newValue);
    lblValue2.setDisable(newValue);
  }
});

由以上範例可以瞭解,AudioClip類別的主要功能僅在於播放與停止播放音訊,並無法處理暫停播放、音訊時間長度、後設資料 (註)、等化器、事件等功能。

【執行結果】

AudioClip

請參考以下範例示範配合滑鼠與按鍵事件,當以滑鼠點選各個長條時,則以AudioClip類別的play()方法分別播放各音階,如同彈琴一般:

AudioClip DoAudioClip = new AudioClip(
  getClass().getResource("audio/Do.wav").toString());
AudioClip ReAudioClip = new AudioClip(
  getClass().getResource("audio/Re.wav").toString());
AudioClip MiAudioClip = new AudioClip(
  getClass().getResource("audio/Mi.wav").toString());
AudioClip FaAudioClip = new AudioClip(
  getClass().getResource("audio/Fa.wav").toString());
AudioClip SoAudioClip = new AudioClip(
  getClass().getResource("audio/So.wav").toString());
AudioClip LaAudioClip = new AudioClip(
  getClass().getResource("audio/La.wav").toString());
AudioClip SiAudioClip = new AudioClip(
  getClass().getResource("audio/Si.wav").toString());
AudioClip Do2AudioClip = new AudioClip(
  getClass().getResource("audio/Do2.wav").toString());

Group DoBar = createBar(Color.RED, Color.ORANGE, 
  27.0, 100.0, 20.0, 80.0);
Group ReBar = createBar(Color.ORANGE, Color.YELLOW, 
  49.0, 100.0, 20.0, 80.0);
Group MiBar = createBar(Color.YELLOW, Color.GREEN, 
  71.0, 100.0, 20.0, 80.0);
Group FaBar = createBar(Color.GREEN, Color.BLUE, 
  93.0, 100.0, 20.0, 80.0);
Group SoBar = createBar(Color.BLUE, Color.INDIGO, 
  115.0, 100.0, 20.0, 80.0);
Group LaBar = createBar(Color.INDIGO, Color.VIOLET, 
  137.0, 100.0, 20.0, 80.0);
Group SiBar = createBar(Color.VIOLET, Color.RED, 
  159.0, 100.0, 20.0, 80.0);
Group Do2Bar = createBar(Color.RED, Color.ORANGE, 
  181.0, 100.0, 20.0, 80.0);

DoBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    DoAudioClip.play(); 
  }
});
ReBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    ReAudioClip.play(); 
  }
});
MiBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    MiAudioClip.play(); 
  }
});
FaBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    FaAudioClip.play(); 
  }
});
SoBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    SoAudioClip.play(); 
  }
});
LaBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    LaAudioClip.play(); 
  }
});
SiBar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    SiAudioClip.play(); 
  }
});
Do2Bar.setOnMousePressed(new EventHandler() {
  @Override public void handle(MouseEvent e) { 
    Do2AudioClip.play(); 
  }
});

Group group = new Group();
group.getChildren().add(DoBar);
group.getChildren().add(ReBar);
group.getChildren().add(MiBar);
group.getChildren().add(FaBar);
group.getChildren().add(SoBar);
group.getChildren().add(LaBar);
group.getChildren().add(SiBar);
group.getChildren().add(Do2Bar);
group.setScaleX(1.5);
group.setScaleY(1.5);

若按下A至K的鍵盤按鍵,同樣以AudioClip類別的play()方法分別播放各音階:

// Key Pressed
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
  @Override public void handle(KeyEvent e) {
    if (e.getCode() == KeyCode.A)
      DoAudioClip.play();
    else if (e.getCode() == KeyCode.S)
      ReAudioClip.play();
    else if (e.getCode() == KeyCode.D)
      MiAudioClip.play();
    else if (e.getCode() == KeyCode.F)
      FaAudioClip.play();
    else if (e.getCode() == KeyCode.G)
      SoAudioClip.play();
    else if (e.getCode() == KeyCode.H)
      LaAudioClip.play();
    else if (e.getCode() == KeyCode.J)
      SiAudioClip.play();
    else if (e.getCode() == KeyCode.K)
      Do2AudioClip.play();
  }
});

【執行結果】

Piano

除了AudioClip類別之外,亦可使用AudioClipBuilder類別處理音訊,請參考以下範例示範以AudioClipBuilder類別處理音訊,首先以create()方法建立AudioClipBuilder的實體,最後再以build()方法以AudioClipBuilder物件建立AudioClip物件,其間並以上述方法設定音訊的相關屬性,各方法可為任意順序或省略:

AudioClip audioclip = null;

URL source = getClass().getResource("audio/Windows.wav");

audioclip = AudioClipBuilder.create()
  .source(source.toString())
  .balance(0.0)
  .cycleCount(1)
  .pan(0.0)
  .rate(1.0)
  .volume(1.0)
  .build();

(註):Metadata原意為Data about Data,中文直譯為有關資料的資料或描述資料的資料,國內學者對於Metadata有不同的譯名,常見的有元資料、詮釋資料、超資料等,中央研究院數位典藏與數位學習國家型科技計畫則譯為後設資料,特此說明。請參考中央研究院數位典藏與數位學習國家型科技計畫之說明。在多媒體中,Metadata是指內嵌於音訊與影像檔案中的標籤 (Tag) 資料。

【參考資料】

[1] Java Official Web Site
[2] JavaFX
[3] NetBeans
[4] JavaFX 2.2 API Specification.
[5] Java Platform, Standard Edition 7 API Specification.

後續 >> JavaFX多媒體(2)使用Media播放音訊與影像

分享:
按讚!加入 CodeData Facebook 粉絲群

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

關於作者

黃嘉輝副教授,目前任職於國立臺北商業大學企業管理學系,喜歡寫程式,特別愛Java,範例可參考教學網站

熱門論壇文章

熱門技術文章