android手机上实现竖直seekbar的EQ均衡器

news/2024/11/22 22:02:11/

From:http://www.cnblogs.com/wenjiang/archive/

2013/05/10/3071103.html

     做音乐播放器,有时会要求EQ均衡器,但android默认的样式是水平的,这时就需要费点心思了。

     先是实现默认SeekBar样式的EQ均衡器:

    

    

      这是4.0以上默认样式的SeekBar,2.3或以下就像是进度条一样。

      要实现这样的效果,其实并不难,先贴上源码:

复制代码
public class MainActivity extends Activity {private MediaPlayer mMediaPlayer;private Equalizer mEqualizer;private LinearLayout mLayout;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setVolumeControlStream(AudioManager.STREAM_MUSIC);mLayout = new LinearLayout(this);mLayout.setOrientation(LinearLayout.VERTICAL);setContentView(mLayout);mMediaPlayer = new MediaPlayer();try {mMediaPlayer.setDataSource("/sdcard/陪我去流浪.mp3");mMediaPlayer.prepare();mMediaPlayer.start();} catch (IllegalArgumentException e) {// TODO Auto-generated catch block
            e.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch block
            e.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch block
            e.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch block
            e.printStackTrace();}setEqualize();}@TargetApi(Build.VERSION_CODES.GINGERBREAD)private void setEqualize() {mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());mEqualizer.setEnabled(true);short bands = mEqualizer.getNumberOfBands();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.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));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.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));minDbTextView.setText((minEqualizer / 100) + " dB");TextView maxDbTextView = new TextView(this);maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));maxDbTextView.setText((maxEqualizer / 100) + " dB");LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);SeekBar seekbar = new SeekBar(this);seekbar.setLayoutParams(layoutParams);seekbar.setMax(maxEqualizer - minEqualizer);seekbar.setProgress(mEqualizer.getBandLevel(band));seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@TargetApi(Build.VERSION_CODES.GINGERBREAD)@Overridepublic 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);}}@TargetApi(Build.VERSION_CODES.GINGERBREAD)@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();if (isFinishing() && mMediaPlayer != null) {mMediaPlayer.release();mEqualizer.release();mMediaPlayer = null;}}
}
复制代码

      这里我采用了手动设置Layout布局的方式,因为上面的Layout采用LinearLayout实现,并且每个SeekBar的属性设置都一样,考虑到SeekBar的数量较多,采用这个方式可能会更好点,至少我们不需要写太繁琐的Layout布局文件。
      撇开那些Layout的布局代码,我们看看最主要的部分:SeekBar和Equalizer的设置。

      android系统提供内置的Equalizer支持,我们可以直接声明并且使用。但必须注意,当我们在代码中使用Equalizer的时候,其实就是调整音量(EQ均衡器是改变音频使得声音发生变化,像是洪亮或者低沉)。所以,我们需要在我们的代码中声明这么一句:

setVolumeControlStream(AudioManager.STREAM_MUSIC);

      因为涉及到硬件方面的修改,我们需要权限:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

      它允许我们进行全局的音频设置。
      我们再来看看这句:

mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());

      每个MediaPlayer都有自己独一无二的SessionId,我们需要将Equalizer附加到这个MediaPlayer上,就必须获取该SessionId。然后我们再创建一个优先级为0的Equalizer对象。所谓的优先级,是因为一个Equalizer engine可以被多个应用程序共享,所以我们必须设置优先级,优先级0代表该应用程序为正常级别。
     要想启动Equalizer,我们还必须这样子:

mEqualizer.setEnabled(true);

    这就是学过单片机的同学非常熟悉的"使能"。

    然后我们再获取支持的频谱:

 short bands = mEqualizer.getNumberOfBands();

    不同的硬件设备支持的频谱是不一样的,像是电脑能支持的频谱就比手机要多得多。
    接着就是获取频谱中的等级范围,我们只需要获取最低和最高即可。

