android音乐柱状频谱实现


注意android2.3以后才可用,主要用到这个类Visualizer,这个源码其实是apiDemos中一个例子,但例子中实现的是两种中的波形显示,而不是频谱显示,

原文博主实现了另一种频谱显示,并分享出来,精神可嘉。我做了些修改,使稍微好看了些,继续分享。


官方文档解释:

public int getFft (byte[] fft)

Since:  API Level 9

Returns a frequency capture of currently playing audio content.

This method must be called when the Visualizer is enabled.

The capture is an 8-bit magnitude FFT, the frequency range covered being 0 (DC) to half of the sampling rate returned by getSamplingRate(). The capture returns the real and imaginary parts of a number of frequency points equal to half of the capture size plus one.

Note: only the real part is returned for the first point (DC) and the last point (sampling frequency / 2).

The layout in the returned byte array is as follows:

  • n is the capture size returned by getCaptureSize()
  • Rfk, Ifk are respectively the real and imaginary parts of the kth frequency component
  • If Fs is the sampling frequency retuned by getSamplingRate() the kth frequency is: (k*Fs)/(n/2)
Index

0

1

2

3

4

5

...

n - 2

n - 1

Data

Rf0

Rf(n/2)

Rf1

If1

Rf2

If2

...

Rf(n-1)/2

If(n-1)/2

Parameters
fft array of bytes where the FFT should be returned
Returns
  • SUCCESS in case of success, ERROR_NO_MEMORYERROR_INVALID_OPERATION or ERROR_DEAD_OBJECT in case of failure.
Throws
IllegalStateException  
实部和虚部的平方和就是振幅的平方,因为是byte类型,所以最大值是127。


对原文的代码做了一些修改,使更好看一些,代码中用到的歌曲谁要用到,自己重新放一首就行,代码如下:


