失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 我的Android进阶之旅------gt;Android实现音乐示波器 均衡器 重低音和音场功能...

我的Android进阶之旅------gt;Android实现音乐示波器 均衡器 重低音和音场功能...

时间:2023-11-08 01:21:16

相关推荐

我的Android进阶之旅------gt;Android实现音乐示波器 均衡器 重低音和音场功能...

本实例来自于《疯狂Android讲义》。要实现详细的功能,须要了解下面API: MediaPlayer 媒体播放器Visualizer 频谱Equalizer 均衡器BassBoost 重低音控制器PresetReverb 预设音场控制器Paint 画图

来看下效果示意图,例如以下所看到的

竖状波形图

块状波形图

曲线波形图

调节均衡器、重低音

选择音场

以下来看详细的实现代码MediaPlayerTest.java

package com.oyp.media;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Style;import android.graphics.Rect;import android.media.AudioManager;import android.media.MediaPlayer;import android.media.audiofx.BassBoost;import android.media.audiofx.Equalizer;import android.media.audiofx.PresetReverb;import android.media.audiofx.Visualizer;import android.os.Bundle;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.LinearLayout;import android.widget.SeekBar;import android.widget.Spinner;import android.widget.TextView;public class MediaPlayerTest extends Activity{// 定义播放声音的MediaPlayerprivate MediaPlayer mPlayer;// 定义系统的频谱private Visualizer mVisualizer;// 定义系统的均衡器private Equalizer mEqualizer;// 定义系统的重低音控制器private BassBoost mBass;// 定义系统的预设音场控制器private PresetReverb mPresetReverb;private LinearLayout layout;private List<Short> reverbNames = new ArrayList<Short>();private List<String> reverbVals = new ArrayList<String>();@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);//设置音频流 - STREAM_MUSIC:音乐回放即媒体音量setVolumeControlStream(AudioManager.STREAM_MUSIC);layout = new LinearLayout(this);//代码创建布局layout.setOrientation(LinearLayout.VERTICAL);//设置为线性布局-上下排列setContentView(layout);//将布局加入到 Activity// 创建MediaPlayer对象,并加入音频// 音频路径为 res/raw/beautiful.mp3mPlayer = MediaPlayer.create(this, R.raw.beautiful);// 初始化示波器setupVisualizer();// 初始化均衡控制器setupEqualizer();// 初始化重低音控制器setupBassBoost();// 初始化预设音场控制器setupPresetReverb();// 开发播放音乐mPlayer.start();}/*** 初始化频谱*/private void setupVisualizer(){// 创建MyVisualizerView组件,用于显示波形图final MyVisualizerView mVisualizerView =new MyVisualizerView(this);mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,(int) (120f * getResources().getDisplayMetrics().density)));// 将MyVisualizerView组件加入到layout容器中layout.addView(mVisualizerView);// 以MediaPlayer的AudioSessionId创建Visualizer// 相当于设置Visualizer负责显示该MediaPlayer的音频数据mVisualizer = new Visualizer(mPlayer.getAudioSessionId());//设置须要转换的音乐内容长度,专业的说这就是採样,该採样值一般为2的指数倍,如64,128,256,512,1024。mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);// 为mVisualizer设置监听器/** Visualizer.setDataCaptureListener(OnDataCaptureListener listener, int rate, boolean waveform, boolean fft* * listener,表监听函数。匿名内部类实现该接口,该接口须要实现两个函数rate, 表示採样的周期,即隔多久採样一次,联系前文就是隔多久採样128个数据iswave,是波形信号isfft。是FFT信号,表示是获取波形信号还是频域信号*/mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener(){//这个回调应该採集的是高速傅里叶变换有关的数据@Overridepublic void onFftDataCapture(Visualizer visualizer,byte[] fft, int samplingRate){}//这个回调应该採集的是波形数据@Overridepublic void onWaveFormDataCapture(Visualizer visualizer,byte[] waveform, int samplingRate){// 用waveform波形数据更新mVisualizerView组件mVisualizerView.updateVisualizer(waveform);}}, Visualizer.getMaxCaptureRate() / 2, true, false);mVisualizer.setEnabled(true);}/*** 初始化均衡控制器*/private void setupEqualizer(){// 以MediaPlayer的AudioSessionId创建Equalizer// 相当于设置Equalizer负责控制该MediaPlayermEqualizer = new Equalizer(0, mPlayer.getAudioSessionId());// 启用均衡控制效果mEqualizer.setEnabled(true);TextView eqTitle = new TextView(this);eqTitle.setText("均衡器:");layout.addView(eqTitle);// 获取均衡控制器支持最小值和最大值final short minEQLevel = mEqualizer.getBandLevelRange()[0];//第一个下标为最低的限度范围short maxEQLevel = mEqualizer.getBandLevelRange()[1]; // 第二个下标为最高的限度范围// 获取均衡控制器支持的全部频率short brands = mEqualizer.getNumberOfBands();for (short i = 0; i < brands; i++){TextView eqTextView = new TextView(this);// 创建一个TextView。用于显示频率eqTextView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT));eqTextView.setGravity(Gravity.CENTER_HORIZONTAL);// 设置该均衡控制器的频率eqTextView.setText((mEqualizer.getCenterFreq(i) / 1000)+ " Hz");layout.addView(eqTextView);// 创建一个水平排列组件的LinearLayoutLinearLayout tmpLayout = new LinearLayout(this);tmpLayout.setOrientation(LinearLayout.HORIZONTAL);// 创建显示均衡控制器最小值的TextViewTextView minDbTextView = new TextView(this);minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));// 显示均衡控制器的最小值minDbTextView.setText((minEQLevel / 100) + " dB");// 创建显示均衡控制器最大值的TextViewTextView 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);layoutParams.weight = 1;// 定义SeekBar做为调整工具SeekBar bar = new SeekBar(this);bar.setLayoutParams(layoutParams);bar.setMax(maxEQLevel - minEQLevel);bar.setProgress(mEqualizer.getBandLevel(i));final short brand = i;// 为SeekBar的拖动事件设置事件监听器bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){@Overridepublic void onProgressChanged(SeekBar seekBar,int progress, boolean fromUser){// 设置该频率的均衡值mEqualizer.setBandLevel(brand,(short) (progress + minEQLevel));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar){}@Overridepublic void onStopTrackingTouch(SeekBar seekBar){}});// 使用水平排列组件的LinearLayout“盛装”3个组件tmpLayout.addView(minDbTextView);tmpLayout.addView(bar);tmpLayout.addView(maxDbTextView);// 将水平排列组件的LinearLayout加入到myLayout容器中layout.addView(tmpLayout);}}/*** 初始化重低音控制器*/private void setupBassBoost(){// 以MediaPlayer的AudioSessionId创建BassBoost// 相当于设置BassBoost负责控制该MediaPlayermBass = new BassBoost(0, mPlayer.getAudioSessionId());// 设置启用重低音效果mBass.setEnabled(true);TextView bbTitle = new TextView(this);bbTitle.setText("重低音:");layout.addView(bbTitle);// 使用SeekBar做为重低音的调整工具 SeekBar bar = new SeekBar(this);// 重低音的范围为0~1000bar.setMax(1000);bar.setProgress(0);// 为SeekBar的拖动事件设置事件监听器bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser){// 设置重低音的强度mBass.setStrength((short) progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar){}@Overridepublic void onStopTrackingTouch(SeekBar seekBar){}});layout.addView(bar);}/*** 初始化预设音场控制器*/private void setupPresetReverb(){// 以MediaPlayer的AudioSessionId创建PresetReverb// 相当于设置PresetReverb负责控制该MediaPlayermPresetReverb = new PresetReverb(0,mPlayer.getAudioSessionId());// 设置启用预设音场控制mPresetReverb.setEnabled(true);TextView prTitle = new TextView(this);prTitle.setText("音场");layout.addView(prTitle);// 获取系统支持的全部预设音场for (short i = 0; i < mEqualizer.getNumberOfPresets(); i++){reverbNames.add(i);reverbVals.add(mEqualizer.getPresetName(i));}// 使用Spinner做为音场选择工具Spinner sp = new Spinner(this);sp.setAdapter(new ArrayAdapter<String>(MediaPlayerTest.this,android.R.layout.simple_spinner_item, reverbVals));// 为Spinner的列表项选中事件设置监听器sp.setOnItemSelectedListener(new Spinner.OnItemSelectedListener(){@Overridepublic void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3){// 设定音场mPresetReverb.setPreset(reverbNames.get(arg2));}@Overridepublic void onNothingSelected(AdapterView<?> arg0){}});layout.addView(sp);}@Overrideprotected void onPause(){super.onPause();if (isFinishing() && mPlayer != null){// 释放全部对象mVisualizer.release();mEqualizer.release();mPresetReverb.release();mBass.release();mPlayer.release();mPlayer = null;}}/*** 依据Visualizer传来的数据动态绘制波形效果,分别为:* 块状波形、柱状波形、曲线波形*/private static class MyVisualizerView extends View{// bytes数组保存了波形抽样点的值private byte[] bytes;private float[] points;private Paint paint = new Paint();private Rect rect = new Rect();private byte type = 0;public MyVisualizerView(Context context){super(context);bytes = null;// 设置画笔的属性paint.setStrokeWidth(1f);paint.setAntiAlias(true);//抗锯齿paint.setColor(Color.YELLOW);//画笔颜色paint.setStyle(Style.FILL);}public void updateVisualizer(byte[] ftt){bytes = ftt;// 通知该组件重绘自己。invalidate();}@Overridepublic boolean onTouchEvent(MotionEvent me){// 当用户触碰该组件时,切换波形类型if(me.getAction() != MotionEvent.ACTION_DOWN){return false;}type ++;if(type >= 3){type = 0;}return true;}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);if (bytes == null){return;}// 绘制白色背景canvas.drawColor(Color.WHITE);// 使用rect对象记录该组件的宽度和高度rect.set(0,0,getWidth(),getHeight());switch(type){// -------绘制块状的波形图-------case 0:for (int i = 0; i < bytes.length - 1; i++){float left = getWidth() * i / (bytes.length - 1);// 依据波形值计算该矩形的高度float top = rect.height()-(byte)(bytes[i+1]+128)* rect.height() / 128;float right = left + 1;float bottom = rect.height();canvas.drawRect(left, top, right, bottom, paint);}break;// -------绘制柱状的波形图(每隔18个抽样点绘制一个矩形)-------case 1:for (int i = 0; i < bytes.length - 1; i += 18){float left = rect.width()*i/(bytes.length - 1);// 依据波形值计算该矩形的高度float top = rect.height()-(byte)(bytes[i+1]+128)* rect.height() / 128;float right = left + 6;float bottom = rect.height();canvas.drawRect(left, top, right, bottom, paint);}break;// -------绘制曲线波形图-------case 2:// 假设point数组还未初始化if (points == null || points.length < bytes.length * 4){points = new float[bytes.length * 4];}for (int i = 0; i < bytes.length - 1; i++){// 计算第i个点的x坐标points[i * 4] = rect.width()*i/(bytes.length - 1);// 依据bytes[i]的值(波形点的值)计算第i个点的y坐标points[i * 4 + 1] = (rect.height() / 2)+ ((byte) (bytes[i] + 128)) * 128/ (rect.height() / 2);// 计算第i+1个点的x坐标points[i * 4 + 2] = rect.width() * (i + 1)/ (bytes.length - 1);// 依据bytes[i+1]的值(波形点的值)计算第i+1个点的y坐标points[i * 4 + 3] = (rect.height() / 2)+ ((byte) (bytes[i + 1] + 128)) * 128/ (rect.height() / 2);}// 绘制波形曲线canvas.drawLines(points, paint);break;}}}}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifestxmlns:android="/apk/res/android"package="com.oyp.media"android:versionCode="1"android:versionName="1.0"><uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17"/><!-- 使用音场效果必要的权限 --><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/><applicationandroid:icon="@drawable/ic_launcher"android:label="@string/app_name"><activityandroid:name=".MediaPlayerTest"android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

PS:请在真机环境下执行此程序,假设在模拟器下执行。可能会报错:

java.lang.RuntimeException: Cannot initialize Visualizer engine, error: -4

====================================================================================

作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!

转载请保留原文地址:/ouyang_peng

====================================================================================

如果觉得《我的Android进阶之旅------gt;Android实现音乐示波器 均衡器 重低音和音场功能...》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。