Android編程之播放器MediaPlayer實(shí)現(xiàn)均衡器效果示例
本文實(shí)例講述了Android播放器MediaPlayer實(shí)現(xiàn)均衡器效果。分享給大家供大家參考,具體如下:
這幾天在系統(tǒng)學(xué)習(xí)Android官方API Demos,看到實(shí)現(xiàn)均衡器效果,就把官方API中代碼copy下來(lái),根據(jù)網(wǎng)上前輩的指引略有修改,添加了注釋。
public class AudioFxDemo extends Activity {
private static final String TAG = "AudioFxDemo";
private static final float VISUALIZER_HEIGHT_DIP = 50f;
// 定義播放器
private MediaPlayer mMediaPlayer;
// 定義系統(tǒng)的頻譜
private Visualizer mVisualizer;
// 定義系統(tǒng)的均衡器
private Equalizer mEqualizer;
private LinearLayout mLinearLayout;
private VisualizerView mVisualizerView;
private TextView mStatusTextView;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// 音量控制
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mStatusTextView = new TextView(this);
mLinearLayout = new LinearLayout(this);
mLinearLayout.setOrientation(LinearLayout.VERTICAL);
mLinearLayout.addView(mStatusTextView);
setContentView(mLinearLayout);
// 創(chuàng)建MediaPlayer對(duì)象
mMediaPlayer = MediaPlayer.create(this, R.raw.test_cbr);
Log.d(TAG,
"MediaPlayer audio session ID: "
+ mMediaPlayer.getAudioSessionId());
// 設(shè)置頻譜顯示
setupVisualizerFxAndUI();
// 設(shè)置示波器顯示
setupEqualizerFxAndUI();
// Make sure the visualizer is enabled only when you actually want to
// receive data, and
// when it makes sense to receive data.
mVisualizer.setEnabled(true);
// When the stream ends, we don't need to collect any more data. We
// don't do this in
// setupVisualizerFxAndUI because we likely want to have more,
// non-Visualizer related code
// in this callback.
mMediaPlayer
.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mediaPlayer) {
mVisualizer.setEnabled(false);
mStatusTextView.setText("播放結(jié)束");
}
});
mMediaPlayer.start();
mStatusTextView.setText("正在播放中");
}
private void setupEqualizerFxAndUI() {
// Create the Equalizer object (an AudioEffect subclass) and attach it
// to our media player,
// with a default priority (0).
mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
mEqualizer.setEnabled(true);
TextView eqTextView = new TextView(this);
eqTextView.setText("Equalizer:");
mLinearLayout.addView(eqTextView);
short bands = mEqualizer.getNumberOfBands();
final short minEQLevel = mEqualizer.getBandLevelRange()[0];
final 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);
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) {
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() {
// Create a VisualizerView (defined below), which will render the
// simplified audio
// wave form to a Canvas.
mVisualizerView = new VisualizerView(this);
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
(int) (VISUALIZER_HEIGHT_DIP * getResources()
.getDisplayMetrics().density)));
mLinearLayout.addView(mVisualizerView);
// Create the Visualizer object and attach it to our media player.
mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
mVisualizer.setDataCaptureListener(
new Visualizer.OnDataCaptureListener() {
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] bytes, int samplingRate) {
mVisualizerView.updateVisualizer(bytes);
}
public void onFftDataCapture(Visualizer visualizer,
byte[] bytes, int samplingRate) {
}
}, Visualizer.getMaxCaptureRate() / 2, true, false);
}
@Override
protected void onPause() {
super.onPause();
if (isFinishing() && mMediaPlayer != null) {
mVisualizer.release();
mEqualizer.release();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
}
/**
* 繪制波狀View
*
* @description:
* @author ldm
* @date 2016-4-20 上午9:11:49
*/
class VisualizerView extends View {
// 數(shù)組保存了波形抽樣點(diǎn)的值
private byte[] bytes;
private float[] points;
// 定義畫(huà)筆
private Paint paint = new Paint();
// 矩形區(qū)域
private Rect rect = new Rect();
private byte type = 0;
public VisualizerView(Context context) {
super(context);
bytes = null;
// 設(shè)置畫(huà)筆的屬性
paint.setStrokeWidth(1f);// 設(shè)置空心線寬
paint.setAntiAlias(true);// 抗鋸齒
paint.setColor(Color.BLUE);// 畫(huà)筆顏色
paint.setStyle(Style.STROKE);// 非填充模式
}
public void updateVisualizer(byte[] ftt) {
bytes = ftt;
// 通知組件重繪
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent me) {
// 當(dāng)用戶觸碰該組件時(shí),切換波形類型
if (me.getAction() != MotionEvent.ACTION_DOWN) {
return false;
}
type++;
if (type >= 3) {
type = 0;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bytes == null) {
return;
}
// 繪制黑色背景
canvas.drawColor(Color.BLACK);
// 使用rect對(duì)象記錄該組件的寬度和高度
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);
// 根據(jù)波形值計(jì)算該矩形的高度
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個(gè)抽樣點(diǎn)繪制一個(gè)矩形)
case 1:
for (int i = 0; i < bytes.length - 1; i += 18) {
float left = rect.width() * i / (bytes.length - 1);
// 根據(jù)波形值計(jì)算該矩形的高度
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數(shù)組還未初始化
if (points == null || points.length < bytes.length * 4) {
points = new float[bytes.length * 4];
}
for (int i = 0; i < bytes.length - 1; i++) {
// 計(jì)算第i個(gè)點(diǎn)的x坐標(biāo)
points[i * 4] = rect.width() * i / (bytes.length - 1);
// 根據(jù)bytes[i]的值(波形點(diǎn)的值)計(jì)算第i個(gè)點(diǎn)的y坐標(biāo)
points[i * 4 + 1] = (rect.height() / 2)
+ ((byte) (bytes[i] + 128)) * 128 / (rect.height() / 2);
// 計(jì)算第i+1個(gè)點(diǎn)的x坐標(biāo)
points[i * 4 + 2] = rect.width() * (i + 1) / (bytes.length - 1);
// 根據(jù)bytes[i+1]的值(波形點(diǎn)的值)計(jì)算第i+1個(gè)點(diǎn)的y坐標(biāo)
points[i * 4 + 3] = (rect.height() / 2)
+ ((byte) (bytes[i + 1] + 128)) * 128
/ (rect.height() / 2);
}
// 繪制波形曲線
canvas.drawLines(points, paint);
break;
}
}
}
自己新建 項(xiàng)目時(shí),記得在res/raw下添加一個(gè)名為test_cbr的mp3格式文件。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android多媒體操作技巧匯總(音頻,視頻,錄音等)》、《Android開(kāi)發(fā)入門(mén)與進(jìn)階教程》、《Android視圖View技巧總結(jié)》、《Android編程之a(chǎn)ctivity操作技巧總結(jié)》、《Android文件操作技巧匯總》、《Android資源操作技巧匯總》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- Android音視頻開(kāi)發(fā)之MediaPlayer使用教程
- Android MediaPlayer 音頻倍速播放 調(diào)整播放速度問(wèn)題
- Android MediaPlayer 播放音頻的方式
- Android多媒體應(yīng)用使用MediaPlayer播放音頻
- Android開(kāi)發(fā)之MediaPlayer多媒體(音頻,視頻)播放工具類
- Android編程視頻播放API之MediaPlayer用法示例
- Android實(shí)現(xiàn)簡(jiǎn)單音樂(lè)播放器(MediaPlayer)
- Android MediaPlayer音頻播放器封裝示例淺析
相關(guān)文章
Android?Gradle?插件自定義Plugin實(shí)現(xiàn)注意事項(xiàng)
這篇文章主要介紹了Android?Gradle?插件自定義Plugin實(shí)現(xiàn)注意事項(xiàng),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-06-06
android開(kāi)發(fā)教程之a(chǎn)ndroid的handler使用方法
這篇文章主要介紹了android的handler使用方法,大家參考使用吧2014-01-01
Android StickyListHeaders實(shí)現(xiàn)電話本列表效果
這篇文章主要為大家詳細(xì)介紹了Android StickyListHeaders實(shí)現(xiàn)電話本列表效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
Android獲取分享應(yīng)用列表詳解及實(shí)例
這篇文章主要介紹了Android獲取分享應(yīng)用列表詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-04-04
HttpURLConnection和okHttp兩種獲取網(wǎng)絡(luò)數(shù)據(jù)的實(shí)現(xiàn)方法
下面小編就為大家分享一篇HttpURLConnection和okHttp兩種獲取網(wǎng)絡(luò)數(shù)據(jù)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
淺析Android中build.gradle的實(shí)用技巧
這篇文章主要介紹了淺析Android中build.gradle的實(shí)用技巧,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03

