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

简介:

  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 ( 0 0 , 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() 
/   2 true false );

    }

 

 

 

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

 

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文件即可。


 本文转自 terry_龙 51CTO博客,原文链接:http://blog.51cto.com/terryblog/475113,如需转载请自行联系原作者



相关文章
|
IDE API 开发工具
 鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Span组件
 鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Span组件
295 3
 鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Span组件
Layui 内置方法 - layer.close(关闭特定层)
Layui 内置方法 - layer.close(关闭特定层)
682 0
|
9月前
鸿蒙开发:一个轻盈的上拉下拉刷新组件
在和可滑动组件使用的时候,记得一定要和nestedScroll属性配合使用,用于解决滑动冲突,除此之外,还需要传递滑动组件的scroller属性,用于手势操作。
181 2
鸿蒙开发:一个轻盈的上拉下拉刷新组件
|
11月前
|
JavaScript 数据管理 编译器
揭秘 ArkTS 与 TypeScript 的神秘差异:鸿蒙系统开发者的必备知识与实战技巧
【10月更文挑战第18天】ArkTS 是华为为鸿蒙系统(HarmonyOS)推出的开发语言,作为 TypeScript 的超集,它针对鸿蒙系统的分布式特性和需求进行了优化和扩展。ArkTS 强化了分布式数据管理、类型系统、编译与运行时性能,并支持声明式 UI 和专为鸿蒙设计的 API,使开发者能够更高效地开发跨设备协同工作的应用。
821 6
|
11月前
|
缓存 前端开发 NoSQL
如何设计一个秒杀系统?
本文详细介绍了秒杀系统的原理与设计方法,包括高性能、一致性、高可用性和可扩展性等方面的要求。文中通过前端和后端的设计方案,探讨了如何实现秒杀系统的高并发处理,例如页面静态化、限流、降级策略及缓存优化等。此外,还分享了实际项目中的库存系统架构设计经验,并提供了面试中如何回答此类问题的建议。
1391 3
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
《FFmpeg开发实战》一书中,第10章示例程序playaudio.c原本仅支持mp3和aac音频播放。为支持ogg、amr、wma等非固定帧率音频,需进行三处修改:1)当frame_size为0时,将输出采样数量设为512;2)遍历音频帧时,计算实际采样位数以确定播放数据大小;3)在SDL音频回调函数中,确保每次发送len字节数据。改进后的代码在chapter10/playaudio2.c,可编译运行播放ring.ogg测试,成功则显示日志并播放铃声。
261 1
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
|
Android开发
DialogFragment 使用指南:几个小问题的解法
DialogFragment是Android中用于创建弹窗的特殊Fragment,继承自Fragment。使用步骤包括:1. 创建子类,2. 在onCreateView加载布局,3. onViewCreated初始化控件,4. 通过show方法显示。示例代码展示了一个基本的DialogFragment及其布局。此外,文中还解答了三个常见问题:如何设置弹窗宽度为match_parent,如何使弹窗位于屏幕底部,以及如何去除弹窗四周的默认padding。每个问题都提供了相应的解决方案,涉及在onStart中调整窗口参数和设置自定义样式。
1450 2
DialogFragment 使用指南:几个小问题的解法
|
Python
基本技术指标 Python 实现(2)
基本技术指标 Python 实现
285 1
|
Web App开发 移动开发 前端开发
多种方法实现Loading(加载)动画效果
当我们ajax提交一个按钮的时候,给那个按钮来个Loading效果会高端很多,体验也会上升个层次。 既能让用户知道正在提交中,也能防止二次提交,好处多多呢。
多种方法实现Loading(加载)动画效果
|
Java Maven 开发工具
如何发布Android Library到maven私有仓库
在我们的项目架构中,一定存在一些基础的模块,这些模块可以在多个app上通用,这种情况我们一般会将这些模块封装成Android Library统一维护,并上传到仓库方便其他小组使用。仓库可以选择如mavenCentral这类公开的仓库,但是我们一般选择搭建自己的maven私有仓库,比如:Sonatype Nexus。本文就一步步的教大家如何将Android Library发布到maven私有仓库。
627 0

热门文章

最新文章