[java]  view plain copy
  1. /* 
  2.  * Copyright (C) 2010 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.AudioFx;  
  18.   
  19. import android.app.Activity;  
  20. import android.content.Context;  
  21. import android.graphics.Canvas;  
  22. import android.graphics.Color;  
  23. import android.graphics.Paint;  
  24. import android.graphics.Rect;  
  25. import android.media.AudioManager;  
  26. import android.media.MediaPlayer;  
  27. import android.media.audiofx.Equalizer;  
  28. import android.media.audiofx.Visualizer;  
  29. import android.os.Bundle;  
  30. import android.util.Log;  
  31. import android.view.Gravity;  
  32. import android.view.View;  
  33. import android.view.ViewGroup;  
  34. import android.view.WindowManager;  
  35. import android.widget.LinearLayout;  
  36. import android.widget.SeekBar;  
  37. import android.widget.TextView;  
  38.   
  39. public class AudioFxActivity extends Activity  
  40. {  
  41.     private static final String TAG = "AudioFxActivity";  
  42.   
  43.     private static final float VISUALIZER_HEIGHT_DIP = 160f;  
  44.   
  45.     private MediaPlayer mMediaPlayer;  
  46.     private Visualizer mVisualizer;  
  47.     private Equalizer mEqualizer;  
  48.   
  49.     private LinearLayout mLinearLayout;  
  50.     private VisualizerView mVisualizerView;  
  51.     private TextView mStatusTextView;  
  52.     private TextView mInfoView;  
  53.   
  54.     @Override  
  55.     public void onCreate(Bundle icicle)  
  56.     {  
  57.         super.onCreate(icicle);  
  58.           
  59.         mStatusTextView = new TextView(this);  
  60.   
  61.         mLinearLayout = new LinearLayout(this);  
  62.         mLinearLayout.setOrientation(LinearLayout.VERTICAL);  
  63.         mLinearLayout.addView(mStatusTextView);  
  64.   
  65.         setContentView(mLinearLayout);  
  66.   
  67.         // Create the MediaPlayer  
  68.         mMediaPlayer = MediaPlayer.create(this, R.raw.my_life);  
  69.         Log.d(TAG,  
  70.                 "MediaPlayer audio session ID: "  
  71.                         + mMediaPlayer.getAudioSessionId());  
  72.   
  73.         setupVisualizerFxAndUI();  
  74.         setupEqualizerFxAndUI();  
  75.   
  76.         // Make sure the visualizer is enabled only when you actually want to  
  77.         // receive data, and  
  78.         // when it makes sense to receive data.  
  79.         mVisualizer.setEnabled(true);  
  80.   
  81.         // When the stream ends, we don't need to collect any more data. We  
  82.         // don't do this in  
  83.         // setupVisualizerFxAndUI because we likely want to have more,  
  84.         // non-Visualizer related code  
  85.         // in this callback.  
  86.         mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()  
  87.                 {  
  88.                     public void onCompletion(MediaPlayer mediaPlayer)  
  89.                     {  
  90.                         mVisualizer.setEnabled(false);  
  91.                         getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
  92.                         setVolumeControlStream(AudioManager.STREAM_SYSTEM);  
  93.                         mStatusTextView.setText("音乐播放完毕");  
  94.                     }  
  95.                 });  
  96.   
  97.         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
  98.         setVolumeControlStream(AudioManager.STREAM_MUSIC);  
  99.         mMediaPlayer.start();  
  100.         mStatusTextView.setText("播放音乐中....");  
  101.     }  
  102.   
  103.     private void setupEqualizerFxAndUI()  
  104.     {  
  105.         // Create the Equalizer object (an AudioEffect subclass) and attach it  
  106.         // to our media player,  
  107.         // with a default priority (0).  
  108.         mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());  
  109.         mEqualizer.setEnabled(true);  
  110.   
  111.         TextView eqTextView = new TextView(this);  
  112.         eqTextView.setText("均衡器:");  
  113.         mLinearLayout.addView(eqTextView);  
  114.   
  115.         short bands = mEqualizer.getNumberOfBands();  
  116.   
  117.         final short minEQLevel = mEqualizer.getBandLevelRange()[0];  
  118.         final short maxEQLevel = mEqualizer.getBandLevelRange()[1];  
  119.   
  120.         for (short i = 0; i < bands; i++)  
  121.         {  
  122.             final short band = i;  
  123.   
  124.             TextView freqTextView = new TextView(this);  
  125.             freqTextView.setLayoutParams(new ViewGroup.LayoutParams(  
  126.                     ViewGroup.LayoutParams.FILL_PARENT,  
  127.                     ViewGroup.LayoutParams.WRAP_CONTENT));  
  128.             freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);  
  129.             freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000)  
  130.                     + " Hz");  
  131.             mLinearLayout.addView(freqTextView);  
  132.   
  133.             LinearLayout row = new LinearLayout(this);  
  134.             row.setOrientation(LinearLayout.HORIZONTAL);  
  135.   
  136.             TextView minDbTextView = new TextView(this);  
  137.             minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(  
  138.                     ViewGroup.LayoutParams.WRAP_CONTENT,  
  139.                     ViewGroup.LayoutParams.WRAP_CONTENT));  
  140.             minDbTextView.setText((minEQLevel / 100) + " dB");  
  141.   
  142.             TextView maxDbTextView = new TextView(this);  
  143.             maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(  
  144.                     ViewGroup.LayoutParams.WRAP_CONTENT,  
  145.                     ViewGroup.LayoutParams.WRAP_CONTENT));  
  146.             maxDbTextView.setText((maxEQLevel / 100) + " dB");  
  147.   
  148.             LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(  
  149.                     ViewGroup.LayoutParams.FILL_PARENT,  
  150.                     ViewGroup.LayoutParams.WRAP_CONTENT);  
  151.             layoutParams.weight = 1;  
  152.             SeekBar bar = new SeekBar(this);  
  153.             bar.setLayoutParams(layoutParams);  
  154.             bar.setMax(maxEQLevel - minEQLevel);  
  155.             bar.setProgress(mEqualizer.getBandLevel(band));  
  156.   
  157.             bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()  
  158.             {  
  159.                 public void onProgressChanged(SeekBar seekBar, int progress,  
  160.                         boolean fromUser)  
  161.                 {  
  162.                     mEqualizer.setBandLevel(band, (short) (progress + minEQLevel));  
  163.                 }  
  164.   
  165.                 public void onStartTrackingTouch(SeekBar seekBar)  
  166.                 {  
  167.                 }  
  168.   
  169.                 public void onStopTrackingTouch(SeekBar seekBar)  
  170.                 {  
  171.                 }  
  172.             });  
  173.   
  174.             row.addView(minDbTextView);  
  175.             row.addView(bar);  
  176.             row.addView(maxDbTextView);  
  177.   
  178.             mLinearLayout.addView(row);  
  179.         }  
  180.     }  
  181.   
  182.     private void setupVisualizerFxAndUI()  
  183.     {  
  184.         mVisualizerView = new VisualizerView(this);  
  185.         mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(  
  186.                 ViewGroup.LayoutParams.FILL_PARENT,  
  187.                 (int) (VISUALIZER_HEIGHT_DIP * getResources()  
  188.                         .getDisplayMetrics().density)));  
  189.         mLinearLayout.addView(mVisualizerView);  
  190.   
  191.         mInfoView = new TextView(this);  
  192.         String infoStr = "";  
  193.           
  194.         int[] csr = Visualizer.getCaptureSizeRange();  
  195.         if(csr != null)  
  196.         {  
  197.             String csrStr = "CaptureSizeRange: ";  
  198.             for(int i = 0; i < csr.length; i ++)  
  199.             {  
  200.                 csrStr += csr[i];  
  201.                 csrStr +=" ";  
  202.             }  
  203.             infoStr += csrStr;  
  204.         }  
  205.           
  206.         final int maxCR = Visualizer.getMaxCaptureRate();  
  207.           
  208.         infoStr = infoStr + "\nMaxCaptureRate: " + maxCR;  
  209.           
  210.         mInfoView.setText(infoStr);  
  211.         mLinearLayout.addView(mInfoView);  
  212.           
  213.         mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());  
  214.         mVisualizer.setCaptureSize(256);  
  215.         mVisualizer.setDataCaptureListener(  
  216.                 new Visualizer.OnDataCaptureListener()  
  217.                 {  
  218.                     public void onWaveFormDataCapture(Visualizer visualizer,  
  219.                             byte[] bytes, int samplingRate)  
  220.                     {  
  221.                         mVisualizerView.updateVisualizer(bytes);  
  222.                     }  
  223.   
  224.                     public void onFftDataCapture(Visualizer visualizer,  
  225.                             byte[] fft, int samplingRate)  
  226.                     {  
  227.                         mVisualizerView.updateVisualizer(fft);  
  228.                     }  
  229.                 }, maxCR / 2falsetrue);  
  230.     }  
  231.   
  232.     @Override  
  233.     protected void onPause()  
  234.     {  
  235.         super.onPause();  
  236.   
  237.         if (isFinishing() && mMediaPlayer != null)  
  238.         {  
  239.             mVisualizer.release();  
  240.             mEqualizer.release();  
  241.             mMediaPlayer.release();  
  242.             mMediaPlayer = null;  
  243.         }  
  244.     }  
  245.       
  246.     /** 
  247.      * A simple class that draws waveform data received from a 
  248.      * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture } 
  249.      */  
  250.     class VisualizerView extends View  
  251.     {  
  252.         private byte[] mBytes;  
  253.         private float[] mPoints;  
  254.         private Rect mRect = new Rect();  
  255.   
  256.         private Paint mForePaint = new Paint();  
  257.         private int mSpectrumNum = 48;  
  258.         private boolean mFirst = true;  
  259.   
  260.         public VisualizerView(Context context)  
  261.         {  
  262.             super(context);  
  263.             init();  
  264.         }  
  265.   
  266.         private void init()  
  267.         {  
  268.             mBytes = null;  
  269.   
  270.             mForePaint.setStrokeWidth(8f);  
  271.             mForePaint.setAntiAlias(true);  
  272.             mForePaint.setColor(Color.rgb(0128255));  
  273.         }  
  274.   
  275.         public void updateVisualizer(byte[] fft)  
  276.         {  
  277.             if(mFirst )  
  278.             {  
  279.                 mInfoView.setText(mInfoView.getText().toString() + "\nCaptureSize: " + fft.length);  
  280.                 mFirst = false;  
  281.             }  
  282.               
  283.               
  284.             byte[] model = new byte[fft.length / 2 + 1];  
  285.   
  286.             model[0] = (byte) Math.abs(fft[0]);  
  287.             for (int i = 2, j = 1; j < mSpectrumNum;)  
  288.             {  
  289.                 model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);  
  290.                 i += 2;  
  291.                 j++;  
  292.             }  
  293.             mBytes = model;  
  294.             invalidate();  
  295.         }  
  296.   
  297.         @Override  
  298.         protected void onDraw(Canvas canvas)  
  299.         {  
  300.             super.onDraw(canvas);  
  301.   
  302.             if (mBytes == null)  
  303.             {  
  304.                 return;  
  305.             }  
  306.   
  307.             if (mPoints == null || mPoints.length < mBytes.length * 4)  
  308.             {  
  309.                 mPoints = new float[mBytes.length * 4];  
  310.             }  
  311.   
  312.             mRect.set(00, getWidth(), getHeight());  
  313.   
  314.             //绘制波形  
  315.             // for (int i = 0; i < mBytes.length - 1; i++) {  
  316.             // mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);  
  317.             // mPoints[i * 4 + 1] = mRect.height() / 2  
  318.             // + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;  
  319.             // mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);  
  320.             // mPoints[i * 4 + 3] = mRect.height() / 2  
  321.             // + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;  
  322.             // }  
  323.               
  324.             //绘制频谱  
  325.             final int baseX = mRect.width()/mSpectrumNum;  
  326.             final int height = mRect.height();  
  327.   
  328.             for (int i = 0; i < mSpectrumNum ; i++)  
  329.             {  
  330.                 if (mBytes[i] < 0)  
  331.                 {  
  332.                     mBytes[i] = 127;  
  333.                 }  
  334.                   
  335.                 final int xi = baseX*i + baseX/2;  
  336.                   
  337.                 mPoints[i * 4] = xi;  
  338.                 mPoints[i * 4 + 1] = height;  
  339.                   
  340.                 mPoints[i * 4 + 2] = xi;  
  341.                 mPoints[i * 4 + 3] = height - mBytes[i];  
  342.             }  
  343.   
  344.             canvas.drawLines(mPoints, mForePaint);  
  345.         }  
  346.     }  
  347. }  

