Android Api Demos登顶之路(九十五)Media-->AudioFx

/*
 * 这个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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值