android音乐柱状频谱实现

from: http://blog.csdn.net/topgun38/article/details/7663849

 

 

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

 

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

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

 

官方文档解释:

 

public int getFft (byte[] fft)

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


运行效果如下:

 

原文地址:https://www.cnblogs.com/Free-Thinker/p/4510973.html