码迷,mamicode.com
首页 > 移动开发 > 详细

android音乐柱状频谱实现

时间:2015-05-18 06:19:02      阅读:499      评论:0      收藏:0      [点我收藏+]

标签:

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. { 
  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. } 


运行效果如下:

 

技术分享

android音乐柱状频谱实现

标签:

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

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!