final short minEqualizer = mEqualizer.getBandLevelRange()[0];
final short maxEqualizer = mEqualizer.getBandLevelRange()[1];

     接下来就是遍历频谱,设置SeekBar了:

复制代码
seekbar.setMax(maxEqualizer - minEqualizer);
seekbar.setProgress(mEqualizer.getBandLevel(band));seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@TargetApi(Build.VERSION_CODES.GINGERBREAD)@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {mEqualizer.setBandLevel(band, (short) (progress + minEqualizer));}
});
复制代码

      我们必须设置SeekBar的最大进度范围,也就是进度顶端所代表的值。接着就是实现SeekBar进度改变时,Equalizer的音频也跟着相应的改变,这就需要监听SeekBar。
      好了,到了这里,基本的EQ均衡器已经实现了,但我们想要的并不是功能的实现,而是界面的实现(这往往是我们这些移动互联网开发者的恶梦,美工设计师们从来都没有考虑过我们要设计出他们的界面有时是多么难甚至不可能的一件事啊!)。

      既然默认的SeekBar样式无法满足我们的要求,我们只能自定义自己想要的SeekBar了。幸好,android还是提供了这种支持:只要继承自AbsSeekBr,我们就能得到自己想要的SeekBar了。

      依然先上源码:

复制代码
public class VerticalSeekBar extends AbsSeekBar {private Drawable mThumb;private int height;private int width;public interface OnSeekBarChangeListener {void onProgressChanged(VerticalSeekBar VerticalSeekBar, int progress,boolean fromUser);void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar);void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar);}private OnSeekBarChangeListener mOnSeekBarChangeListener;public VerticalSeekBar(Context context) {this(context, null);}public VerticalSeekBar(Context context, AttributeSet attrs) {this(context, attrs, android.R.attr.seekBarStyle);}public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {mOnSeekBarChangeListener = l;}void onStartTrackingTouch() {if (mOnSeekBarChangeListener != null) {mOnSeekBarChangeListener.onStartTrackingTouch(this);}}void onStopTrackingTouch() {if (mOnSeekBarChangeListener != null) {mOnSeekBarChangeListener.onStopTrackingTouch(this);}}void onProgressRefresh(float scale, boolean fromUser) {Drawable thumb = mThumb;if (thumb != null) {setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);invalidate();}if (mOnSeekBarChangeListener != null) {mOnSeekBarChangeListener.onProgressChanged(this, getProgress(),fromUser);}}private void setThumbPos(int w, Drawable thumb, float scale, int gap) {int available = w + getPaddingLeft() - getPaddingRight();int thumbWidth = thumb.getIntrinsicWidth();int thumbHeight = thumb.getIntrinsicHeight();available -= thumbWidth;
        available += getThumbOffset() / 2;int thumbPos = (int) (scale * available);int topBound, bottomBound;if (gap == Integer.MIN_VALUE) {Rect oldBounds = thumb.getBounds();topBound = oldBounds.top;bottomBound = oldBounds.bottom;} else {topBound = gap;bottomBound = gap + thumbHeight;}thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);}protected void onDraw(Canvas c) {c.rotate(-90);c.translate(-height, 0);super.onDraw(c);}protected synchronized void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {height = View.MeasureSpec.getSize(heightMeasureSpec) / 2;width = 50;this.setMeasuredDimension(width, height);}@Overridepublic void setThumb(Drawable thumb) {mThumb = thumb;super.setThumb(thumb);}protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(h, w, oldw, oldh);}public boolean onTouchEvent(MotionEvent event) {if (!isEnabled()) {return false;}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:setPressed(true);onStartTrackingTouch();trackTouchEvent(event);break;case MotionEvent.ACTION_MOVE:trackTouchEvent(event);attemptClaimDrag();break;case MotionEvent.ACTION_UP:trackTouchEvent(event);onStopTrackingTouch();setPressed(false);break;case MotionEvent.ACTION_CANCEL:onStopTrackingTouch();setPressed(false);break;}return true;}private void trackTouchEvent(MotionEvent event) {final int Height = getHeight();final int available = Height - getPaddingBottom() - getPaddingTop();int Y = (int) event.getY();float scale;float progress = 0;if (Y > Height - getPaddingBottom()) {scale = 0.0f;} else if (Y < getPaddingTop()) {scale = 1.0f;} else {scale = (float) (Height - getPaddingBottom() - Y)/ (float) available;}final int max = getMax();progress = scale * max;setProgress((int) progress);}private void attemptClaimDrag() {if (getParent() != null) {getParent().requestDisallowInterceptTouchEvent(true);}}public boolean dispatchKeyEvent(KeyEvent event) {if (event.getAction() == KeyEvent.ACTION_DOWN) {KeyEvent newEvent = null;switch (event.getKeyCode()) {case KeyEvent.KEYCODE_DPAD_UP:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_RIGHT);break;case KeyEvent.KEYCODE_DPAD_DOWN:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_LEFT);break;case KeyEvent.KEYCODE_DPAD_LEFT:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_DOWN);break;case KeyEvent.KEYCODE_DPAD_RIGHT:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_UP);break;default:newEvent = new KeyEvent(KeyEvent.ACTION_DOWN,event.getKeyCode());break;}return newEvent.dispatch(this);}return false;}
}
复制代码

       代码很长,但关键是我上面标记的几个方法。
       onDraw()该方法就是实现竖直SeekBar的关键。我们可以看到,关键就是那个c.rotate(-90),它实现了我们的竖直:通过反转-90度。setThumbPos()方法是为了调整thumb的大小,这个很重要,尤其是当我们开始排版的时候,thumb很可能因为布局的问题而显示不完全或者根本就不见了。onMeasure()针对的是进度条的设置。至于具体的大小怎样设置,得看大家自己的具体应用了。

       这个是实现的效果:

      

      前面的代码基本保持不变,只要将SeekBar改为VerticalSeekBar就可以了:

