JavaFX多媒體(4)Equalizer 與 Audio Spectrum
|
JavaFX多媒體(3)Metadata與Marker << 前情 等化器 (Equalizer) 原應用於通訊傳輸,由於信號經傳送路徑到接收器的過程中,常會受到干擾與遮蔽物阻擋而造成遮蔽效應,此效應將造成訊號錯誤,為了降低傳送通訊的錯誤率,因而對通訊兩端做估測,經由估測結果對通訊兩端做頻率補償以降低傳送錯誤率。現已運用於聲音處理,將聲音優化,以調整聲音適合某類曲風,例如搖滾樂、流行樂等。 等化器由數個不同頻率的音訊頻譜 (Audio Spectrum) 所組成,可使用MediaPlayer類別以下的方法處理頻譜:
請參考以下範例,示範如何處理頻譜與等化器,範例首先以自訂之Equalizer類別建立等化器,其中各頻譜以不同的顏色處理,範例以javafx.scene.paint.Stop類別設定各頻譜比率的顏色: 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 lists = getChildren();
for (int i = 0; i < lists.size(); i++) {
lists.get(i).setVisible(i > barCount - barsLit);
}
}
...
}
接著由250 Hz開始分別建立七條等化器: GridPane gridpane = new GridPane();
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] Java Official Web Site |

Java 學習之路

