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
-
SUCCESS
in case of success,ERROR_NO_MEMORY
,ERROR_INVALID_OPERATION
orERROR_DEAD_OBJECT
in case of failure.
Throws
IllegalStateException |
---|
实部和虚部的平方和就是振幅的平方,因为是byte类型,所以最大值是127。
对原文的代码做了一些修改,使更好看一些,代码中用到的歌曲谁要用到,自己重新放一首就行,代码如下:
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.AudioFx;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.media.audiofx.Equalizer;
- import android.media.audiofx.Visualizer;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.WindowManager;
- import android.widget.LinearLayout;
- import android.widget.SeekBar;
- import android.widget.TextView;
- public class AudioFxActivity extends Activity
- {
- private static final String TAG = "AudioFxActivity";
- private static final float VISUALIZER_HEIGHT_DIP = 160f;
- private MediaPlayer mMediaPlayer;
- private Visualizer mVisualizer;
- private Equalizer mEqualizer;
- private LinearLayout mLinearLayout;
- private VisualizerView mVisualizerView;
- private TextView mStatusTextView;
- private TextView mInfoView;
- @Override
- public void onCreate(Bundle icicle)
- {
- super.onCreate(icicle);
- mStatusTextView = new TextView(this);
- mLinearLayout = new LinearLayout(this);
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- mLinearLayout.addView(mStatusTextView);
- setContentView(mLinearLayout);
- // Create the MediaPlayer
- mMediaPlayer = MediaPlayer.create(this, R.raw.my_life);
- Log.d(TAG,
- "MediaPlayer audio session ID: "
- + mMediaPlayer.getAudioSessionId());
- setupVisualizerFxAndUI();
- setupEqualizerFxAndUI();
- // Make sure the visualizer is enabled only when you actually want to
- // receive data, and
- // when it makes sense to receive data.
- mVisualizer.setEnabled(true);
- // When the stream ends, we don't need to collect any more data. We
- // don't do this in
- // setupVisualizerFxAndUI because we likely want to have more,
- // non-Visualizer related code
- // in this callback.
- mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
- {
- public void onCompletion(MediaPlayer mediaPlayer)
- {
- mVisualizer.setEnabled(false);
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- setVolumeControlStream(AudioManager.STREAM_SYSTEM);
- mStatusTextView.setText("音乐播放完毕");
- }
- });
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
- mMediaPlayer.start();
- mStatusTextView.setText("播放音乐中....");
- }
- private void setupEqualizerFxAndUI()
- {
- // Create the Equalizer object (an AudioEffect subclass) and attach it
- // to our media player,
- // with a default priority (0).
- mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
- mEqualizer.setEnabled(true);
- TextView eqTextView = new TextView(this);
- eqTextView.setText("均衡器:");
- mLinearLayout.addView(eqTextView);
- short bands = mEqualizer.getNumberOfBands();
- final short minEQLevel = mEqualizer.getBandLevelRange()[0];
- final short maxEQLevel = mEqualizer.getBandLevelRange()[1];
- for (short i = 0; i < bands; i++)
- {
- final short band = i;
- TextView freqTextView = new TextView(this);
- freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
- freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000)
- + " Hz");
- mLinearLayout.addView(freqTextView);
- LinearLayout row = new LinearLayout(this);
- row.setOrientation(LinearLayout.HORIZONTAL);
- TextView minDbTextView = new TextView(this);
- minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- minDbTextView.setText((minEQLevel / 100) + " dB");
- TextView maxDbTextView = new TextView(this);
- maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- maxDbTextView.setText((maxEQLevel / 100) + " dB");
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- layoutParams.weight = 1;
- SeekBar bar = new SeekBar(this);
- bar.setLayoutParams(layoutParams);
- bar.setMax(maxEQLevel - minEQLevel);
- bar.setProgress(mEqualizer.getBandLevel(band));
- bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
- {
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser)
- {
- mEqualizer.setBandLevel(band, (short) (progress + minEQLevel));
- }
- public void onStartTrackingTouch(SeekBar seekBar)
- {
- }
- public void onStopTrackingTouch(SeekBar seekBar)
- {
- }
- });
- row.addView(minDbTextView);
- row.addView(bar);
- row.addView(maxDbTextView);
- mLinearLayout.addView(row);
- }
- }
- private void setupVisualizerFxAndUI()
- {
- mVisualizerView = new VisualizerView(this);
- mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- (int) (VISUALIZER_HEIGHT_DIP * getResources()
- .getDisplayMetrics().density)));
- mLinearLayout.addView(mVisualizerView);
- mInfoView = new TextView(this);
- String infoStr = "";
- int[] csr = Visualizer.getCaptureSizeRange();
- if(csr != null)
- {
- String csrStr = "CaptureSizeRange: ";
- for(int i = 0; i < csr.length; i ++)
- {
- csrStr += csr[i];
- csrStr +=" ";
- }
- infoStr += csrStr;
- }
- final int maxCR = Visualizer.getMaxCaptureRate();
- infoStr = infoStr + "\nMaxCaptureRate: " + maxCR;
- mInfoView.setText(infoStr);
- mLinearLayout.addView(mInfoView);
- mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
- mVisualizer.setCaptureSize(256);
- mVisualizer.setDataCaptureListener(
- new Visualizer.OnDataCaptureListener()
- {
- public void onWaveFormDataCapture(Visualizer visualizer,
- byte[] bytes, int samplingRate)
- {
- mVisualizerView.updateVisualizer(bytes);
- }
- public void onFftDataCapture(Visualizer visualizer,
- byte[] fft, int samplingRate)
- {
- mVisualizerView.updateVisualizer(fft);
- }
- }, maxCR / 2, false, true);
- }
- @Override
- protected void onPause()
- {
- super.onPause();
- if (isFinishing() && mMediaPlayer != null)
- {
- mVisualizer.release();
- mEqualizer.release();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
- }
- /**
- * A simple class that draws waveform data received from a
- * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
- */
- class VisualizerView extends View
- {
- private byte[] mBytes;
- private float[] mPoints;
- private Rect mRect = new Rect();
- private Paint mForePaint = new Paint();
- private int mSpectrumNum = 48;
- private boolean mFirst = true;
- public VisualizerView(Context context)
- {
- super(context);
- init();
- }
- private void init()
- {
- mBytes = null;
- mForePaint.setStrokeWidth(8f);
- mForePaint.setAntiAlias(true);
- mForePaint.setColor(Color.rgb(0, 128, 255));
- }
- public void updateVisualizer(byte[] fft)
- {
- if(mFirst )
- {
- mInfoView.setText(mInfoView.getText().toString() + "\nCaptureSize: " + fft.length);
- mFirst = false;
- }
- byte[] model = new byte[fft.length / 2 + 1];
- model[0] = (byte) Math.abs(fft[0]);
- for (int i = 2, j = 1; j < mSpectrumNum;)
- {
- model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
- i += 2;
- j++;
- }
- mBytes = model;
- invalidate();
- }
- @Override
- protected void onDraw(Canvas canvas)
- {
- super.onDraw(canvas);
- if (mBytes == null)
- {
- return;
- }
- if (mPoints == null || mPoints.length < mBytes.length * 4)
- {
- mPoints = new float[mBytes.length * 4];
- }
- mRect.set(0, 0, getWidth(), getHeight());
- //绘制波形
- // for (int i = 0; i < mBytes.length - 1; i++) {
- // mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
- // mPoints[i * 4 + 1] = mRect.height() / 2
- // + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
- // mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
- // mPoints[i * 4 + 3] = mRect.height() / 2
- // + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
- // }
- //绘制频谱
- final int baseX = mRect.width()/mSpectrumNum;
- final int height = mRect.height();
- for (int i = 0; i < mSpectrumNum ; i++)
- {
- if (mBytes[i] < 0)
- {
- mBytes[i] = 127;
- }
- final int xi = baseX*i + baseX/2;
- mPoints[i * 4] = xi;
- mPoints[i * 4 + 1] = height;
- mPoints[i * 4 + 2] = xi;
- mPoints[i * 4 + 3] = height - mBytes[i];
- }
- canvas.drawLines(mPoints, mForePaint);
- }
- }
- }
运行效果如下: