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 ...
随机推荐
- opendrive.com提供的免费网盘
opendrive.com是由以前freehao123给大家介绍的BOXSTr免费网络硬盘演变而来的,现在BOXSTr已经无法使用了.打开BOXSTr网站就会自动跳转到opendrive.com网站. ...
- 【具体数学 读书笔记】1.2 Lines in the Plane
本节介绍平面划分问题,即n条直线最多把一个平面划分为几个区域(region). 问题描述: "What is the maximum number Ln of regions defined ...
- hdu 2222 Keywords_ac自动机模板
题意:给你n个单词,再给你一串字符,求在字符中有多少个单词出现过 #include <iostream> #include<cstdio> #include<cstrin ...
- C++中基类的析构函数为什么要用virtual虚析构函数
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅: C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...
- 解决初学者学不懂android,不理解android的设计
最近在忙着搞一个小项目,所以没有来得及写一些原创性的东西,好容易今天中秋节,就趁现在写一些吧,今天仍然看了些老马的视频,尽管这些东西以前都用过,但是感觉仍然学到了不少东西,说给大家听希望大家也要不要不 ...
- WIN7 以下创建cocos2d-x3.0+lua项目
用命令行生成和执行项目 无需打开VS 配置完环境 CMD执行 cocos new helloWold -p com.test -l lua -d E:\cocos2dx 来创建项目 cocos ...
- Google C++ style guide——头文件
1.#define保护 使用#define防止头文件被多重包括.命名格式为:<PROJECT>_<PATH>_<FILE>_H_ 比如,foo中的头文件foo/sr ...
- Oracle SecureFiles 说明(转)
Oracle SecureFiles 说明 Oracle Database 11g 将LOB 数据类型作为Oracle SecureFiles 进行了完全重新设计,显著改进了应用程序开发的性能.可管理 ...
- 编写isNull isArray isFunction的方法
1.isNull 判断null,需要排除掉undefined和0.''(空串). function isNull(arr){ return !arr&&typeof arr!=='un ...
- .net程序员转战android第二篇---牛刀小试
上篇说道如何搭建android的开发环境,这一篇我们将牛刀小试一下, 完成我们第一个android APP应用. 我就从新建项目说起吧. 首先打开Eclipse,选择顶部的File(文件)——new( ...