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. package com.AudioFx;
  17. import android.app.Activity;
  18. import android.content.Context;
  19. import android.graphics.Canvas;
  20. import android.graphics.Color;
  21. import android.graphics.Paint;
  22. import android.graphics.Rect;
  23. import android.media.AudioManager;
  24. import android.media.MediaPlayer;
  25. import android.media.audiofx.Equalizer;
  26. import android.media.audiofx.Visualizer;
  27. import android.os.Bundle;
  28. import android.util.Log;
  29. import android.view.Gravity;
  30. import android.view.View;
  31. import android.view.ViewGroup;
  32. import android.view.WindowManager;
  33. import android.widget.LinearLayout;
  34. import android.widget.SeekBar;
  35. import android.widget.TextView;
  36. public class AudioFxActivity extends Activity
  37. {
  38. private static final String TAG = "AudioFxActivity";
  39. private static final float VISUALIZER_HEIGHT_DIP = 160f;
  40. private MediaPlayer mMediaPlayer;
  41. private Visualizer mVisualizer;
  42. private Equalizer mEqualizer;
  43. private LinearLayout mLinearLayout;
  44. private VisualizerView mVisualizerView;
  45. private TextView mStatusTextView;
  46. private TextView mInfoView;
  47. @Override
  48. public void onCreate(Bundle icicle)
  49. {
  50. super.onCreate(icicle);
  51. mStatusTextView = new TextView(this);
  52. mLinearLayout = new LinearLayout(this);
  53. mLinearLayout.setOrientation(LinearLayout.VERTICAL);
  54. mLinearLayout.addView(mStatusTextView);
  55. setContentView(mLinearLayout);
  56. // Create the MediaPlayer
  57. mMediaPlayer = MediaPlayer.create(this, R.raw.my_life);
  58. Log.d(TAG,
  59. "MediaPlayer audio session ID: "
  60. + mMediaPlayer.getAudioSessionId());
  61. setupVisualizerFxAndUI();
  62. setupEqualizerFxAndUI();
  63. // Make sure the visualizer is enabled only when you actually want to
  64. // receive data, and
  65. // when it makes sense to receive data.
  66. mVisualizer.setEnabled(true);
  67. // When the stream ends, we don't need to collect any more data. We
  68. // don't do this in
  69. // setupVisualizerFxAndUI because we likely want to have more,
  70. // non-Visualizer related code
  71. // in this callback.
  72. mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
  73. {
  74. public void onCompletion(MediaPlayer mediaPlayer)
  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. private void setupEqualizerFxAndUI()
  88. {
  89. // Create the Equalizer object (an AudioEffect subclass) and attach it
  90. // to our media player,
  91. // with a default priority (0).
  92. mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
  93. mEqualizer.setEnabled(true);
  94. TextView eqTextView = new TextView(this);
  95. eqTextView.setText("均衡器:");
  96. mLinearLayout.addView(eqTextView);
  97. short bands = mEqualizer.getNumberOfBands();
  98. final short minEQLevel = mEqualizer.getBandLevelRange()[0];
  99. final short maxEQLevel = mEqualizer.getBandLevelRange()[1];
  100. for (short i = 0; i < bands; i++)
  101. {
  102. final short band = i;
  103. TextView freqTextView = new TextView(this);
  104. freqTextView.setLayoutParams(new ViewGroup.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. LinearLayout row = new LinearLayout(this);
  112. row.setOrientation(LinearLayout.HORIZONTAL);
  113. TextView minDbTextView = new TextView(this);
  114. minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
  115. ViewGroup.LayoutParams.WRAP_CONTENT,
  116. ViewGroup.LayoutParams.WRAP_CONTENT));
  117. minDbTextView.setText((minEQLevel / 100) + " dB");
  118. TextView maxDbTextView = new TextView(this);
  119. maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
  120. ViewGroup.LayoutParams.WRAP_CONTENT,
  121. ViewGroup.LayoutParams.WRAP_CONTENT));
  122. maxDbTextView.setText((maxEQLevel / 100) + " dB");
  123. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
  124. ViewGroup.LayoutParams.FILL_PARENT,
  125. ViewGroup.LayoutParams.WRAP_CONTENT);
  126. layoutParams.weight = 1;
  127. SeekBar bar = new SeekBar(this);
  128. bar.setLayoutParams(layoutParams);
  129. bar.setMax(maxEQLevel - minEQLevel);
  130. bar.setProgress(mEqualizer.getBandLevel(band));
  131. bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
  132. {
  133. public void onProgressChanged(SeekBar seekBar, int progress,
  134. boolean fromUser)
  135. {
  136. mEqualizer.setBandLevel(band, (short) (progress + minEQLevel));
  137. }
  138. public void onStartTrackingTouch(SeekBar seekBar)
  139. {
  140. }
  141. public void onStopTrackingTouch(SeekBar seekBar)
  142. {
  143. }
  144. });
  145. row.addView(minDbTextView);
  146. row.addView(bar);
  147. row.addView(maxDbTextView);
  148. mLinearLayout.addView(row);
  149. }
  150. }
  151. private void setupVisualizerFxAndUI()
  152. {
  153. mVisualizerView = new VisualizerView(this);
  154. mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
  155. ViewGroup.LayoutParams.FILL_PARENT,
  156. (int) (VISUALIZER_HEIGHT_DIP * getResources()
  157. .getDisplayMetrics().density)));
  158. mLinearLayout.addView(mVisualizerView);
  159. mInfoView = new TextView(this);
  160. String infoStr = "";
  161. int[] csr = Visualizer.getCaptureSizeRange();
  162. if(csr != null)
  163. {
  164. String csrStr = "CaptureSizeRange: ";
  165. for(int i = 0; i < csr.length; i ++)
  166. {
  167. csrStr += csr[i];
  168. csrStr +=" ";
  169. }
  170. infoStr += csrStr;
  171. }
  172. final int maxCR = Visualizer.getMaxCaptureRate();
  173. infoStr = infoStr + "\nMaxCaptureRate: " + maxCR;
  174. mInfoView.setText(infoStr);
  175. mLinearLayout.addView(mInfoView);
  176. mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
  177. mVisualizer.setCaptureSize(256);
  178. mVisualizer.setDataCaptureListener(
  179. new Visualizer.OnDataCaptureListener()
  180. {
  181. public void onWaveFormDataCapture(Visualizer visualizer,
  182. byte[] bytes, int samplingRate)
  183. {
  184. mVisualizerView.updateVisualizer(bytes);
  185. }
  186. public void onFftDataCapture(Visualizer visualizer,
  187. byte[] fft, int samplingRate)
  188. {
  189. mVisualizerView.updateVisualizer(fft);
  190. }
  191. }, maxCR / 2, false, true);
  192. }
  193. @Override
  194. protected void onPause()
  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. * A simple class that draws waveform data received from a
  207. * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
  208. */
  209. class VisualizerView extends View
  210. {
  211. private byte[] mBytes;
  212. private float[] mPoints;
  213. private Rect mRect = new Rect();
  214. private Paint mForePaint = new Paint();
  215. private int mSpectrumNum = 48;
  216. private boolean mFirst = true;
  217. public VisualizerView(Context context)
  218. {
  219. super(context);
  220. init();
  221. }
  222. private void init()
  223. {
  224. mBytes = null;
  225. mForePaint.setStrokeWidth(8f);
  226. mForePaint.setAntiAlias(true);
  227. mForePaint.setColor(Color.rgb(0, 128, 255));
  228. }
  229. public void updateVisualizer(byte[] fft)
  230. {
  231. if(mFirst )
  232. {
  233. mInfoView.setText(mInfoView.getText().toString() + "\nCaptureSize: " + fft.length);
  234. mFirst = false;
  235. }
  236. byte[] model = new byte[fft.length / 2 + 1];
  237. model[0] = (byte) Math.abs(fft[0]);
  238. for (int i = 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. protected void onDraw(Canvas canvas)
  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 = new float[mBytes.length * 4];
  258. }
  259. mRect.set(0, 0, getWidth(), getHeight());
  260. //绘制波形
  261. // for (int i = 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. final int baseX = mRect.width()/mSpectrumNum;
  271. final int height = mRect.height();
  272. for (int i = 0; i < mSpectrumNum ; i++)
  273. {
  274. if (mBytes[i] < 0)
  275. {
  276. mBytes[i] = 127;
  277. }
  278. final int xi = 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 自定义View - 柱状波形图 wave view

    前言 柱状波形图是一种常见的图形.一个个柱子按顺序排列,构成一个波形图. 柱子的高度由输入数据决定.如果输入的是音频的音量,则可得到一个声波图. 在一些音频软件中,我们也可以左右拖动声波,来改变音频的 ...

  2. Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)

    一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 源码下载:http://code.66 ...

  3. 一款非常简单的android音乐播放器源码分享给大家

    一款非常简单的android音乐播放器源码分享给大家,该应用虽然很小,大家常用的播放器功能基本实现了,可能有点还不够完善,大家也可以自己完善一下,源码在源码天堂那里已经有了,大家可以到那里下载学习吧. ...

  4. Android无限级树状结构

    通过对ListView简单的扩展.再封装,即可实现无限层级的树控件TreeView. package cn.asiontang.nleveltreelistview; import android.a ...

  5. 用canvas 绘制的饼状统计图、柱状统计图、折线统计图

    canvas 绘制的饼状统计图 canvas 绘制的柱状统计图 canvas 绘制的折线统计图

  6. android音乐播放器开发教程

    android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...

  7. iOS 使用Charts框架 折线,柱状,K线,饼状,雷达全攻略

    我是前言: 大约几个月前我在某平台写了一篇文章, 文中简单地介绍了Charts两种图表的样式的使用, 不过有种意犹未尽的感觉, 利用周末的空闲时间再次看了看, 有了新的收获, 今天发出来,分享给大家, ...

  8. 用Jfree实现条形柱状图表,java代码实现

    用Jfree实现条形柱状图表,java代码实现.可经经常使用于报表的制作,代码自己主动生成后能够自由查看.能够自由配置图表的各个属性,用来达到自己的要求和目的 package test1; impor ...

  9. 用echartsjs 实现动态绘制折线、柱状等图形,并实现多图联动效果

    echarts对于大数据处理后绘制折线图,柱形图等等的效果和速度都很好.下面我们介绍 怎么把封装的数据列表解析出来,动态绘图,并且实现鼠标联动效果引入js文件: <script type=&qu ...

随机推荐

  1. java 汉字转拼音

    先决条件: pinyin4j.jar(Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的转换.拼音输出格式可以定制.) 下载地址:http://pan.baidu.com/share/l ...

  2. XML读写文件辅助类

    /// <summary> /// 历史下载记录xml文件操作 /// </summary> public class XMLHelper { private string x ...

  3. Hibernate学习之缓存机制

    转自:http://www.cnblogs.com/xiaoluo501395377/p/3377604.html 一.N+1问题 首先我们来探讨一下N+1的问题,我们先通过一个例子来看一下,什么是N ...

  4. Cloudera Manager Service Monitor 定期挂掉问题排查

    显示:查询 Service Monitor 时发生内部错误(Error sending messages to firehose: mgmt-SERVICEMONITOR-) 1.初步排查出是smon ...

  5. @Transactional失效的问题

    spring事物配置一般没有问题, 优先检查mysql的引擎是否是innodb, 是的话检查包的扫描是否有问题. 我就是因为包的扫描导致@Transactional失效. 具体情况如下, 在sprin ...

  6. 关于Python的self指向性

    Python的self是指向类的实例化对像,而不是类本身,每次调用类的实例化即self指向此实例化对像,如下代码: class Person: def __init__(self,name): sel ...

  7. cocos2d-x Android环境搭建

    1.Java虚拟机.分32位和64位.64位: jdk-8u11-windows-x64-8.0.11.12.1406275777 环境变量配置,我的电脑右击->属性->高级系统设置-&g ...

  8. 射频识别技术漫谈(16)——Mifare UltraLight

    Mifare UltraLight又称为MF0,从UltraLight(超轻的)这个名字就可以看出来,它是一个低成本.小容量的卡片.低成本,是指它是目前市场中价格最低的遵守ISO14443A协议的芯片 ...

  9. MSSQL SERVER 2008 R2 无法连接到数据库,用户sa登录失败,错误:18456

    原因:勾选了强制实施密码策略,但是设置的密码很简单依然可以,比如:123456 这是为什么?原来,这个功能要用到NetValidatePasswordPolicy() API这个函数. (该功能只有在 ...

  10. android天气查询(一)websevice之ksoap2软件包的使用

    对于用到天气信息,首先我想: 第一:数据不可能是我测得的,必须是网上的信息. 第二:网上的信息分为好多种,具体哪种比较好一点,这里我总结了两种. 第三:数据JSON怎么解析. 第四:如何提出数据与显示 ...