Android編程之播放器MediaPlayer實(shí)現(xiàn)均衡器效果示例
本文實(shí)例講述了Android播放器MediaPlayer實(shí)現(xiàn)均衡器效果。分享給大家供大家參考,具體如下:
這幾天在系統(tǒng)學(xué)習(xí)Android官方API Demos,看到實(shí)現(xiàn)均衡器效果,就把官方API中代碼copy下來,根據(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;
// 定義畫筆
private Paint paint = new Paint();
// 矩形區(qū)域
private Rect rect = new Rect();
private byte type = 0;
public VisualizerView(Context context) {
super(context);
bytes = null;
// 設(shè)置畫筆的屬性
paint.setStrokeWidth(1f);// 設(shè)置空心線寬
paint.setAntiAlias(true);// 抗鋸齒
paint.setColor(Color.BLUE);// 畫筆顏色
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開發(fā)入門與進(jìn)階教程》、《Android視圖View技巧總結(jié)》、《Android編程之a(chǎn)ctivity操作技巧總結(jié)》、《Android文件操作技巧匯總》、《Android資源操作技巧匯總》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Android庫項(xiàng)目中的資源ID沖突的解決方法
本篇文章主要介紹了Android庫項(xiàng)目中的資源ID沖突的解決方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
Android開發(fā)實(shí)現(xiàn)模仿360二維碼掃描功能實(shí)例詳解
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)模仿360二維碼掃描功能,結(jié)合實(shí)例形式詳細(xì)分析了Android開發(fā)二維碼掃描功能所涉及的zxing開源項(xiàng)目文件使用方法及具體掃碼功能相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-10-10
Android編程開發(fā)之seekBar采用handler消息處理操作的方法
這篇文章主要介紹了Android編程開發(fā)之seekBar采用handler消息處理操作的方法,結(jié)合實(shí)例分析了Android實(shí)現(xiàn)進(jìn)度條功能的相關(guān)技巧,需要的朋友可以參考下2015-12-12
android實(shí)現(xiàn)圓形漸變進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)圓形漸變進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05

