android音乐柱状频谱实现

原文地址:http://blog.csdn.net/caryee89/article/details/6935237

 

注意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

实部和虚部的平方和就是振幅的平方,因为是byte类型,所以最大值是127。

 

 

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

 

 

[java] view plaincopy
 
 
  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 / 2, false, true);  
  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(0, 128, 255));  
  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(0, 0, 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. }  


运行效果如下:

 

posted @ 2015-08-20 19:15  brave-sailor  阅读(423)  评论(0编辑  收藏  举报