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 ...
随机推荐
- poj 1734 Sightseeing trip_ 最小环记录路径
题意:求最出小环,输出路径 #include <iostream> #include<cstdio> using namespace std; #define N 110 #d ...
- 【LeetCode练习题】Validate Binary Search Tree
Validate Binary Search Tree Given a binary tree, determine if it is a valid binary search tree (BST) ...
- API经济产业
技术大咖为我们铺好了前进道路,我们为什么还要敬而远之舍近索远呢?充分利用开源,利用API进行App有效整合. 为应用添加日志功能,Loggly; 为应用添加用户管理和身份认证模块,Stormpath; ...
- Storages and virtual servers
1. IBM Storages: SONAS,V7k,V7ku,SVC,XIV 存储设备都安装了个性化定制的Linux系统,来完成不同的服务,这几台存储设备使用原理都是类似的,以SONAS (Scal ...
- jquery第三期:js与jquery对象转换
我们开始进入jquery的学习了,jquery的学习就不那么中规中矩了,我们来看一个和javascript有所区别的地方. <!DOCTYPE html PUBLIC "-//W3C/ ...
- paip.vs2010 或.net 4.0安装出错解决大法.
paip.vs2010 或.net 4.0安装出错解决大法. 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.cs ...
- springmvc 传递和接收数组参数
java url中如何传递数组,springMVC框架controller类如何接收数组参数? 下面介绍一下URL中传递数组参数方法: dd.do?titles[]=col1&titles[] ...
- SSH框架中一些技巧、处理办法
1.使用jstree插件时,操作成功直接刷新jstree 该页面(index.jsp)本身使用iframe框架jstree在leftFrame,操作页(add_input.jsp.add_succes ...
- Java 反射机制浅析
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...
- VB.NET 内存指针和非托管内存的应用
介绍 Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存.然而利用.NET框架中的structures 和 classes,可以做许多类似的事情.它们包括 IntPtr, ...