复制代码
for (short i = 0; i < bands; i++) {final short band = i;int index = (int) i;VerticalSeekBar seekBar = (VerticalSeekBar) findViewById(seekBars[index]);seekBar.setMax(maxEqualizer - minEqualizer);seekBar.setProgress(mEqualizer.getBandLevel(band));seekBar.setOnSeekBarChangeListener(new VerticalSeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(VerticalSeekBar VerticalSeekBar,int progress, boolean fromUser) {mEqualizer.setBandLevel(band,(short) (progress + minEqualizer));}@Overridepublic void onStartTrackingTouch(VerticalSeekBar VerticalSeekBar) {// TODO Auto-generated method stub
}@Overridepublic void onStopTrackingTouch(VerticalSeekBar VerticalSeekBar) {// TODO Auto-generated method stub
}});
复制代码

       为了实现我上面的布局效果,我这次使用了RelativeLayout布局文件,至于那些间距的调整,就留给读者们了。

      这样的效果还是不行的,因为有个致命的缺陷:android2.3的默认样式和android4.0的默认样式是不一样的!别看我上面的效果挺美观的,在android2.3上可不是这样。

      最好的解决方法就是替换默认样式。

      替换默认样式的方法很简单:在res目录下,新建drawable文件夹,然后我们在该目录下新建一个xml文件:

复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" ><item android:id="@android:id/secondaryProgress"><clip android:drawable="@drawable/progress2" /></item><item android:id="@android:id/progress"><clip android:drawable="@drawable/progress1" /></item></layer-list>
复制代码

     我们可以使用layer-list来替换默认样式,secondaryProgress指的是我们进度条中剩下的进度,progress指的就是我们当前的进度。
     分别设置好它们的替换图片后,我们再在SeekBar中这样设置:

