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,如需转载请自行联系原作者



相关文章
|
5月前
|
存储 缓存 Android开发
安卓Jetpack Compose+Kotlin, 使用ExoPlayer播放多个【远程url】音频,搭配Okhttp库进行下载和缓存,播放完随机播放下一首
这是一个Kotlin项目,使用Jetpack Compose和ExoPlayer框架开发Android应用,功能是播放远程URL音频列表。应用会检查本地缓存,如果文件存在且大小与远程文件一致则使用缓存,否则下载文件并播放。播放完成后或遇到异常,会随机播放下一首音频,并在播放前随机设置播放速度(0.9到1.2倍速)。代码包括ViewModel,负责音频管理和播放逻辑,以及UI层,包含播放和停止按钮。
|
6月前
|
Android开发
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
1160 0
|
5月前
|
存储 数据库 Android开发
安卓Jetpack Compose+Kotlin,支持从本地添加音频文件到播放列表,支持删除,使用ExoPlayer播放音乐
为了在UI界面添加用于添加和删除本地音乐文件的按钮,以及相关的播放功能,你需要实现以下几个步骤: 1. **集成用户选择本地音乐**:允许用户从设备中选择音乐文件。 2. **创建UI按钮**:在界面中创建添加和删除按钮。 3. **数据库功能**:使用Room数据库来存储音频文件信息。 4. **更新ViewModel**:处理添加、删除和播放音频文件的逻辑。 5. **UI实现**:在UI层支持添加、删除音乐以及播放功能。
|
5月前
|
XML Java API
20. 【Android教程】拖动条 SeekBar
20. 【Android教程】拖动条 SeekBar
82 3
|
6月前
|
XML 开发工具 Android开发
|
5月前
|
Android开发
Android中如何快速的实现RecycleView的拖动重排序功能
使用`ItemTouchHelper`和自定义`Callback`,在`RecyclerView`中实现拖动排序功能。定义`ItemTouchHelperAdapter`接口,`Adapter`实现它以处理`onItemMove`方法。`SimpleItemTouchHelperCallback`设置拖动标志,如`LEFT`或`RIGHT`(水平拖动),并绑定到`RecyclerView`以启用拖动。完成这些步骤后,即可实现拖放排序。关注公众号“AntDream”获取更多内容。
109 3
|
5月前
|
缓存 Android开发 Kotlin
【安卓app开发】kotlin Jetpack Compose框架 | 先用OKhttp下载远程音频文件再使用ExoPlayer播放
使用 Kotlin 的 Jetpack Compose 开发安卓应用时,可以结合 OkHttp 下载远程音频文件和 ExoPlayer 进行播放。在 `build.gradle` 添加相关依赖后,示例代码展示了如何下载音频并用 ExoPlayer 播放。代码包括添加依赖、下载文件、播放文件及简单的 Compose UI。注意,示例未包含完整错误处理和资源释放,实际应用需补充这些内容。
|
5月前
|
存储 Android开发 Kotlin
开发安卓app OKhttp下载后使用MediaPlayer播放
在Android Jetpack Compose应用程序中,要使用OkHttp下载远程音频文件并在本地播放,你需要完成以下几个步骤: 1. **添加依赖**:确保`build.gradle`文件包含OkHttp和Jetpack Compose的相关依赖。 2. **下载逻辑**:创建一个`suspend`函数,使用OkHttp发起网络请求下载音频文件到本地。 3. **播放逻辑**:利用`MediaPlayer`管理音频播放状态。 4. **Compose UI**:构建用户界面,包含下载和播放音频的按钮。
|
5月前
|
存储 Android开发
安卓app,MediaPlayer播放本地音频 | 按钮控制播放和停止
在Jetpack Compose中,不直接操作原生Android组件如`Button`和`MediaPlayer`,而是使用Compose UI构建器定义界面并结合ViewModel管理音频播放逻辑。以下示例展示如何播放本地音频并用按钮控制播放/停止:创建一个`AudioPlayerViewModel`管理`MediaPlayer`实例和播放状态,然后在Compose UI中使用`Button`根据`isPlaying`状态控制播放。记得在`MainActivity`设置Compose UI,并处理相关依赖和权限。
|
5月前
|
XML 前端开发 API
Android中实现Bitmap在自定义View中的放大与拖动
Android中实现Bitmap在自定义View中的放大与拖动
149 1
下一篇
无影云桌面