Android平台音频信号FFT的实现
转载请标明出处:http://blog.csdn.net/sctu_vroy/article/details/45871823
功能:加载本地SD卡中moveDsp文件夹中的音频文件(包括录音获取文件和MP3文件),播放实时FFT,绘制出信号的时域和频域波形。
- public class URecorder implements IVoiceManager{
- private static final String TAG = "URecorder";
- private Context context = null;
- private String path = null;
- private MediaRecorder mRecorder = null;
- public URecorder(Context context, String path) {
- this.context = context;
- this.path = path;
- mRecorder = new MediaRecorder();
- }
- @Override
- public boolean start() {
- //设置音源为Micphone
- mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- //设置封装格式
- mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
- mRecorder.setOutputFile(path);
- //设置编码格式
- mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
- try {
- mRecorder.prepare();
- } catch (IOException e) {
- Log.e(TAG, "prepare() failed");
- }
- //录音
- mRecorder.start();
- return false;
- }
- @Override
- public boolean stop() {
- mRecorder.stop();
- mRecorder.release();
- mRecorder = null;
- return false;
- }
- }
- public interface IVoiceManager {
- public boolean start();
- public boolean stop();
- }
第二步:继承父类View,编写自定义绘图类VisualizerView(显示时域波形)和VisualizerFFTView(显示频域波形(频谱)),重写onDraw()方法
- public class VisualizerView extends View {
- private byte[] mBytes;
- private float[] mPoints;
- private Rect mRect = new Rect();
- private Paint mForePaint = new Paint();
- public VisualizerView(Context context) {
- super(context);
- init();
- }
- /**
- * 初始化
- */
- private void init() {
- mBytes = null;
- mForePaint.setStrokeWidth(1f);
- mForePaint.setAntiAlias(true);
- mForePaint.setColor(Color.GREEN);
- }
- public void updateVisualizer(byte[] waveForm)
- {
- mBytes = waveForm;
- 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;
- }
- canvas.drawLines(mPoints, mForePaint);
- }
- }
频谱显示类:
- public class VisualizerFFTView extends View {
- private byte[] mBytes;
- private float[] mPoints;
- private Rect mRect = new Rect();
- private Paint mForePaint = new Paint();
- private int mSpectrumNum = 48;
- public VisualizerFFTView(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)
- {
- 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());
- //绘制频谱
- 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);
- }
- }
第三步:通过URI新建一个MediaPlayer对象,其他方式当执行getAudioSessionId()时将为null
- //uri = Uri.parse(AudioPath); // 解析录音文件路径到uri
- uri = Uri.parse(Mp3Path); // 解析MP3文件路径到uri
- mMedia = MediaPlayer.create(this, uri); // 实例化mMedia对象,并通过uri将资源文件加载到该对象
调用Android SDK 2.3以上版本中一个工具包android.media.audiofx.Visualizer,程序需要做的就是实例化一个Visualizer对象,通过获得一个实例化的音频媒体类对象的SessionId,并设置该对象的需要转换的音乐内容长度和采样率。最后为visualizer设置监听器setDataCaptureListener(OnDataCaptureListener listener, rate, iswave, isfft),当采样得到的数据长度达到之前设置的内容长度后,将会触发两个函数,在这两个函数中即可分别得到音频信号的时域信号数据以及经过快速傅里叶变换(FFT)处理的频域信号数据,均为字节数组形式(即:byte[])。
- mWaveView = new VisualizerView(this); // 创建VisualizerView对象
- mFFtView = new VisualizerFFTView(this); // 创建VisualizerFFTView对象
- final int maxCR = Visualizer.getMaxCaptureRate(); // 获取最大采样率
- mVisualizer = new Visualizer(mMedia.getAudioSessionId()); // 实例化mVisualizer
- mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]); // 设置内容长度为1024
- mVisualizer.setDataCaptureListener(
- new Visualizer.OnDataCaptureListener()
- {
- public void onWaveFormDataCapture(Visualizer visualizer,
- byte[] waveform, int samplingRate)
- {
- mWaveView.updateVisualizer(waveform); // 更新时域波形数据
- }
- public void onFftDataCapture(Visualizer visualizer,
- byte[] fft, int samplingRate)
- {
- mFFtView.updateVisualizer(fft); // 更新频域波形数据
- }
- }, maxCR / 2, true, true); // 采样速率为512MHz,设置同时获取时域、频域波形数据
需要注意的是:停止播放时,除了release播放类对象外,还要释放Visualizer对象。
音频信号FFT效果图:
源码下载链接:
Android平台音频信号FFT的实现的更多相关文章
- [译]:Xamarin.Android平台功能——位置服务
返回索引目录 原文链接:Location Services. 译文链接:Xamarin.Android平台功能--位置服务 本部分介绍位置服务以及与如何使用位置提供商服务 Location Servi ...
- Cocos2d-x 3.2 学习笔记(四)学习打包Android平台APK!
从cocos2dx 3.2项目打包成apk安卓应用文件,搭建安卓环境的步骤有点繁琐,但搭建一次之后,以后就会非常快捷! (涉及到3.1.1版本的,请自动对应3.2版本,3.x版本的环境搭建都是一样的) ...
- (转)android平台phonegap框架实现原理
(原文)http://blog.csdn.net/wuruixn/article/details/7405175 android平台phonegap框架实现原理 分类: Android2012-03- ...
- Android平台免Root无侵入AOP框架Dexposed使用详解
Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架. Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者 ...
- Cocos2dx-3.0版本 从开发环境搭建(Win32)到项目移植Android平台过程详解
作为重量级的跨平台开发的游戏引擎,Cocos2d-x在现今的手游开发领域占有重要地位.那么问题来了,作为Cocos2dx的学习者,它的可移植特性我们就需要掌握,要不然总觉得少一门技能.然而这个时候各种 ...
- 基于android平台的斗地主AI
本软件是基于android平台的斗地主AI,我们在源代码的基础之上,旨在改进AI的算法,使玩家具有更丰富的体验感,让NPC可以更为智能. (一)玩法解析: (1)发牌和叫牌:一副扑克54张,先为每个人 ...
- 4412开发板Android教程——Android平台简介
本文转自迅为开发板论坛:http://www.topeetboard.com Android和IOS Android的历史 Android公司 2005年Google收购成立22个月的Android公 ...
- Android平台的开发环境的发展演变
因为之前学习java语言的时候安装过了eclipse,所以想在eclipse上搭建android平台,在参照知乎上大神们的意见,发现了AS强大的代码提示.实时预览和搜索匹配等出色功能,最后还是选择在A ...
- Cocos2d-x 3.0修改Android平台帧率fps - 解决游戏运行手机发热发烫问题
使用Cocos2d-x 3.0开发游戏之后,发现游戏在android手机上发热非常严重,在魅族2上,几乎担心手机会爆炸了~~~采取的一个措施就是降低帧率,因为游戏对于帧率要求不是非常高. 做过coco ...
随机推荐
- Python中metaclass解释
Classes as objects 首先,在认识metaclass之前,你需要认识下python中的class.python中class的奇怪特性借鉴了smalltalk语言.大多数语言中,clas ...
- Chapter 13. Miscellaneous PerlTk Methods PerlTk 方法杂项:
Chapter 13. Miscellaneous PerlTk Methods PerlTk 方法杂项: 到目前为止,这本书的大部分章节 集中在特定的几个部件, 这个章节覆盖了方法和子程序 可以被任 ...
- java反射 实例
首先介绍几个概念: 1.Java反射的概念 反射含义:可以获取正在运行的Java对象. 2.Java反射的功能 1)可以判断运行时对象所属的类 2)可以判断运行时对象所具有的成员变量和方法 3)通过反 ...
- c++冒泡排序的模板函数设计
说明 由于课程设计需要,特编写本程序.本程序首先定义了一个冒泡程序的模板函数,然后在main()函数中定义了两个不同类型的数组,调用模板函数对其进行排序.(注意,本程序是在linux下编写,但是直接拷 ...
- C# 泛型转换 将object[] 数组转换为泛型列表
public List<TaskSoftInfo> ReadSoftDownTaskList() { string[] Tid = (strin ...
- 深入理解JVM : Java垃圾收集器
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都可能会有很大差 ...
- JqueryUI-1
本文在于巩固基础 学习网址:http://jqueryui.com/ 基本概念:jQuery UI[是以 jQuery 为基础的开源 JavaScript 网页用户界面代码库.包含底层用户交互.动画. ...
- linode最新试用(购买)流程
最新linode官网www.linode.com可以免费试用7天,但是需要你的身份认证 第一步:注册一个linode账号email填写国内的163.126.qq邮箱是不能认证的,这里可以填写gmail ...
- matlab中norm与svd函数用法
格式:n=norm(A,p) 功能:norm函数可计算几种不同类型的矩阵范数,根据p的不同可得到不同的范数 以下是Matlab中help norm 的解释: NORM Matrix or vector ...
- 等待事件:enq: HW - contention和enq: TM - contention
今天生成了生产库前几日的AWR报告,发现等待事件中出现了一个陌生的event--enq: HW - contention,google一下是ASSM(Auto Segment Space Manage ...