
JavaFX多媒體(1)使用Audio Clip播放音訊
在Java Swing中欲處理音訊與影像,需額外安裝Java Media Framework (JMF),JMF為Java S.E.的選項套件,目前版本為JMF 2.1.1.e,支援以下之應用:
JMF並支援以下的音訊與影像格式:
但JMF 2.1.1.e自2003年5月發表以來則沒有任何更新,因此許多新的媒體格式均無法正常運作。此外,由於JMF屬於Java S.E.的選項套件,因此在使用之前必須安裝與設定。 JavaFX內建支援處理音訊與影像的API,分為Audio Clip與Media,前者僅處理播放簡短音訊;後者則類似於Java Media Framework,可播放音訊與影像。 JavaFX支援以下的音訊與影像編碼:
JavaFX支援以下的音訊與影像格式:
分別由以下類別處理:
以下類別處理音訊等化器 (Audio Equalizer):
以下類別處理媒體事件:
在JavaFX中欲播放簡短音訊,可使用javafx.scene.media.AudioClip類別,類似於Java AWT的AudioClip介面。 AudioClip類別定義以下的屬性值:
AudioClip類別的方法包括:
須注意的是上述設定方法,其設定值並不會影響正在播放中的音訊,只有在下一次執行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類別的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(); } }); 【執行結果】 除了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 |