代码改变世界

Android 音频均衡器,可通过拖动调节音频EQ

2011-01-09 12:03  Terry_龙  阅读(7983)  评论(8编辑  收藏  举报

  2.3之后,Google 为Mediaplayer 类添加了EQ支持,如果你需要使用这个EQ功能,有两点需要注意,分别为如下:

  • 在配置文件中设置最小的SDK版本为9
  • 添加权限android.permission.RECORD_AUDIO 即可使用,具体的使用方法,下文会介绍

为了使应用程序能够支持波段变化,我们需要重新定义一个VIEW对象,在onDraw 方法画频谱,代码如下:

 

class VisualizerView extends View {

        
private byte[] mBytes;
        
private float[] mPoints;
        
// 矩形区域
        private Rect mRect = new Rect();
        
// 画笔
        private Paint mPaint = new Paint();

        
// 初始化画笔
        private void init() {
            mBytes 
= null;
            mPaint.setStrokeWidth(1f);
            mPaint.setAntiAlias(
true);
            mPaint.setColor(Color.BLUE);
        }

        
public VisualizerView(Context context) {
            super(context);
            init();
        }

        
public void updateVisualizer(byte[] mbyte) {
            mBytes 
= mbyte;
            invalidate();
        }

        @Override
        
protected void onDraw(Canvas canvas) {
            
// TODO Auto-generated method stub
            super.onDraw(canvas);

            
if (mBytes == null) {
                
return;
            }
            
if (mPoints == null || mPoints.length < mBytes.length * 4) {
                mPoints 
= new float[mBytes.length * 4];
            }

            mRect.
set(00, getWidth(), getHeight());

            
for (int i = 0; i < mBytes.length - 1; i++) {
                mPoints[i 
* 4= mRect.width() * i / (mBytes.length - 1);
                mPoints[i 
* 4 + 1= mRect.height() / 2
                        
+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2)
                        
/ 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;
            }

            canvas.drawLines(mPoints, mPaint);
        }
    }

 

 

另外,为了使用EQ和频谱可视化,我们必须了解以下两个类:

  • Visualizer
    此类能使应用程序获取当前有效的一部分音频可视化的目的。使用此类必须添加上面提到的权限。
  • Equalizer
    一个均衡器的类,使用此类可以轻松的操纵音频的频段,和输出的混合 。

具体使用代码和注释见下面:

 

/**
     * 通过mMediaPlayer返回的AudioSessionId创建一个优先级为0均衡器对象 并且通过频谱生成相应的UI和对应的事件
     
*/
    
private void setupEqualizeFxAndUi() {
        mEqualizer 
= new Equalizer(0, mMediaPlayer.getAudioSessionId());
        mEqualizer.setEnabled(
true);// 启用均衡器
        TextView eqTextView = new TextView(this);
        eqTextView.setText(
"均衡器:");
        mLayout.addView(eqTextView);

        
// 通过均衡器得到其支持的频谱引擎
        short bands = mEqualizer.getNumberOfBands();

        
// getBandLevelRange 是一个数组,返回一组频谱等级数组,
        
// 第一个下标为最低的限度范围
        
// 第二个下标为最大的上限,依次取出
        final short minEqualizer = mEqualizer.getBandLevelRange()[0];
        final 
short maxEqualizer = 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.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));

            freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);

            
// 取出中心频率
            freqTextView
                    .setText((mEqualizer.getCenterFreq(band) 
/ 1000+ "HZ");
            mLayout.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((minEqualizer 
/ 100+ " dB");

            TextView maxDbTextView 
= new TextView(this);
            maxDbTextView.setLayoutParams(
new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            maxDbTextView.setText((maxEqualizer 
/ 100+ " dB");

            LinearLayout.LayoutParams layoutParams 
= new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);

            layoutParams.weight 
= 1;

            SeekBar seekbar 
= new SeekBar(this);
            seekbar.setLayoutParams(layoutParams);
            seekbar.setMax(maxEqualizer 
- minEqualizer);
            seekbar.setProgress(mEqualizer.getBandLevel(band));

            seekbar.setOnSeekBarChangeListener(
new OnSeekBarChangeListener() {

                @Override
                
public void onStopTrackingTouch(SeekBar seekBar) {
                }

                @Override
                
public void onStartTrackingTouch(SeekBar seekBar) {
                }

                @Override
                
public void onProgressChanged(SeekBar seekBar, int progress,
                        boolean fromUser) {
                    
// TODO Auto-generated method stub
                    mEqualizer.setBandLevel(band,
                            (
short) (progress + minEqualizer));
                }
            });
            row.addView(minDbTextView);
            row.addView(seekbar);
            row.addView(maxDbTextView);

            mLayout.addView(row);
        }

    }
 

 

 

 

 

/**
     * 生成一个VisualizerView对象,使音频频谱的波段能够反映到 VisualizerView上
     
*/
    
private void setupVisualizerFxAndUi() {
        mVisualizerView 
= new VisualizerView(this);
        mVisualizerView.setLayoutParams(
new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.FILL_PARENT,
                (
int) (VISUALIZER_HEIGHT_DIP * getResources()
                        .getDisplayMetrics().density)));
        mLayout.addView(mVisualizerView);

        mVisualizer 
= new Visualizer(mMediaPlayer.getAudioSessionId());
        
// 参数内必须是2的位数
        mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);

        
// 设置允许波形表示,并且捕获它
        mVisualizer.setDataCaptureListener(new OnDataCaptureListener() {

            @Override
            
public void onWaveFormDataCapture(Visualizer visualizer,
                    
byte[] waveform, int samplingRate) {
                
// TODO Auto-generated method stub
                mVisualizerView.updateVisualizer(waveform);
            }

            @Override
            
public void onFftDataCapture(Visualizer visualizer, byte[] fft,
                    
int samplingRate) {
                
// TODO Auto-generated method stub

            }
        }, Visualizer.getMaxCaptureRate() 
/ 2truefalse);

    }

 

 

 

进入程序后,在程序入口加载如下代码:

 

mStatusTextView = new TextView(this);
        mLayout 
= new LinearLayout(this);
        mLayout.setOrientation(LinearLayout.VERTICAL);
        mLayout.addView(mStatusTextView);
        setContentView(mLayout);

        mMediaPlayer 
= MediaPlayer.create(this, R.raw.eason);

        setupVisualizerFxAndUi();
        setupEqualizeFxAndUi();

        mVisualizer.setEnabled(
true);
        mMediaPlayer.setOnCompletionListener(
new OnCompletionListener() {

            @Override
            
public void onCompletion(MediaPlayer mp) {
                
// TODO Auto-generated method stub
                mVisualizer.setEnabled(false);
            }
        });

        mMediaPlayer.start();
        mStatusTextView.setText(
"播放中。。。");

 

 

 

完整运行效果:

 

试试改变一下拖动条,听一下音频有什么变化。

源码下载:

音频频谱操作

 

注:源码内没有包含音频文件,测试的话自行添加一个MP3文件即可。