运行效果如下:

android音乐柱状频谱实现_第1张图片



跟上一篇一样,完全参考自google源码,如果可以自己去看是最好的

否则你就要看我的个人理解了

 

EQ应该就是频率均衡器,适当的调整和控制可以设置重低音,古典,摇滚之类的感觉

主要的类就是android.media.audiofx.Equalizer;
            //many application can control equalizer ,so we need priotiry

//首先初始化这个类,需要两个参数,第一个是优先级,默认是0.所谓优先级就是说当有多个应用同时去控制EQ的时候,就靠优先级来判断了。第二个参数是音乐的sessionId.
            mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
            mEqualizer.setEnabled(true);

//可以得到当前Equalizer 引擎所支持的控制频率的标签数目。

            short bands = mEqualizer.getNumberOfBands();

//可以得到的最小频率(我这是-15dB)
            short minEQLevel = mEqualizer.getBandLevelRange()[0];
//可以得到的最大频率(我这是15dB)

            short maxEQLevel = mEqualizer.getBandLevelRange()[1];


        for (short i = 0; i < bands; i++) {
            final short band = i;

//通过标签可以顺次的获得所有你所支持的频率的名字比如 60Hz 230Hz

            freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000) + " Hz");

            ......

//接下来就是最重要的方法 设置频率的值了,需要提供标签号,和设置的大小data。这个data要记住其最小值是上面得到的minEQLevel,最大值是maxEQLevel.

            mEqualizer.setBandLevel(band, (short) data);

        }

 

