/*
* 這個demon示範了在進行音頻播放時如何使用Visualizer和Equalizer類為音頻定制
* 示波器和均衡器。
*/
public class MainActivity extends Activity {
// 定義示波器界面的高度(機關為dip)
private static final float VISUALIZER_HEIGHT_DIP = f;
// 定義一個媒體播放器
private MediaPlayer mMediaPlay;
// 定義示波器
private Visualizer mVisualizer;
// 定義均衡器
private Equalizer mEqualizer;
private LinearLayout mLinearLayout;
// 定義示波器的顯示界面(這是一個自定義的内部類)
private VisualizerView mVisualizerView;
private TextView mStatusTextView;
private class VisualizerView extends View {
// 定義一個位元組數組用于接收Visualizer在采樣時擷取到的位元組資料
private byte[] mBytes;
// 定義一個浮點數組,用于表示每段示波線段的兩個端點
private float[] mPoints;
// 定義示波器的顯示區域
private Rect mRect = new Rect();
private Paint mPaint;
public VisualizerView(Context context) {
super(context);
// 清空mBytes該變量由Visualizer在采樣後指派,是以要確定在未被指派前後狀态為空
mBytes = null;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(f);
mPaint.setColor(Color.rgb(, , ));
}
// 更新資料,為mBytes指派
public void updateVisualizer(byte[] bytes) {
mBytes = bytes;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBytes == null) {
return;
}
// 将采樣得到的資料個數作為x軸刻度的計算依據,每個位元組值的大小作為y軸刻度的計算依據建立坐标系
// 第i個點處的波動圖示由第i個點和第i+1個點的連線組成,是以每個示波線段由四個點組成,而到連到
// 最後一個點處結束,每段小波由兩個點組成,每個點由兩個值組成,是以必須確定mPoints的長度為(mBytes.length-1)
if (mPoints == null || mPoints.length < (mBytes.length - ) * ) {
mPoints = new float[(mBytes.length - ) * ];
}
// 繪圖區域的大小為整個示波器視圖界面
mRect.set(, , getWidth(), getHeight());
// 坐标系的刻度為x為采樣資料的個數,y軸為每個位元組資料的大小,以視圖的左側中心為圓點
for (int i = ; i < mBytes.length - ; i++) {
mPoints[i * ] = mRect.width() * i / (mBytes.length - );
// byte的聚會範圍為-127到128,是以将y軸的刻度定義為半高/128
// (byte)(mBytes[i]+128)變換一下會使波形更平滑一些
mPoints[i * + ] = mRect.height() /
+ (byte) (mBytes[i] + ) * (mRect.height() / ) / ;
/*
* System.out.println("未轉換:"+mBytes[i]);
* System.out.println("轉換後:"+(byte)(mBytes[i]+128));
*/
mPoints[i * + ] = mRect.width() * (i + )
/ (mBytes.length - );
mPoints[i * + ] = mRect.height() /
+ (byte) (mBytes[i + ] + ) * (mRect.height() / )
/ ;
}
// System.out.println(mPoints.length);
canvas.drawLines(mPoints, mPaint);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 設定該Activity中音量控制鍵控制的音頻流為音樂回放,即媒體音量
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mStatusTextView = new TextView(this);
mLinearLayout = new LinearLayout(this);
mLinearLayout.setOrientation(LinearLayout.VERTICAL);
mLinearLayout.addView(mStatusTextView);
setContentView(mLinearLayout);
// 建立媒體播放器,并指定播放的音頻
mMediaPlay = MediaPlayer.create(this, R.raw.test_cbr);
// 設定示波器的界面并傳遞資料
setupVisualizerFxAndUi();
// 設定均衡器的界面并傳遞資料
setupEqualizerFxAndUi();
// 隻有當示波器真正接收資料時才将其設定為可用
mVisualizer.setEnabled(true);
// 當媒體播放完畢,示波器設定為不可用狀态
mMediaPlay.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mVisualizer.setEnabled(false);
}
});
mMediaPlay.start();
mStatusTextView.setText("Playing audio...");
}
@Override
protected void onPause() {
super.onPause();
//如果該activity的程序結束且媒體播放器不為空
if(isFinishing() && mMediaPlay!=null){
mVisualizer.release();
mEqualizer.release();
mMediaPlay.release();
mMediaPlay=null;
}
}
private void setupEqualizerFxAndUi() {
// 擷取均衡器,第一個參數表示優先級,預設為0,當有多個應用控制EQ時就需要通過優先級來判定
// 第二個參數是音樂的sessionId.
mEqualizer = new Equalizer(, mMediaPlay.getAudioSessionId());
mEqualizer.setEnabled(true);
TextView eqTextView = new TextView(this);
eqTextView.setText("Equalizer:");
mLinearLayout.addView(eqTextView);
// 擷取目前Equalizer引擎所支援的控制頻率的标簽數目
short bands = mEqualizer.getNumberOfBands();
// 擷取最小的頻率
final short minEqLevel = mEqualizer.getBandLevelRange()[];
short maxEqLevel = mEqualizer.getBandLevelRange()[];
for (short i = ; i < bands; i++) {
final short band = i;
// 定義并設定頻率标簽的顯示文本
TextView freqTextView = new TextView(this);
freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
freqTextView.setText((mEqualizer.getCenterFreq(band)/)+" Hz");
mLinearLayout.addView(freqTextView);
LinearLayout row=new LinearLayout(this);
row.setOrientation(LinearLayout.HORIZONTAL);
TextView minDbTextView = new TextView(this);
minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
minDbTextView.setText((minEqLevel / ) + " dB");
TextView maxDbTextView = new TextView(this);
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
maxDbTextView.setText((maxEqLevel / ) + " dB");
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
//使SeekBar的寬度占據剩餘的全部寬度
layoutParams.weight = ;
SeekBar bar = new SeekBar(this);
bar.setLayoutParams(layoutParams);
bar.setMax(maxEqLevel - minEqLevel);
bar.setProgress(mEqualizer.getBandLevel(band));
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
//設定頻率的值了,需要提供标簽号,和設定的大小data
mEqualizer.setBandLevel(band, (short) (progress + minEqLevel));
}
public void onStartTrackingTouch(SeekBar seekBar) {}
public void onStopTrackingTouch(SeekBar seekBar) {}
});
row.addView(minDbTextView);
row.addView(bar);
row.addView(maxDbTextView);
mLinearLayout.addView(row);
}
}
private void setupVisualizerFxAndUi() {
// 将示波器界面添加到布局當中
mVisualizerView = new VisualizerView(this);
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
(int) (VISUALIZER_HEIGHT_DIP * getResources()
.getDisplayMetrics().density)));
mLinearLayout.addView(mVisualizerView);
// 擷取到示波器
mVisualizer = new Visualizer(mMediaPlay.getAudioSessionId());
// 設定采樣的大小,getCaptureSizeRange()所傳回的數組裡面就兩個值
// .數組[0]是最小值(128),數組[1]是最大值(1024)。
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[]);
// 監聽不斷而來的所采集的資料。一共有4個參數,第一個是監聽者,第二個機關是毫赫茲,表示的是采集的頻率,
// 第三個是是否采集波形,第四個是是否采集頻率
mVisualizer.setDataCaptureListener(new OnDataCaptureListener() {
// 回調應該采集的是波形資料
@Override
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] waveform, int samplingRate) {
mVisualizerView.updateVisualizer(waveform);
}
// 回調應該采集的是快速傅裡葉變換有關的資料
@Override
public void onFftDataCapture(Visualizer visualizer, byte[] fft,
int samplingRate) {
}
}, Visualizer.getMaxCaptureRate() / , true, false);
}
}