android音乐柱状频谱实现

摘要:
我做了些修改,使稍微好看了些,继续分享。

原文地址: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

Parameters
fftarray of bytes where the FFT should be returned
Returns

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

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

  1. /*
  2. *Copyright(C)2010TheAndroidOpenSourceProject
  3. *
  4. *LicensedundertheApacheLicense,Version2.0(the"License");
  5. *youmaynotusethisfileexceptincompliancewiththeLicense.
  6. *YoumayobtainacopyoftheLicenseat
  7. *
  8. *http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  11. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,
  12. *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
  13. *SeetheLicenseforthespecificlanguagegoverningpermissionsand
  14. *limitationsundertheLicense.
  15. */
  16. packagecom.AudioFx;
  17. importandroid.app.Activity;
  18. importandroid.content.Context;
  19. importandroid.graphics.Canvas;
  20. importandroid.graphics.Color;
  21. importandroid.graphics.Paint;
  22. importandroid.graphics.Rect;
  23. importandroid.media.AudioManager;
  24. importandroid.media.MediaPlayer;
  25. importandroid.media.audiofx.Equalizer;
  26. importandroid.media.audiofx.Visualizer;
  27. importandroid.os.Bundle;
  28. importandroid.util.Log;
  29. importandroid.view.Gravity;
  30. importandroid.view.View;
  31. importandroid.view.ViewGroup;
  32. importandroid.view.WindowManager;
  33. importandroid.widget.LinearLayout;
  34. importandroid.widget.SeekBar;
  35. importandroid.widget.TextView;
  36. publicclassAudioFxActivityextendsActivity
  37. {
  38. privatestaticfinalStringTAG="AudioFxActivity";
  39. privatestaticfinalfloatVISUALIZER_HEIGHT_DIP=160f;
  40. privateMediaPlayermMediaPlayer;
  41. privateVisualizermVisualizer;
  42. privateEqualizermEqualizer;
  43. privateLinearLayoutmLinearLayout;
  44. privateVisualizerViewmVisualizerView;
  45. privateTextViewmStatusTextView;
  46. privateTextViewmInfoView;
  47. @Override
  48. publicvoidonCreate(Bundleicicle)
  49. {
  50. super.onCreate(icicle);
  51. mStatusTextView=newTextView(this);
  52. mLinearLayout=newLinearLayout(this);
  53. mLinearLayout.setOrientation(LinearLayout.VERTICAL);
  54. mLinearLayout.addView(mStatusTextView);
  55. setContentView(mLinearLayout);
  56. //CreatetheMediaPlayer
  57. mMediaPlayer=MediaPlayer.create(this,R.raw.my_life);
  58. Log.d(TAG,
  59. "MediaPlayeraudiosessionID:"
  60. +mMediaPlayer.getAudioSessionId());
  61. setupVisualizerFxAndUI();
  62. setupEqualizerFxAndUI();
  63. //Makesurethevisualizerisenabledonlywhenyouactuallywantto
  64. //receivedata,and
  65. //whenitmakessensetoreceivedata.
  66. mVisualizer.setEnabled(true);
  67. //Whenthestreamends,wedon'tneedtocollectanymoredata.We
  68. //don'tdothisin
  69. //setupVisualizerFxAndUIbecausewelikelywanttohavemore,
  70. //non-Visualizerrelatedcode
  71. //inthiscallback.
  72. mMediaPlayer.setOnCompletionListener(newMediaPlayer.OnCompletionListener()
  73. {
  74. publicvoidonCompletion(MediaPlayermediaPlayer)
  75. {
  76. mVisualizer.setEnabled(false);
  77. getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  78. setVolumeControlStream(AudioManager.STREAM_SYSTEM);
  79. mStatusTextView.setText("音乐播放完毕");
  80. }
  81. });
  82. getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  83. setVolumeControlStream(AudioManager.STREAM_MUSIC);
  84. mMediaPlayer.start();
  85. mStatusTextView.setText("播放音乐中....");
  86. }
  87. privatevoidsetupEqualizerFxAndUI()
  88. {
  89. //CreatetheEqualizerobject(anAudioEffectsubclass)andattachit
  90. //toourmediaplayer,
  91. //withadefaultpriority(0).
  92. mEqualizer=newEqualizer(0,mMediaPlayer.getAudioSessionId());
  93. mEqualizer.setEnabled(true);
  94. TextVieweqTextView=newTextView(this);
  95. eqTextView.setText("均衡器:");
  96. mLinearLayout.addView(eqTextView);
  97. shortbands=mEqualizer.getNumberOfBands();
  98. finalshortminEQLevel=mEqualizer.getBandLevelRange()[0];
  99. finalshortmaxEQLevel=mEqualizer.getBandLevelRange()[1];
  100. for(shorti=0;i<bands;i++)
  101. {
  102. finalshortband=i;
  103. TextViewfreqTextView=newTextView(this);
  104. freqTextView.setLayoutParams(newViewGroup.LayoutParams(
  105. ViewGroup.LayoutParams.FILL_PARENT,
  106. ViewGroup.LayoutParams.WRAP_CONTENT));
  107. freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
  108. freqTextView.setText((mEqualizer.getCenterFreq(band)/1000)
  109. +"Hz");
  110. mLinearLayout.addView(freqTextView);
  111. LinearLayoutrow=newLinearLayout(this);
  112. row.setOrientation(LinearLayout.HORIZONTAL);
  113. TextViewminDbTextView=newTextView(this);
  114. minDbTextView.setLayoutParams(newViewGroup.LayoutParams(
  115. ViewGroup.LayoutParams.WRAP_CONTENT,
  116. ViewGroup.LayoutParams.WRAP_CONTENT));
  117. minDbTextView.setText((minEQLevel/100)+"dB");
  118. TextViewmaxDbTextView=newTextView(this);
  119. maxDbTextView.setLayoutParams(newViewGroup.LayoutParams(
  120. ViewGroup.LayoutParams.WRAP_CONTENT,
  121. ViewGroup.LayoutParams.WRAP_CONTENT));
  122. maxDbTextView.setText((maxEQLevel/100)+"dB");
  123. LinearLayout.LayoutParamslayoutParams=newLinearLayout.LayoutParams(
  124. ViewGroup.LayoutParams.FILL_PARENT,
  125. ViewGroup.LayoutParams.WRAP_CONTENT);
  126. layoutParams.weight=1;
  127. SeekBarbar=newSeekBar(this);
  128. bar.setLayoutParams(layoutParams);
  129. bar.setMax(maxEQLevel-minEQLevel);
  130. bar.setProgress(mEqualizer.getBandLevel(band));
  131. bar.setOnSeekBarChangeListener(newSeekBar.OnSeekBarChangeListener()
  132. {
  133. publicvoidonProgressChanged(SeekBarseekBar,intprogress,
  134. booleanfromUser)
  135. {
  136. mEqualizer.setBandLevel(band,(short)(progress+minEQLevel));
  137. }
  138. publicvoidonStartTrackingTouch(SeekBarseekBar)
  139. {
  140. }
  141. publicvoidonStopTrackingTouch(SeekBarseekBar)
  142. {
  143. }
  144. });
  145. row.addView(minDbTextView);
  146. row.addView(bar);
  147. row.addView(maxDbTextView);
  148. mLinearLayout.addView(row);
  149. }
  150. }
  151. privatevoidsetupVisualizerFxAndUI()
  152. {
  153. mVisualizerView=newVisualizerView(this);
  154. mVisualizerView.setLayoutParams(newViewGroup.LayoutParams(
  155. ViewGroup.LayoutParams.FILL_PARENT,
  156. (int)(VISUALIZER_HEIGHT_DIP*getResources()
  157. .getDisplayMetrics().density)));
  158. mLinearLayout.addView(mVisualizerView);
  159. mInfoView=newTextView(this);
  160. StringinfoStr="";
  161. int[]csr=Visualizer.getCaptureSizeRange();
  162. if(csr!=null)
  163. {
  164. StringcsrStr="CaptureSizeRange:";
  165. for(inti=0;i<csr.length;i++)
  166. {
  167. csrStr+=csr[i];
  168. csrStr+="";
  169. }
  170. infoStr+=csrStr;
  171. }
  172. finalintmaxCR=Visualizer.getMaxCaptureRate();
  173. infoStr=infoStr+" MaxCaptureRate:"+maxCR;
  174. mInfoView.setText(infoStr);
  175. mLinearLayout.addView(mInfoView);
  176. mVisualizer=newVisualizer(mMediaPlayer.getAudioSessionId());
  177. mVisualizer.setCaptureSize(256);
  178. mVisualizer.setDataCaptureListener(
  179. newVisualizer.OnDataCaptureListener()
  180. {
  181. publicvoidonWaveFormDataCapture(Visualizervisualizer,
  182. byte[]bytes,intsamplingRate)
  183. {
  184. mVisualizerView.updateVisualizer(bytes);
  185. }
  186. publicvoidonFftDataCapture(Visualizervisualizer,
  187. byte[]fft,intsamplingRate)
  188. {
  189. mVisualizerView.updateVisualizer(fft);
  190. }
  191. },maxCR/2,false,true);
  192. }
  193. @Override
  194. protectedvoidonPause()
  195. {
  196. super.onPause();
  197. if(isFinishing()&&mMediaPlayer!=null)
  198. {
  199. mVisualizer.release();
  200. mEqualizer.release();
  201. mMediaPlayer.release();
  202. mMediaPlayer=null;
  203. }
  204. }
  205. /**
  206. *Asimpleclassthatdrawswaveformdatareceivedfroma
  207. *{@linkVisualizer.OnDataCaptureListener#onWaveFormDataCapture}
  208. */
  209. classVisualizerViewextendsView
  210. {
  211. privatebyte[]mBytes;
  212. privatefloat[]mPoints;
  213. privateRectmRect=newRect();
  214. privatePaintmForePaint=newPaint();
  215. privateintmSpectrumNum=48;
  216. privatebooleanmFirst=true;
  217. publicVisualizerView(Contextcontext)
  218. {
  219. super(context);
  220. init();
  221. }
  222. privatevoidinit()
  223. {
  224. mBytes=null;
  225. mForePaint.setStrokeWidth(8f);
  226. mForePaint.setAntiAlias(true);
  227. mForePaint.setColor(Color.rgb(0,128,255));
  228. }
  229. publicvoidupdateVisualizer(byte[]fft)
  230. {
  231. if(mFirst)
  232. {
  233. mInfoView.setText(mInfoView.getText().toString()+" CaptureSize:"+fft.length);
  234. mFirst=false;
  235. }
  236. byte[]model=newbyte[fft.length/2+1];
  237. model[0]=(byte)Math.abs(fft[0]);
  238. for(inti=2,j=1;j<mSpectrumNum;)
  239. {
  240. model[j]=(byte)Math.hypot(fft[i],fft[i+1]);
  241. i+=2;
  242. j++;
  243. }
  244. mBytes=model;
  245. invalidate();
  246. }
  247. @Override
  248. protectedvoidonDraw(Canvascanvas)
  249. {
  250. super.onDraw(canvas);
  251. if(mBytes==null)
  252. {
  253. return;
  254. }
  255. if(mPoints==null||mPoints.length<mBytes.length*4)
  256. {
  257. mPoints=newfloat[mBytes.length*4];
  258. }
  259. mRect.set(0,0,getWidth(),getHeight());
  260. //绘制波形
  261. //for(inti=0;i<mBytes.length-1;i++){
  262. //mPoints[i*4]=mRect.width()*i/(mBytes.length-1);
  263. //mPoints[i*4+1]=mRect.height()/2
  264. //+((byte)(mBytes[i]+128))*(mRect.height()/2)/128;
  265. //mPoints[i*4+2]=mRect.width()*(i+1)/(mBytes.length-1);
  266. //mPoints[i*4+3]=mRect.height()/2
  267. //+((byte)(mBytes[i+1]+128))*(mRect.height()/2)/128;
  268. //}
  269. //绘制频谱
  270. finalintbaseX=mRect.width()/mSpectrumNum;
  271. finalintheight=mRect.height();
  272. for(inti=0;i<mSpectrumNum;i++)
  273. {
  274. if(mBytes[i]<0)
  275. {
  276. mBytes[i]=127;
  277. }
  278. finalintxi=baseX*i+baseX/2;
  279. mPoints[i*4]=xi;
  280. mPoints[i*4+1]=height;
  281. mPoints[i*4+2]=xi;
  282. mPoints[i*4+3]=height-mBytes[i];
  283. }
  284. canvas.drawLines(mPoints,mForePaint);
  285. }
  286. }
  287. }

