zoukankan      html  css  js  c++  java
  • Android 音乐频谱实现

    最近由于需要实现音乐频谱,所以今天就为大家普及一下。关于音乐频谱你需要了解数字信号处理的知识,尤其是FFT的知识。简单说就是把时域上连续的信号(波形)强度转换成离散的频域信号(频谱)。我理解波形就是信号的强度,或者说音响设备的输出的功率,功率高,音量就大。但是歌曲的曲调是不会变的,因为频谱是不会变的。

    频谱反映的是这个这个音乐在某个连续时间段内,声音的震动频率。不知道理解的对不对。

    本文的音乐频谱实现是仿照Android Api Demo 里的一个例子实现的,需要Android 2.3及以上系统,因为要用到Visualizer 类,这个类只在Android 2.3以上的API才支持。

    首先实例化Visualizer,参数SessionId可以通过MediaPlayer的对象获得

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. visualizer = new Visualizer(mPlayerInstance.getAudioSessionId());  

    接着设置需要转换的音乐内容长度,专业的说这就是采样,该采样值一般为2的指数倍,如64,128,256,512,1024。这里我设置了128,原因是长度越长,FFT算法运行时间更长。

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. visualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[0]);  

    然后为visualizer设置监听器,这样当Capture一段数据后,就会触发两个函数进行处理。设置监听函数为

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. setDataCaptureListener(OnDataCaptureListener listener, rata,iswave,isfft )  

    参数解释:

    rate, 表示采样的周期,即隔多久采样一次,联系前文就是隔多久采样128个数据,本文设置为512mHz更新一次

    iswave,是波形信号

    isfft,是FFT信号,表示是获取波形信号还是频域信号

    OnDataCaptureListener,表监听函数,匿名内部类实现该接口,该接口需要实现两个函数

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. onWaveFormDataCapture(Visualizer visualizer,byte[] waveform, int samplingRate)   

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. public void onFftDataCapture(Visualizer visualizer,byte[] fft, int samplingRate)   

    samplingRate是采样速率,即上文的rate值,512mHz。

    其中两个byte[] waveform和byte[] fft数组,分别是获得波形数据和FFT的数据,该byte数组的大小即为之前设置的采样值大小128,获得数据如下图所示。

    其中n为采样值,index 0 表示直流分量,Rf表示FFT计算后的实部,If表示FFT计算后的虚部。

    如何计算出该频率,就是将FFT的实部和对应的虚部先各自平方再相加然后开方,简单说就是平方取模。

    具体计算请看如下的代码。

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. visualizer.setDataCaptureListener(  
    2.     new Visualizer.OnDataCaptureListener() {  
    3.   
    4.         @Override  
    5.         public void onWaveFormDataCapture(Visualizer visualizer,  
    6.             byte[] waveform, int samplingRate) {  
    7.   
    8.             // 这里添加获得数据的处理 byte[] 数组 更新出去,并画图。这里可以把这个  
    9.             // 数组传到RunOnMusic里去  
    10.             // visualView.updateVisualizer(waveform);  
    11.   
    12.         }  
    13.   
    14.         @Override  
    15.         public void onFftDataCapture(Visualizer visualizer,  
    16.             byte[] fft, int samplingRate) {  
    17.             byte[] model = new byte[fft.length / 2 + 1];  
    18.             model[0] = (byte) Math.abs(fft[1]);  
    19.             int j = 1;  
    20.   
    21.             for (int i = 2; i < 18;) {  
    22.                 model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);  
    23.                 i += 2;  
    24.                 j++;  
    25.             }  
    26.   
    27.             visualView.updateVisualizer(model);  
    28.   
    29.         }  
    30.     }, Visualizer.getMaxCaptureRate() / 2, false, true);  
    31.   
    32. }  

    其中visualView是显示程序,updateVisulizer是将model获取的频谱值更新到要显示的view。

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1.      protected void onDraw(Canvas canvas) {  
    2.     super.onDraw(canvas);  
    3.   
    4.     if (mBytes == null) {  
    5.         return;  
    6.     }  
    7.   
    8.     if (mPoints == null || mPoints.length < mBytes.length * 4) {  
    9.       
    10.                    mPoints = new float[mBytes.length * 4];  
    11.                    mRect.set(0, 0, getWidth(), getHeight() - 50);  
    12.                   
    13.                    for (int i = 0; i < 9; i++) {  
    14.                  
    15.                        if (mBytes[i] < 0)  
    16.                            mBytes[i] = 127;   
    17.                          
    18.                        mPoints[i * 4] = mRect.width() * i / 9;  
    19.                        mPoints[i * 4 + 1] = mRect.height() / 2;  
    20.                        mPoints[i * 4 + 2] = mRect.width() * i / 9;  
    21.                        mPoints[i * 4 + 3] = 2 + mRect.height() / 2 + mBytes[i];  
    22.                    }  
    23.                    canvas.drawLines(mPoints, mForePaint);  
    24.                }  
    25.   
    26. }  
  • 相关阅读:
    c++智能指针-shared_ptr
    python全栈学习笔记(二)网络基础之子网划分
    python全栈学习笔记(一)网络基础之网络协议篇
    Fiddler抓包4-工具介绍(request和response)
    python接口自动化5-Json数据处理
    python接口自动化4-绕过验证码登录(cookie) (转载)
    Http status(二)
    python接口自动化1-发送get请求
    Fiddler抓包11-HTTPS证书Actions无法导出问题
    使用idea配置tomcat将web项目跑起来
  • 原文地址:https://www.cnblogs.com/li-fei/p/4293940.html
Copyright © 2011-2022 走看看