Android 音频可视化

Android音频可视化,指的是将音频的频率绘制到屏幕上,达到一种视觉效果,使播放或录制过程更加生动形象。

Android进行视频可视化涉及的三个主要知识点,其中比较难以理解的傅里叶变换公式。

  • Android原生的Visualizer使用(获取频率数据)
  • 傅里叶变换(音频从时域到频域变换理论)
  • 自定义View(展示频率数据)
一、开发难点
  • Android原生的Visualizer限制

    • 需要录音权限(播放音乐需要录音权限?)
    • 音量为0时,获取不到数据(有可能被误认为Bug)
    • 仅支持AudioTrack,MediaPlayer

    解决方案,自定Visualizer,可以参考末尾文章。

  • 傅里叶变换的理解

    如果从数学角度去推导和验证傅里叶变换,需要学习三角函数及其正交性、微积分、欧拉定理等等。感兴趣可看文章末尾B站视频。在这里,我们暂且知道傅里叶变换可以将函数分解成正余弦函数之和。在工程上应用,可以从时域变换到频域,从而可以观察一些特性。例如在音频上,在频率可以分析大多数男生为低频,女生为高频,可以进行变音处理和声纹模仿等应用。

    通过Visualizer可以拿到傅里叶变换后的数据,或者通过第三方库区计算。

  • 自定义View

    拿到频率数据,如何处理这些数据,并在View进行绘制。

二、Visualizer

比较庆幸的,Android原生为我们提供了Visualizer类,让我们可以快速得从音频获取原始的波形数据或快速傅里叶变换后数据。下面简单介绍其使用。

我们在创建AudioTrack或者AudioRecord实例后,可以获取对应的audioSessionId,用于创建Visualizer实例。

val visualizer = Visualizer(audioTrack.audioSessionId)

通过setCaptureSize函数设置采样率大小,其大小我们一般通过getCaptureSizeRange函数来获取。getCaptureSizeRange函数返回两个int类型数组,第一个表示最小值,第二个表示最大值,用来表示采样值的范围。

 visualizer.captureSize = Visualizer.getCaptureSizeRange()[1]

接着通过setDataCaptureListener获取采样数据回调。

setDataCaptureListener(OnDataCaptureListener listener,int rate, boolean waveform, boolean fft)
  • OnDataCaptureListener 采样数据回调类,拥有onWaveFormDataCaptureonFftDataCapture两个函数,前者回调波形数据,后者回调傅里叶变换后数据。

  • rate 采样的频率,设置范围在0~Visualizer.getMaxCaptureRate()

  • waveform 是否返回波形数据,false的话,OnDataCaptureListeneronWaveFormDataCapture函数不会有回调。

  • fft 是否返回傅里叶变换后数据,false的话,OnDataCaptureListeneronFftDataCapture函数不会有回调。

    visualizer.setDataCaptureListener(object : OnDataCaptureListener {
    override fun onWaveFormDataCapture(visualizer: Visualizer?, waveform: ByteArray?, samplingRate: Int) {

      }
    
      override fun onFftDataCapture(visualizer: Visualizer?, fft: ByteArray?, samplingRate: Int) {
    
      }
    

    }, Visualizer.getMaxCaptureRate() / 2, false, true)

开始采样:

visualizer.enabled = true

退出界面或者停止,记得设置:

visualizer.enabled = false
三、自定义View

通过给Visualizer设置OnDataCaptureListener之后,可以onFftDataCapture函数中获取快速傅里叶变换后的数据,但如何处理返回后的fft数据呢?

通过FFT的数组格式,获取到每个频率点的实部和虚部。

val n = fft!!.size
val magnitudes = FloatArray(n / 2 + 1)
val phases = FloatArray(n / 2 + 1)
magnitudes[0] = Math.abs(fft[0].toInt()) as Float // DC

magnitudes[n / 2] = Math.abs(fft[1].toInt()) as Float // Nyquist

phases[0] = 0.also { phases[n / 2] = it.toFloat() }.toFloat()
for (k in 1 until n / 2) {
    val i = k * 2
    //取频率点实部与虚部的模
    magnitudes[k] = Math.hypot(fft!![i].toDouble(), fft!![i + 1].toDouble()).toFloat()
}

按照官方代码示例,我们去实数与虚数的模作为数据绘制点,模代表幅值的大小。

拿到数据magnitudes之后在View中进行绘制。

将每个点以条形状的形式画出:

mStrokeWidth = (mRect.width() - (mSpectrumCount - 1) * mItemMargin) / mSpectrumCount * 1.0f;
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setStyle(Paint.Style.FILL);
for (int i = 0; i < mSpectrumCount; i++) {
    canvas.drawLine(mRect.width() * i / mSpectrumCount, mRect.height() / 2, mRect.width() * i / mSpectrumCount, 2 + mRect.height() / 2 - mRawAudioBytes[i], mPaint);
}

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

相关推荐
Jouzzy6 小时前
【Android安全】Ubuntu 16.04安装GDB和GEF
android·ubuntu·gdb
极客先躯7 小时前
java和kotlin 可以同时运行吗
android·java·开发语言·kotlin·同时运行
茜茜西西CeCe9 小时前
移动技术开发:登录注册界面
java·gitee·gradle·android studio·安卓·移动技术开发·原生安卓开发
Good_tea_h9 小时前
Android中的单例模式
android·单例模式
小东来10 小时前
电脑端视频剪辑软件哪个好用,十多款剪辑软件分享
音视频
cuijiecheng201812 小时前
音视频入门基础:AAC专题(8)——FFmpeg源码中计算AAC裸流AVStream的time_base的实现
ffmpeg·音视频·aac
Mr数据杨13 小时前
我的AI工具箱Tauri版-VideoIntroductionClipCut视频介绍混剪
人工智能·音视频
神一样的老师13 小时前
基于环境音频和振动数据的人类活动识别
人工智能·音视频
启明云端wireless-tag13 小时前
设备稳定流畅视频体验,乐鑫ESP32-S3芯片方案无线音视频传输通信
物联网·音视频·交互·乐鑫·wifi模组
计算机源码社14 小时前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题