android获取和展现音乐的频谱

还有一些帖子: https://blog.csdn.net/Qzhongwenze/article/details/52851297html

http://blog.sina.com.cn/s/blog_67d95f40010113ec.htmljava

https://blog.csdn.net/caryee89/article/details/6935237android

https://blog.csdn.net/qq2582494/article/details/74393315git

https://blog.csdn.net/java173842219/article/details/54096598 (不少音乐播放器类的Android项目源码)github

https://blog.csdn.net/SCTU_vroy/article/details/45871823 (Android平台音频信号FFT的实现 源码,还有各类滤波算法:https://github.com/vroy007/MoveDSP)算法

https://www.jianshu.com/p/cdd09b840500 (Android:音乐特效控制 有回声,噪音删除,波形)canvas

http://www.javashuo.com/article/p-vklhojgg-gy.html (Android 音频FFT提取分析 )数组

http://www.javashuo.com/article/p-cgorruls-gm.html (Android音频进阶 Equalizer,Visualizer,BassBoost,PresetReverb,EnvironmentalReverb)session

https://www.cnblogs.com/Free-Thinker/p/5027830.html (Android提升第十一篇之模拟信号示波器)ide

https://www.cnblogs.com/sage-blog/p/3885802.html (JNI实例1---扫描SD卡中mp3文件 JNI实例2---扫描SD卡中mp3文件,native层调用Java自定义的类 JNI实例3---扫描SD卡中mp3文件,native层调用Java自定义的类)

针对onFftDataCapture拿到的数据全为0的状况,这一篇帖子中有更祥细的变量说明: https://blog.csdn.net/suwenlie/article/details/45070883

作了个音乐播放器 就一直想作个加一个音乐频谱的展现界面

觉的这是一个好玩的东西,能够将耳边动听的声音形象化,仿佛眼前能够看到声音同样。

可是我在文档的开发者指南里没有讲任何有关音乐频谱的东西,最后仍是在google的源码示例中找到了。

你能够直接去参看源代码更原滋原味 如下只是我的对着源码的重构和理解

全部如下所讲的功能,均须要在2.3以上的sdk中才能实现。

音频频谱的获取

首先音频的频谱相关的类叫作 android.media.audiofx.Visualizer;

须要权限 <uses-permission android:name="android.permission.RECORD_AUDIO"/> 因此要作的第一件事 是初始化一个visualizer出来

//使用音乐的sessionId来实例化这个类

        mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
        //设置每次捕获频谱的大小,音乐在播放中的时候采集的数据的大小或者说是采集的精度吧,个人理解,并且getCaptureSizeRange()所返回的数组里面就两个值 .文档里说数组[0]是最小值(128),数组[1]是最大值(1024)。

        mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);



       //接下来就好理解了设置一个监听器来监听不断而来的所采集的数据。一共有4个参数,第一个是监听者,第二个单位是毫赫兹,表示的是采集的频率,第三个是是否采集波形,第四个是是否采集频率
        mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
           

       //这个回调应该采集的是波形数据
            [@Override](https://my.oschina.net/u/1162528)
            public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform,
                    int samplingRate) {

            //waveformView 是一个自定义的view用来按照波形来画图 一会后面再讲
                waveformView.updateVisualizer(waveform);
            }
           

     //这个回调应该采集的是快速傅里叶变换有关的数据,没试过,回头有空了再试试
            [@Override](https://my.oschina.net/u/1162528)
            public void onFftDataCapture(Visualizer visualizer, byte[] fft,
                    int samplingRate) {
                // TODO Auto-generated method stub
               
            }
        }, Visualizer.getMaxCaptureRate() / 2, true, false);

以上波形的数据采集就完成了,须要注意的一个点是mVisualizer.setEnabled(true);

这个方法的主要做用是为了控制什么时候去采集频谱数据,你应该只是愿意采集你所关心的音乐数据,而不关心声音输出器中任何的声音。并且对mVisualizer的许多设置必须在setEnable以前完成。而且结束功能后,要记得setEnable(false)

若是你见到了如下这个错误,那基本上就是由于没有及时setEnable(false),致使setCaptureSize()这个方法出错。

E/AndroidRuntime(22259): Caused by: java.lang.IllegalStateException: setCaptureSize() called in wrong state: 2

顺带再说一个bug 若是你获得的错误代码是 -1 那么基本上的缘由是你忘记了声明权限

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

音频频谱的展现

你在上一节已经经过监听器得到了波形数据,那么如何展现?这仅仅是一个自定义view的问题,简单废话一下:重点提一下view中的onDraw()方法

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas);

//mBytes就是采集来的数据 这里是个大小为1024的数组,里面的数据都是byts类型,因此大小为-127到128

if (mBytes == null) {
        return;
    }

    if (mPoints == null || mPoints.length < mBytes.length * 4) {

//mPoints主要用来存储要画直线的4个坐标(每一个点两个坐标,因此一条直线须要两个点,也就是4个坐标) mPoints = new float[mBytes.length * 4]; }

mRect.set(0, 0, getWidth(), getHeight());

//xOrdinate是x轴的总刻度,由于一次会传输过来1024个数据,每两个数据要画成一条直线,因此x轴咱们分红1023段。你要是觉的太多了,也能够像我同样除以2,看本身需求了。

int xOrdinate = (mBytes.length - 1)/2;

//如下的for循环将利用mBytes[i] mBytes[i+1] 这两个数据去生成4个坐标值,从而在刻画成两个坐标,来画线条 for (int i = 0; i <xOrdinate ; i++) {

//第i个点在总横轴上的坐标,

        mPoints[i * 4] = mRect.width() * i / xOrdinate;

//第i个点的在总纵轴上的坐标。他在画线上以总纵轴的1/2为基准线(mRect.height() / 2),全部的点或正或负以此线为基础标记。

//((byte) (mBytes[i] + 128))这个一直没有理解,若是+128是为了将数据所有换算为正整数,那么强转为byte后不又变回-127到128了么??要是谁知道缘由能够留言告诉我.....

//(mRect.height() / 2) / 128就是将二分之一的总长度换算成128个刻度,由于咱们的数据是byte类型,因此刻画成128个刻度正好 mPoints[i * 4 + 1] = mRect.height() / 2+ ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;

//如下就是刻画第i+1个数据了,原理和刻画第i个同样 mPoints[i * 4 + 2] = mRect.width() * (i + 1) / xOrdinate; mPoints[i * 4 + 3] = mRect.height() / 2 + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128; }

//循环结束后,就获得了这一次波形的全部刻画坐标,直接画在画布上就行了

canvas.drawLines(mPoints, mForePaint);
}

作的音乐软件 纯粹好玩 就放在了国内的market上

http://market.nduoa.com/apk/detail/412136

相关文章
相关标签/搜索