Android平台音频信号FFT的实现

转载请标明出处:http://blog.csdn.net/sctu_vroy/article/details/45871823

功能:加载本地SD卡中moveDsp文件夹中的音频文件(包括录音获取文件和MP3文件),播放实时FFT,绘制出信号的时域和频域波形。

设计步骤:

第一步:页面布局,编写录音工具类URecorder(设置录音属性)和接口IVoiceManager

[java] view plaincopy

  1. public class URecorder implements IVoiceManager{
  2. private static final String TAG = "URecorder";
  3. private Context context = null;
  4. private String path = null;
  5. private MediaRecorder mRecorder = null;
  6. public URecorder(Context context, String path) {
  7. this.context = context;
  8. this.path = path;
  9. mRecorder = new MediaRecorder();
  10. }
  11. @Override
  12. public boolean start() {
  13. //设置音源为Micphone
  14. mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  15. //设置封装格式
  16. mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
  17. mRecorder.setOutputFile(path);
  18. //设置编码格式
  19. mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  20. try {
  21. mRecorder.prepare();
  22. } catch (IOException e) {
  23. Log.e(TAG, "prepare() failed");
  24. }
  25. //录音
  26. mRecorder.start();
  27. return false;
  28. }
  29. @Override
  30. public boolean stop() {
  31. mRecorder.stop();
  32. mRecorder.release();
  33. mRecorder = null;
  34. return false;
  35. }
  36. }

[java] view plaincopy

  1. public interface IVoiceManager {
  2. public boolean start();
  3. public boolean stop();
  4. }

第二步:继承父类View,编写自定义绘图类VisualizerView(显示时域波形)和VisualizerFFTView(显示频域波形(频谱)),重写onDraw()方法

时域波形显示类:

[java] view plaincopy

  1. public class VisualizerView extends View {
  2. private byte[] mBytes;
  3. private float[] mPoints;
  4. private Rect mRect = new Rect();
  5. private Paint mForePaint = new Paint();
  6. public VisualizerView(Context context) {
  7. super(context);
  8. init();
  9. }
  10. /**
  11. * 初始化
  12. */
  13. private void init() {
  14. mBytes = null;
  15. mForePaint.setStrokeWidth(1f);
  16. mForePaint.setAntiAlias(true);
  17. mForePaint.setColor(Color.GREEN);
  18. }
  19. public void updateVisualizer(byte[] waveForm)
  20. {
  21. mBytes = waveForm;
  22. invalidate();
  23. }
  24. @Override
  25. protected void onDraw(Canvas canvas) {
  26. super.onDraw(canvas);
  27. if (mBytes == null)
  28. {
  29. return;
  30. }
  31. if (mPoints == null || mPoints.length < mBytes.length * 4)
  32. {
  33. mPoints = new float[mBytes.length * 4];
  34. }
  35. mRect.set(0, 0, getWidth(), getHeight());
  36. //绘制波形
  37. for (int i = 0; i < mBytes.length - 1; i++) {
  38. mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
  39. mPoints[i * 4 + 1] = mRect.height() / 2
  40. + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
  41. mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
  42. mPoints[i * 4 + 3] = mRect.height() / 2
  43. + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
  44. }
  45. canvas.drawLines(mPoints, mForePaint);
  46. }
  47. }

频谱显示类:

[java] view plaincopy

  1. public class VisualizerFFTView extends View {
  2. private byte[] mBytes;
  3. private float[] mPoints;
  4. private Rect mRect = new Rect();
  5. private Paint mForePaint = new Paint();
  6. private int mSpectrumNum = 48;
  7. public VisualizerFFTView(Context context) {
  8. super(context);
  9. init();
  10. }
  11. /**
  12. * 初始化
  13. */
  14. private void init() {
  15. mBytes = null;
  16. mForePaint.setStrokeWidth(8f);
  17. mForePaint.setAntiAlias(true);
  18. mForePaint.setColor(Color.rgb(0, 128, 255));
  19. }
  20. public void updateVisualizer(byte[] fft)
  21. {
  22. byte[] model = new byte[fft.length / 2 + 1];
  23. model[0] = (byte) Math.abs(fft[0]);
  24. for (int i = 2, j = 1; j < mSpectrumNum;)
  25. {
  26. model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
  27. i += 2;
  28. j++;
  29. }
  30. mBytes = model;
  31. invalidate();
  32. }
  33. @Override
  34. protected void onDraw(Canvas canvas) {
  35. super.onDraw(canvas);
  36. if (mBytes == null)
  37. {
  38. return;
  39. }
  40. if (mPoints == null || mPoints.length < mBytes.length * 4)
  41. {
  42. mPoints = new float[mBytes.length * 4];
  43. }
  44. mRect.set(0, 0, getWidth(), getHeight());
  45. //绘制频谱
  46. final int baseX = mRect.width()/mSpectrumNum;
  47. final int height = mRect.height();
  48. for (int i = 0; i < mSpectrumNum ; i++)
  49. {
  50. if (mBytes[i] < 0)
  51. {
  52. mBytes[i] = 127;
  53. }
  54. final int xi = baseX*i + baseX/2;
  55. mPoints[i * 4] = xi;
  56. mPoints[i * 4 + 1] = height;
  57. mPoints[i * 4 + 2] = xi;
  58. mPoints[i * 4 + 3] = height - mBytes[i];
  59. }
  60. canvas.drawLines(mPoints, mForePaint);
  61. }
  62. }

第三步:通过URI新建一个MediaPlayer对象,其他方式当执行getAudioSessionId()时将为null

[java] view plaincopy

  1. //uri = Uri.parse(AudioPath);  // 解析录音文件路径到uri
  2. uri = Uri.parse(Mp3Path);  // 解析MP3文件路径到uri
  3. 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[])。