运行效果如下:

android音乐柱状频谱实现第1张

免责声明:文章转载自《android音乐柱状频谱实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇tcgetattr函数与tcsetattr函数控制终端如何优雅的屏蔽GCC编译器告警下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

FFT题集

FFT学习参考这两篇博客,很详细,结合这看,互补。 博客一 博客二 很大一部分题目需要构造多项式相乘来进行计数问题。 1.HDU 1402 A * B Problem Plus把A和B分别当作多项式的系数。 #include <cstdio>#include <algorithm>#include <cmath>#in...

多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/例题与常用套路【入门】 前置技能 对复数以及复平面有一定的了解 对数论要求了解:逆元,原根,中国剩余定理 对分治有充足的认识 对多项式有一定的认识,并会写...

[转载]功率谱

原文地址:功率谱作者:wangjiufa1987 求信号功率谱时候用下面的不同方法,功率谱密度的幅值大小相差很大!我的问题是,计算具体信号时,到底应该以什么准则决定该选用什么方法啊?功率谱密度的幅植的具体意义是什么??下面是一些不同方法计算同一信号的matlab程序!欢迎大家给点建议! 直接法:直接法又称周期图法,它是把随机序列x(n)的N个观...

HDU1402 FFT高精度乘法模板题

#include<bits/stdc++.h> using namespace std; const int N = 50005*4; const double PI = acos(-1); typedef complex <double> cp; char sa[N], sb[N]; int n = 1, lena, lenb,...

Matlab图像处理系列4———傅立叶变换和反变换的图像

注意:这一系列实验的图像处理程序,使用Matlab实现最重要的图像处理算法 1.Fourier兑换 (1)频域增强 除了在空间域内能够加工处理图像以外,我们还能够将图像变换到其它空间后进行处理。这些方法称为变换域方法,最常见的变换域是频域。 使用Fourier变换把图像从空间域变换到频域。在频域内做对应增强处理,再从频域变换到空间域得到处理后的图像。...

STM32使用FFT变换计算THD(20年四川省电子设计大赛E题软件部分)

注: 本篇内容意在使不理解FFT变换的读者也可以通过使用FFT来计算总谐波失真 FFT变换 根据总谐波失真的定义: [THD = frac{sqrt{sum_{n=0}^{infty}{G_{n}^{2}}}}{G_0} (G_0为基波,G_n 为高次谐波) ] 可知,要计算THD需要知道基波分量和各个谐波分量的大小。 ​ FFT也叫快速傅里叶变换,是离散...