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
原创粉丝点击