以上就可以搞定了。

如果你不知道 自己手上那些频率都代表什么效果 我就顺手转载网上的知识吧

 

均衡器分段后的每个部分的作用:
    1. 20Hz--60Hz部分

    这一段提升能给音乐强有力的感觉,给人很响的感觉,如雷声。是音乐中强劲有力的感觉。如果提升过高,则又会混浊不清,造成清晰度不佳,特别是低频响应差和低频过重的音响设备。

    2. 60Hz--250Hz部分

    这段是音乐的低频结构,它们包含了节奏部分的基础音,包括基音、节奏音的主音。它和高中音的比例构成了音色结构的平衡特性。提升这一段可使声音丰满,过度提升会发出隆隆声。衰减这两段会使声音单薄。

    3. 250Hz--2KHz部分

    这段包含了大多数乐器的低频谐波,如果提升过多会使声音像电话里的声音。如把600Hz和1kHz过度提升会使声音像喇叭的声音。如把3kHz提升过多会掩蔽说话的识别音,即口齿不清,并使唇音“mbv”难以分辨。如把1kHz和3kHz过分提升会使声音具有金属感。由于人耳对这一频段比较敏感,通常不调节这一段,过分提升这一段会使听觉疲劳。

    4. 2KHz--4kHz部分

    这段频率属中频,如果提升得过高会掩盖说话的识别音,尤其是3kHz提升过高,会引起听觉疲劳。

    5. 4kHz--5KHz部分

    这是具有临场感的频段,它影响语言和乐器等声音的清晰度。提升这一频段,使人感觉声源与听者的距离显得稍近了一些;衰减5kHz,就会使声音的距离感变远;如果在5kHz左右提出升6dB,则会使整个混合声音的声功率提升3dB。

    6. 6kHz--16kHz部分

    这一频段控制着音色的明亮度,宏亮度和清晰度。一般来说提升这几段使声音宏亮,但不清晰,不可能会引起齿音过重,衰减时声音变得清晰,但声音不宏亮。


你可能感兴趣的:(android音乐柱状频谱实现)