等化器由數個不同頻率的音訊頻譜 (Audio Spectrum) 所組成,可使用MediaPlayer類別以下的方法處理頻譜:
- getAudioSpectrumInterval():取得音訊頻譜的間隔,單位為秒。
- setAudioSpectrumInterval():設定音訊頻譜的間隔。
- getAudioSpectrumNumBands():取得音訊頻譜的頻帶 (Band) 數量。
- setAudioSpectrumNumBands():設定音訊頻譜的頻帶數量,其中參數value須大於或等於2。
- getAudioSpectrumThreshold():取得音訊頻譜的閾值 (Threshold),單位為分貝。
- setAudioSpectrumThreshold():設定音訊頻譜的閾值,其中參數value須小於或等於0。
- getAudioSpectrumListener():取得音訊頻譜的事件Listener。
- setAudioSpectrumListener():設定音訊頻譜的事件Listener。
public class Equalizer extends VBox { int maxValue; int barCount; double lastWidth = 0.0; double lastHeight = 0.0; public Equalizer(int maxValue, int barCount) { this.maxValue = maxValue; this.barCount = barCount; setSpacing(1.0); setAlignment(Pos.BOTTOM_CENTER); setStyle("-fx-background-color: black; -fx-padding: 5;"); Stop[] stop = new Stop[5]; stop[0] = new Stop(0.2, Color.RED); stop[1] = new Stop(0.4, Color.ORANGE); stop[2] = new Stop(0.6, Color.YELLOW); stop[3] = new Stop(0.8, Color.LIGHTGREEN); stop[4] = new Stop(0.9, Color.GREEN); for (int i = 0; i < barCount; i++) { int color = (int)((double)i / (double)barCount * 255.0); Rectangle rectangle = new Rectangle(); rectangle.setVisible(false); rectangle.setFill(Utils.ladder( Color.rgb(color, color, color), stop)); getChildren().add(rectangle); } } public void setValue(double value) { int barsLit = Math.min( barCount, (int)Math.round(value/maxValue*barCount)); ObservableList<Node> lists = getChildren(); for (int i = 0; i < lists.size(); i++) { lists.get(i).setVisible(i > barCount - barsLit); } } ... } |
接著由250 Hz開始分別建立七條等化器:
final Equalizer[] equalizer = new Equalizer[7]; Reflection reflection = new Reflection(); reflection.setFraction(1.0); for (int i = 0; i < equalizer.length; i++) { equalizer[i] = new Equalizer(100, 20); equalizer[i].setMaxWidth(50); equalizer[i].setMaxHeight(200); equalizer[i].setEffect(reflection); GridPane.setHalignment(equalizer[i], HPos.CENTER); gridpane.add(equalizer[i], i, 0); } gridpane.setTranslateX(120.0); // 取得音訊頻譜的閾值 final double minValue = mediaplayer.getAudioSpectrumThreshold(); final double[] norms = new double[equalizer.length]; double currentNorm = 0.05; for (int i = 0; i < norms.length; i++) { norms[i] = 1 + currentNorm; currentNorm *= 2; } // 取得音訊頻譜的頻帶數量 int bandCount = mediaplayer.getAudioSpectrumNumBands(); final int[] counts = new int[equalizer.length]; double startFreq = 250.0; double bandwidth = 22050.0 / bandCount; double currentSpectrumFreq = bandwidth / 2.0; double currentEQFreq = startFreq / 2.0; double currentCutoff = 0.0; int currentBucketIndex = -1; for (int i = 0; i < bandCount; i++) { if (currentSpectrumFreq > currentCutoff) { currentEQFreq *= 2; currentCutoff = currentEQFreq + currentEQFreq / 2; ++currentBucketIndex; if (currentBucketIndex == counts.length) { break; } } ++counts[currentBucketIndex]; currentSpectrumFreq += bandwidth; } |
此外,並以setAudioSpectrumListener()方法設定音訊頻譜的事件Listener,當音訊頻譜改變時,則更新頻譜比率長度:
// 設定音訊頻譜的事件Listener mediaplayer.setAudioSpectrumListener(new AudioSpectrumListener() { @Override public void spectrumDataUpdate(double timestamp, double duration, float[] magnitudes, float[] phases) { int index = 0; int bucketIndex = 0; int currentBucketCount = 0; double sum = 0.0; while (index < magnitudes.length) { sum += magnitudes[index] - minValue; ++currentBucketCount; if (currentBucketCount >= counts[bucketIndex]) { equalizer[bucketIndex].setValue(sum / norms[bucketIndex]); currentBucketCount = 0; sum = 0.0; ++bucketIndex; } ++index; } } }); |
【執行結果】
【參考資料】
[1] 黃嘉輝,深入研究JavaFX 2。
[2] 黃嘉輝,深入研究Java Swing。
[3] Java Official Web Site:http://www.oracle.com/technetwork/java/index.html
[4] JavaFX:http://www.oracle.com/technetwork/java/javafx
[5] JavaFX 2.2 API Specification.
[6] Java Platform, Standard Edition 7 API Specification.
© Chia-Hui Huang
沒有留言:
張貼留言