Android Api Demos登顶之路(九十五)Media-->AudioFx
来源:互联网 发布:linux killproc 编辑:程序博客网 时间:2024/06/05 02:55
/* * 这个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); }}
0 0
- Android Api Demos登顶之路(九十五)Media-->AudioFx
- Android Api Demos登顶之路(十三)Presentation With Media Router
- Android Api Demos登顶之路(二)
- Android Api Demos登顶之路(三)
- Android Api Demos登顶之路(四)
- Android Api Demos登顶之路(五)
- Android Api Demos登顶之路(六)
- Android Api Demos登顶之路(七)
- Android Api Demos登顶之路(八)
- Android Api Demos登顶之路(九)
- Android Api Demos登顶之路(十)Overscan
- Android Api Demos登顶之路(十一)Persistent state
- Android Api Demos登顶之路(十二)Presentation
- Android Api Demos登顶之路(十四)Quick Contacts
- Android Api Demos登顶之路(十五)Receive Result
- Android Api Demos登顶之路(十六)Recreate
- Android Api Demos登顶之路(十七)Redirection
- Android Api Demos登顶之路(十八)Recorder Activities
- 产品学习:基于云计算的智能城市
- 支持向量机SVM(一)
- Android :Android Studio中如何找到自己的API
- 百度编辑器上传大容量视频报HTTP错误
- [[UIBarButtonItem alloc] initWithTitle与[[UIBarButtonItem alloc] initWithBarButtonSystemItem的区别
- Android Api Demos登顶之路(九十五)Media-->AudioFx
- IO 复用
- 编码解码模型实现中的其他一些考虑
- C++基础---typedef struct与struct的区别
- 布局自动化处理方法
- 温故知新: JavaScript
- View相关知识学习(一)
- 设计模式--工厂方法模式
- RecyclerView的通用适配器,和滚动时不加载图片的封装