[java] view plaincopy

  1. mWaveView = new VisualizerView(this);   // 创建VisualizerView对象
  2. mFFtView = new VisualizerFFTView(this);   // 创建VisualizerFFTView对象
  3. final int maxCR = Visualizer.getMaxCaptureRate();   // 获取最大采样率
  4. mVisualizer = new Visualizer(mMedia.getAudioSessionId());   // 实例化mVisualizer
  5. mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);   // 设置内容长度为1024
  6. mVisualizer.setDataCaptureListener(
  7. new Visualizer.OnDataCaptureListener()
  8. {
  9. public void onWaveFormDataCapture(Visualizer visualizer,
  10. byte[] waveform, int samplingRate)
  11. {
  12. mWaveView.updateVisualizer(waveform);  // 更新时域波形数据
  13. }
  14. public void onFftDataCapture(Visualizer visualizer,
  15. byte[] fft, int samplingRate)
  16. {
  17. mFFtView.updateVisualizer(fft);  // 更新频域波形数据
  18. }
  19. }, maxCR / 2, true, true);   // 采样速率为512MHz,设置同时获取时域、频域波形数据

需要注意的是:停止播放时,除了release播放类对象外,还要释放Visualizer对象。
音频信号FFT效果图:


源码下载链接:

https://github.com/vroy007/MoveDSP

http://download.csdn.net/detail/sctu_vroy/8720193

时间: 2024-10-17 06:04:39

Android平台音频信号FFT的实现的相关文章

基于Android平台的i-jetty网站智能农业监控系统

基于android平台i-jetty网站的智能农业监控系统 摘要:传统的监控系统,一般是基于PC的有线通信传输,其有很多不足之处,如功耗较高.布线成本高.难度大,适应性差,可扩展性不强,增加新的通信线路需要再次布线施工,而且维护起来也比较麻烦,一旦线路出问题,需要繁琐的检查.而嵌入式Web监控系统是基于物联网技术,其无线通信技术具有成本低廉.适应性强.扩展性强.信息安全.使用维护简单等优点. 智能农业中,种植大棚是通过大棚内安装温湿度以及光照传感器,来对农作物的环境参数进行实时采集,由Web监控

Unity3D在Android平台使用嵌入式数据库Sqlite,解决无法找到数据库文件的问题

做一个需要嵌入式数据库Sqlite 的unity3d项目,在pc机上运行良好,需要发布到Android平台上,于是,各种坑爹...会遇到找不到数据库文件的问题.当在pc机上使用sqlite时,当执行SqliteConnection dbConnection = new SqliteConnection("data source = test.db");语句时,如果有这个数据库文件则建立连接,如果没有则创建出这个文件,然后建立连接.当在Android平台上时,扯淡的事情就开始了,总之便不

用Kotlin开发android平台语音识别,语义理解应用(olamisdk)

用Kotlin开发android平台语音识别,语义理解应用(olamisdk) http://blog.csdn.net/ls0609/article/details/75084994

如何在android平台上使用js直接调用Java方法[转]

转载自:http://www.cocos.com/docs/html5/v3/reflection/zh.html #如何在android平台上使用js直接调用Java方法 在cocos2d-js 3.0beta中加入了一个新特性,在android平台上我们可以通过反射直接在js中调用java的静态方法.它的使用方法很简单: var o = jsb.reflection.callStaticMethod(className, methodName, methodSignature, parame

「Unity」与iOS、Android平台的整合:3、导出的Android-Studio工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

调研Android平台的开发环境的发展演变

一.发展演变 1.Android版本进化史 阿童木(Android beta)和发条机器人(Android1.0)->Cupcake(Android1.5)->Dount(Android1.6)->Eclair(Android2.0/2.1)->Froyo(Android2.2/2.2.1)->Gingerbread(Android2.3.x)->Honeycomb(Android3.0/3.1/3.2)->Ice Cream Sandwich(Android4.

Cocos2d-x 3.0修改Android平台帧率fps - 解决游戏运行手机发热发烫问题

使用Cocos2d-x 3.0开发游戏之后,发现游戏在android手机上发热非常严重,在魅族2上,几乎担心手机会爆炸了~~~采取的一个措施就是降低帧率,因为游戏对于帧率要求不是非常高. 做过cocos2d开发的同学应该都知道在win32平台修改帧率的方式非常简单,就是在AppDelegate.cpp文件中修改: 1 director->setAnimationInterval(1.0 / 40); 但是这种修改方式在导出android安卓apk到真机测试的时候,发现左下角的调试信息还是现实60

android平台的技术架构

Android平台采用了软件堆层(Software Stack)的架构,主要分为四个部分: 1.应用软件 Android 连同一个核心应用程序包一起发布,该应用程序包包括E-mail客户端.SMS短消息程序.日历.地图.浏览器.联系人管理程序等.所有的应用程序都是用Java编写的. 2.应用程序框架 开发者完全可以访问核心应用程序所使用的API框架.该应用程序框架架构用来简化组件软件的重用,任何一个应用程序都可以发布它的功能块并且任何其他的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全

Ogre3d Android平台编译教程

上一篇我们讲了Ogre3d 在 Window平台的编译流程方法 点击跳转 这一篇我们介绍 Ogre3d 编译到Android 平台的方法.可以和官方英文教程对照学习. 转载自博客 http://blog.csdn.net/huutu QQ:790621656 首先下载Ogre3d 依赖库源代码 和Ogre3d 源代码,下载方法在上一篇中介绍了,这里不再重复. 转载自博客 http://blog.csdn.net/huutu QQ:790621656 编译工具:NDK.Visual Studio.