原文地址:http://blog.csdn.net/caryee89/article/details/6935237
注意android2.3以后才可用,主要用到这个类Visualizer,这个源码其实是apiDemos中一个例子,但例子中实现的是两种中的波形显示,而不是频谱显示,
原文博主实现了另一种频谱显示,并分享出来,精神可嘉。我做了些修改,使稍微好看了些,继续分享。
官方文档解释:
public intgetFft(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 bygetSamplingRate()
. 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 |
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)2010TheAndroidOpenSourceProject
- *
- *LicensedundertheApacheLicense,Version2.0(the"License");
- *youmaynotusethisfileexceptincompliancewiththeLicense.
- *YoumayobtainacopyoftheLicenseat
- *
- *http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
- *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
- *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
- *SeetheLicenseforthespecificlanguagegoverningpermissionsand
- *limitationsundertheLicense.
- */
- packagecom.AudioFx;
- importandroid.app.Activity;
- importandroid.content.Context;
- importandroid.graphics.Canvas;
- importandroid.graphics.Color;
- importandroid.graphics.Paint;
- importandroid.graphics.Rect;
- importandroid.media.AudioManager;
- importandroid.media.MediaPlayer;
- importandroid.media.audiofx.Equalizer;
- importandroid.media.audiofx.Visualizer;
- importandroid.os.Bundle;
- importandroid.util.Log;
- importandroid.view.Gravity;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.view.WindowManager;
- importandroid.widget.LinearLayout;
- importandroid.widget.SeekBar;
- importandroid.widget.TextView;
- publicclassAudioFxActivityextendsActivity
- {
- privatestaticfinalStringTAG="AudioFxActivity";
- privatestaticfinalfloatVISUALIZER_HEIGHT_DIP=160f;
- privateMediaPlayermMediaPlayer;
- privateVisualizermVisualizer;
- privateEqualizermEqualizer;
- privateLinearLayoutmLinearLayout;
- privateVisualizerViewmVisualizerView;
- privateTextViewmStatusTextView;
- privateTextViewmInfoView;
- @Override
- publicvoidonCreate(Bundleicicle)
- {
- super.onCreate(icicle);
- mStatusTextView=newTextView(this);
- mLinearLayout=newLinearLayout(this);
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- mLinearLayout.addView(mStatusTextView);
- setContentView(mLinearLayout);
- //CreatetheMediaPlayer
- mMediaPlayer=MediaPlayer.create(this,R.raw.my_life);
- Log.d(TAG,
- "MediaPlayeraudiosessionID:"
- +mMediaPlayer.getAudioSessionId());
- setupVisualizerFxAndUI();
- setupEqualizerFxAndUI();
- //Makesurethevisualizerisenabledonlywhenyouactuallywantto
- //receivedata,and
- //whenitmakessensetoreceivedata.
- mVisualizer.setEnabled(true);
- //Whenthestreamends,wedon'tneedtocollectanymoredata.We
- //don'tdothisin
- //setupVisualizerFxAndUIbecausewelikelywanttohavemore,
- //non-Visualizerrelatedcode
- //inthiscallback.
- mMediaPlayer.setOnCompletionListener(newMediaPlayer.OnCompletionListener()
- {
- publicvoidonCompletion(MediaPlayermediaPlayer)
- {
- 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("播放音乐中....");
- }
- privatevoidsetupEqualizerFxAndUI()
- {
- //CreatetheEqualizerobject(anAudioEffectsubclass)andattachit
- //toourmediaplayer,
- //withadefaultpriority(0).
- mEqualizer=newEqualizer(0,mMediaPlayer.getAudioSessionId());
- mEqualizer.setEnabled(true);
- TextVieweqTextView=newTextView(this);
- eqTextView.setText("均衡器:");
- mLinearLayout.addView(eqTextView);
- shortbands=mEqualizer.getNumberOfBands();
- finalshortminEQLevel=mEqualizer.getBandLevelRange()[0];
- finalshortmaxEQLevel=mEqualizer.getBandLevelRange()[1];
- for(shorti=0;i<bands;i++)
- {
- finalshortband=i;
- TextViewfreqTextView=newTextView(this);
- freqTextView.setLayoutParams(newViewGroup.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
- freqTextView.setText((mEqualizer.getCenterFreq(band)/1000)
- +"Hz");
- mLinearLayout.addView(freqTextView);
- LinearLayoutrow=newLinearLayout(this);
- row.setOrientation(LinearLayout.HORIZONTAL);
- TextViewminDbTextView=newTextView(this);
- minDbTextView.setLayoutParams(newViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- minDbTextView.setText((minEQLevel/100)+"dB");
- TextViewmaxDbTextView=newTextView(this);
- maxDbTextView.setLayoutParams(newViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- maxDbTextView.setText((maxEQLevel/100)+"dB");
- LinearLayout.LayoutParamslayoutParams=newLinearLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- layoutParams.weight=1;
- SeekBarbar=newSeekBar(this);
- bar.setLayoutParams(layoutParams);
- bar.setMax(maxEQLevel-minEQLevel);
- bar.setProgress(mEqualizer.getBandLevel(band));
- bar.setOnSeekBarChangeListener(newSeekBar.OnSeekBarChangeListener()
- {
- publicvoidonProgressChanged(SeekBarseekBar,intprogress,
- booleanfromUser)
- {
- mEqualizer.setBandLevel(band,(short)(progress+minEQLevel));
- }
- publicvoidonStartTrackingTouch(SeekBarseekBar)
- {
- }
- publicvoidonStopTrackingTouch(SeekBarseekBar)
- {
- }
- });
- row.addView(minDbTextView);
- row.addView(bar);
- row.addView(maxDbTextView);
- mLinearLayout.addView(row);
- }
- }
- privatevoidsetupVisualizerFxAndUI()
- {
- mVisualizerView=newVisualizerView(this);
- mVisualizerView.setLayoutParams(newViewGroup.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- (int)(VISUALIZER_HEIGHT_DIP*getResources()
- .getDisplayMetrics().density)));
- mLinearLayout.addView(mVisualizerView);
- mInfoView=newTextView(this);
- StringinfoStr="";
- int[]csr=Visualizer.getCaptureSizeRange();
- if(csr!=null)
- {
- StringcsrStr="CaptureSizeRange:";
- for(inti=0;i<csr.length;i++)
- {
- csrStr+=csr[i];
- csrStr+="";
- }
- infoStr+=csrStr;
- }
- finalintmaxCR=Visualizer.getMaxCaptureRate();
- infoStr=infoStr+" MaxCaptureRate:"+maxCR;
- mInfoView.setText(infoStr);
- mLinearLayout.addView(mInfoView);
- mVisualizer=newVisualizer(mMediaPlayer.getAudioSessionId());
- mVisualizer.setCaptureSize(256);
- mVisualizer.setDataCaptureListener(
- newVisualizer.OnDataCaptureListener()
- {
- publicvoidonWaveFormDataCapture(Visualizervisualizer,
- byte[]bytes,intsamplingRate)
- {
- mVisualizerView.updateVisualizer(bytes);
- }
- publicvoidonFftDataCapture(Visualizervisualizer,
- byte[]fft,intsamplingRate)
- {
- mVisualizerView.updateVisualizer(fft);
- }
- },maxCR/2,false,true);
- }
- @Override
- protectedvoidonPause()
- {
- super.onPause();
- if(isFinishing()&&mMediaPlayer!=null)
- {
- mVisualizer.release();
- mEqualizer.release();
- mMediaPlayer.release();
- mMediaPlayer=null;
- }
- }
- /**
- *Asimpleclassthatdrawswaveformdatareceivedfroma
- *{@linkVisualizer.OnDataCaptureListener#onWaveFormDataCapture}
- */
- classVisualizerViewextendsView
- {
- privatebyte[]mBytes;
- privatefloat[]mPoints;
- privateRectmRect=newRect();
- privatePaintmForePaint=newPaint();
- privateintmSpectrumNum=48;
- privatebooleanmFirst=true;
- publicVisualizerView(Contextcontext)
- {
- super(context);
- init();
- }
- privatevoidinit()
- {
- mBytes=null;
- mForePaint.setStrokeWidth(8f);
- mForePaint.setAntiAlias(true);
- mForePaint.setColor(Color.rgb(0,128,255));
- }
- publicvoidupdateVisualizer(byte[]fft)
- {
- if(mFirst)
- {
- mInfoView.setText(mInfoView.getText().toString()+" CaptureSize:"+fft.length);
- mFirst=false;
- }
- byte[]model=newbyte[fft.length/2+1];
- model[0]=(byte)Math.abs(fft[0]);
- for(inti=2,j=1;j<mSpectrumNum;)
- {
- model[j]=(byte)Math.hypot(fft[i],fft[i+1]);
- i+=2;
- j++;
- }
- mBytes=model;
- invalidate();
- }
- @Override
- protectedvoidonDraw(Canvascanvas)
- {
- super.onDraw(canvas);
- if(mBytes==null)
- {
- return;
- }
- if(mPoints==null||mPoints.length<mBytes.length*4)
- {
- mPoints=newfloat[mBytes.length*4];
- }
- mRect.set(0,0,getWidth(),getHeight());
- //绘制波形
- //for(inti=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;
- //}
- //绘制频谱
- finalintbaseX=mRect.width()/mSpectrumNum;
- finalintheight=mRect.height();
- for(inti=0;i<mSpectrumNum;i++)
- {
- if(mBytes[i]<0)
- {
- mBytes[i]=127;
- }
- finalintxi=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);
- }
- }
- }
运行效果如下: