/*
* 这个demon演示了在进行音频播放时如何使用Visualizer和Equalizer类为音频定制
* 示波器和均衡器。
*/
public class MainActivity extends Activity {
// 定义示波器界面的高度(单位为dip)
private static final float VISUALIZER_HEIGHT_DIP = 50f;
// 定义一个媒体播放器
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(1f);
mPaint.setColor(Color.rgb(0, 128, 255));
}
// 更新数据,为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 - 1) * 4) {
mPoints = new float[(mBytes.length - 1) * 4];
}
// 绘图区域的大小为整个示波器视图界面
mRect.set(0, 0, getWidth(), getHeight());
// 坐标系的刻度为x为采样数据的个数,y轴为每个字节数据的大小,以视图的左侧中心为圆点
for (int i = 0; i < mBytes.length - 1; i++) {
mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
// byte的聚会范围为-127到128,所以将y轴的刻度定义为半高/128
// (byte)(mBytes[i]+128)变换一下会使波形更平滑一些
mPoints[i * 4 + 1] = mRect.height() / 2
+ (byte) (mBytes[i] + 128) * (mRect.height() / 2) / 128;
/*
* System.out.println("未转换:"+mBytes[i]);
* System.out.println("转换后:"+(byte)(mBytes[i]+128));
*/
mPoints[i * 4 + 2] = mRect.width() * (i + 1)
/ (mBytes.length - 1);
mPoints[i * 4 + 3] = mRect.height() / 2
+ (byte) (mBytes[i + 1] + 128) * (mRect.height() / 2)
/ 128;
}
// 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(0, 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()[0];
short maxEqLevel = mEqualizer.getBandLevelRange()[1];
for (short i = 0; 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)/1000)+" 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 / 100) + " dB");
TextView maxDbTextView = new TextView(this);
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
maxDbTextView.setText((maxEqLevel / 100) + " dB");
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
//使SeekBar的宽度占据剩余的全部宽度
layoutParams.weight = 1;
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()[1]);
// 监听不断而来的所采集的数据。一共有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() / 2, true, false);
}
}
Android Api Demos登顶之路(九十五)Media-->AudioFx
最新推荐文章于 2023-07-12 21:42:16 发布