复制代码
<com.example.eqpratice.VerticalSeekBarandroid:id="@+id/sec"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/fir"android:progressDrawable="@drawable/progress"android:secondaryProgress="100"android:thumb="@drawable/thumb" />
复制代码

     这里android: secondaryProgress="100"设置的是我们thumb能达到的最大进度,这个是要设置的,不然会出现thumb超出进度条的情况。
     现在的效果如图:

     

        大家可以根据自己的需要,自定义自己想要的样式。

        因为是菜鸟,很多东西都是一笔带过,写得不好或者是有错的,还请各位大神指教。

     


http://www.ppmy.cn/news/344713.html

相关文章

[zz] 音频均衡器Equalizer算法研究与实现

一. 声学背景 心理声学研究证实人耳可闻的声音频率范围为20Hz--20kHz。在可闻的频率范围内&#xff0c;不同的频段对人耳的感知影响不同。 如下所述&#xff1a; “1. 20Hz--60Hz部分 这一段提升能给音乐强有力的感觉&#xff0c;给人很响的感觉&#xff0c;如雷声。是音乐…

音乐频率的划分及播放器均衡器设置

专业音乐播放器均衡器设置 转载&#xff1a;https://www.jianshu.com/p/d3d2d2f3330b 0.1442014.05.08 01:43:34字数 4,990阅读 552 均衡器还可以用来根据用家听音口味做适当优化&#xff0c;比如&#xff1a;适当提升7khz和10khz可以突出细节并且让人声变甜。而对14khz和20…

均衡器代码

最近在做均衡器&#xff0c;上网找了一堆&#xff0c;但是能方便使用的很少。大部分都是直接MP3出来后就来一个EQ&#xff0c;一个功能的代码散落在各个角楼里&#xff0c;很难整理。 还好有xmms这个eq插件&#xff0c;感谢开源的奉献精神&#xff0c;原来的代码是在linux的…

Android自带音频均衡器MusicFx分析

Android自带音频均衡器MusicFx分析 种种原因&#xff0c;我要简单分析一个Android中built-in的音频均衡器MusicFx。重点是它的默认值的来历。网上很少有文章讲了这个的除了这篇《com.android.musicFx设置音效流程 -- 从app到AudioFlinger》。注&#xff1a;Android系统版本为4.…

百万调音师—Audition EQ均衡器

百万调音师—Audition EQ均衡器 频率分析FFT&#xff08;快速傅里叶变换&#xff09;图形均衡器10段20段30段 陷波滤波器参数均衡器补充&#xff1a;知识EQ黄金定律 eq均衡器定义 EQ是Equalizer的缩写&#xff0c;中国大陆地区称呼为均衡器&#xff0c;港台地区称呼为等化器。它…

poweramp最完美设置_【分享】三种针对音乐神器PowerAmp的均衡器设置方法

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 【第一种设置方法】:完美低音 具体设置如下&#xff1a;第一是增益&#xff0c;增益往后共有十个频段&#xff0c;从左至右是低音到高音&#xff0c;我的设 置方法从均衡器的初始状态开始&#xff0c;即在中间&#xff0c;设值为0…

EQ均衡器原理

做音乐最离不开的效果器是什么&#xff1f;相信大多数朋友都会回答&#xff1a;是EQ&#xff01;不错&#xff0c;正是有了这个所谓“均衡”的效果器&#xff0c;我们的音乐才不会过载&#xff0c;乐器音色才会如此丰富。然而知道1加1等于2更要知道1加1为什么等于2。今天我把这…

音乐均衡器EQ的调试方法(一)

Fruity Parametric EQ 2均衡器&#xff0c;是一款我们在FL Studio制作音乐时经常会用到的插件&#xff0c;它是EQ中的战斗鸡&#xff0c;它不仅有一个高级的 7 波段参数均衡器&#xff0c;还具有声谱分析能力。我们在对很多曲子的音色进行调整时都会用到它。 如果我们自己调节…