android获取和展示音乐的频谱
做了个音乐播放器 就一直想做个加一个音乐频谱的展示界面
觉的这是一个好玩的东西,可以将耳边动听的声音形象化,仿佛眼前可以看到声音一样。
但是我在文档的开发者指南里没有讲任何有关音乐频谱的东西,最后还是在google的源码示例中找到了。
你可以直接去参看源代码更原滋原味 以下只是个人对着源码的重构和理解
所有以下所讲的功能,均需要在2.3以上的sdk中才能实现。
音频频谱的获取
首先音频的频谱相关的类叫做 android.media.audiofx.Visualizer;
需要权限 <uses-permission android:name="android.permission.RECORD_AUDIO"/>
所以要做的第一件事 是初始化一个visualizer出来
//使用音乐的sessionId来实例化这个类
mVisualizer
= new Visualizer(mMediaPlayer.getAudioSessionId());
//设置每次捕获频谱的大小,音乐在播放中的时候采集的数据的大小或者说是采集的精度吧,我的理解,而且getCaptureSizeRange()所返回的数组里面就两个值
.文档里说数组[0]是最小值(128),数组[1]是最大值(1024)。
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
//接下来就好理解了设置一个监听器来监听不断而来的所采集的数据。一共有4个参数,第一个是监听者,第二个单位是毫赫兹,表示的是采集的频率,第三个是是否采集波形,第四个是是否采集频率
mVisualizer.setDataCaptureListener(new
Visualizer.OnDataCaptureListener() {
//这个回调应该采集的是波形数据
@Override
public void onWaveFormDataCapture(Visualizer visualizer, byte[]
waveform,
int samplingRate) {
//waveformView 是一个自定义的view用来按照波形来画图 一会后面再讲
waveformView.updateVisualizer(waveform);
}
//这个回调应该采集的是快速傅里叶变换有关的数据,没试过,回头有空了再试试
@Override
public void onFftDataCapture(Visualizer visualizer, byte[]
fft,
int samplingRate) {
// TODO Auto-generated method stub
}
}, Visualizer.getMaxCaptureRate() / 2, true, false);
以上波形的数据采集就完成了,需要注意的一个点是mVisualizer.setEnabled(true);
这个方法的主要作用是为了控制何时去采集频谱数据,你应该只是愿意采集你所关心的音乐数据,而不关心声音输出器中任何的声音。而且对mVisualizer的许多设置必须在setEnable之前完成。并且结束功能后,要记得setEnable(false)
如果你见到了以下这个错误,那基本上就是因为没有及时setEnable(false),导致setCaptureSize()这个方法出错。
E/AndroidRuntime(22259): Caused by:
java.lang.IllegalStateException: setCaptureSize() called in wrong
state: 2
顺带再说一个bug 如果你得到的错误代码是 -1 那么基本上的原因是你忘记了声明权限
<uses-permission
android:name="android.permission.RECORD_AUDIO"/>
音频频谱的展示
你在上一节已经通过监听器获得了波形数据,那么如何展示?这仅仅是一个自定义view的问题,简单废话一下:重点提一下view中的onDraw()方法
@Override
protected
void onDraw(Canvas canvas) {
super.onDraw(canvas);
//mBytes就是采集来的数据 这里是个大小为1024的数组,里面的数据都是byts类型,所以大小为-127到128
if (mBytes == null) {
return;
}
if (mPoints == null || mPoints.length <
mBytes.length * 4) {
//mPoints主要用来存储要画直线的4个坐标(每个点两个坐标,所以一条直线需要两个点,也就是4个坐标)
mPoints = new float[mBytes.length * 4];
}
mRect.set(0, 0, getWidth(), getHeight());
//xOrdinate是x轴的总刻度,因为一次会传输过来1024个数据,每两个数据要画成一条直线,所以x轴我们分成1023段。你要是觉的太多了,也可以像我一样除以2,看自己需求了。
int xOrdinate = (mBytes.length - 1)/2;
//以下的for循环将利用mBytes[i] mBytes[i+1]
这两个数据去生成4个坐标值,从而在刻画成两个坐标,来画线条
for (int i = 0; i <xOrdinate ; i++) {
//第i个点在总横轴上的坐标,
mPoints[i * 4] = mRect.width() * i / xOrdinate;
//第i个点的在总纵轴上的坐标。他在画线上以总纵轴的1/2为基准线(mRect.height() /
2),所有的点或正或负以此线为基础标记。
//((byte) (mBytes[i] +
128))这个一直没有理解,如果+128是为了将数据全部换算为正整数,那么强转为byte后不又变回-127到128了么??要是谁知道原因可以留言告诉我.....
//(mRect.height() / 2) /
128就是将二分之一的总长度换算成128个刻度,因为我们的数据是byte类型,所以刻画成128个刻度正好
mPoints[i * 4 + 1] = mRect.height() / 2+ ((byte) (mBytes[i] + 128))
* (mRect.height() / 2) / 128;
//以下就是刻画第i+1个数据了,原理和刻画第i个一样
mPoints[i * 4 + 2] = mRect.width() * (i + 1) / xOrdinate;
mPoints[i * 4 + 3] = mRect.height() / 2 + ((byte) (mBytes[i + 1] +
128)) * (mRect.height() / 2) / 128;
}
//循环结束后,就得到了这一次波形的所有刻画坐标,直接画在画布上就好了
canvas.drawLines(mPoints, mForePaint);
}
做的音乐软件 纯粹好玩 就放在了国内的market上
http://market.nduoa.com/apk/detail/412136
android获取和展示音乐的频谱的更多相关文章
- Android获取网络状态
Android获取网络状态 学习自 https://developer.android.google.cn/reference/android/net/ConnectivityManager http ...
- Android获取SD卡路径/内存的几种方法
Android获取SD卡路径 本篇将会带领大家学习如何获取android路径的几种常见用法,但在我开始bb之前需要大家清楚android中内存和外存之间的区别,下面进行简短介绍:android中的内存 ...
- Android获取内置sdcard跟外置sdcard路径
Android获取内置sdcard跟外置sdcard路径.(测试过两个手机,亲测可用) 1.先得到外置sdcard路径,这个接口是系统提供的标准接口. 2.得到上一级文件夹目录 3.得到该目录的所有文 ...
- Android获取系统时间方法的总结
Android获取系统时间方法的方法有很多种,常用的有Calendar.Date.currentTimeMills等方法. (1)Calendar Calendar获取系统时间首先要用Calendar ...
- Android获取屏幕宽和高
android获取屏幕的高度和宽度用到WindowManager这个类,两种方法: 1.WindowManager wm = (WindowManager) getContext() ...
- android 获取文件夹、文件的大小 以B、KB、MB、GB 为单位
android 获取文件夹.文件的大小 以B.KB.MB.GB 为单位 public class FileSizeUtil { public static final int SIZETYPE_B ...
- Android获取APK包名的几种方法
Android获取APK包名的几种方法:1.adb shell pm list package -f | findstr 关键字 #只能获取到包名,主Activity名无法获取到 2.使用aapt-- ...
- I.MX6 android 获取framebuffer信息
/******************************************************************************** * I.MX6 android 获取 ...
- android 获取IMEI号
android 获取 imei号码 核心代码: Imei = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId( ...
随机推荐
- Android时间戳与字符串相互转换
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public cl ...
- python内存增长问题
如果你的程序没有调用什么特殊的库, 只是用了很平常的库, 而且使再循环很多的情况下, 那么建议你把循环里的程序拆出来,写成一子函数,循环子函数. 如下面格式: for (循环) 子函数 这样程序每 ...
- 忍者无敌-实例解说Cocos2d-x瓦片地图
实例比較简单,如图所看到的,地图上有一个忍者精灵,玩家点击他周围的上.下.左.右,他能够向这个方向行走. 当他遇到障碍物后是无法穿越的,障碍物是除了草地以为部分,包含了:树.山.河流等. 忍者实例地图 ...
- 【LeetCode-面试算法经典-Java实现】【199-Binary Tree Right Side View(从右边看二叉树)】
[199-Binary Tree Right Side View(从右边看二叉树] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 代码下载[https://github.co ...
- c编程:僵尸吃大脑
第一行输入一个正整数n 以下每一行输入僵尸已经吃了的大脑数量a,和需要生存必需要吃的大脑数量b.总共n行. 例子输入 3 4 5 3 3 4 3 例子输出 NO BRAINS MMM BRAINS M ...
- Codeforces Round #445 Div. 1 C Maximum Element (dp + 组合数学)
题目链接: http://codeforces.com/contest/889/problem/C 题意: 给你 \(n\)和 \(k\). 让你找一种全排列长度为\(n\)的 \(p\),满足存在下 ...
- 【例题 6-14 UVA-816】Abbott's Revenge
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 预处理出某个方向的左边.前边.右边是哪个方向就好了. 然后就是普通的bfs了. hash存到某个点,走到这里的方向的最小距离. df ...
- App.js和App.css(用于移动应用的js和css)
App.js和App.css(用于移动应用的js和css) 一.App.js和App.css(用于移动应用的js和css) App.js 是一个轻量级的 JavaScript UI 库,用来创建移动的 ...
- c++读取lua配置基础类
一.内容介绍 把lua作为配置文件,里面的参数值的获取,在他人基础上做了修改,并且补充了一维数组的处理方式. 若有不足之处请多多指教. 对于二维数组,没有成功.希望大家继续补充和修改,非常感谢! 二. ...
- 【习题 3-1 UVA - 1585】Score
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟水题 [错的次数] 在这里输入错的次数 [反思] 在这里输入反思 [代码] #include <bits/stdc++.h ...