如何从AudioRecord读取的ShortArray数据中提取音频振幅
从AudioRecord读取的ShortArray中提取振幅的实现方法
你当前用ShortArray接收音频数据的写法,是适配安卓平台最通用的AudioFormat.ENCODING_PCM_16BIT(16位有符号PCM)音频格式的标准写法,比处理ByteArray少了手动拼接高低位字节的步骤,提取振幅的逻辑更简单。
16位PCM单个采样点的取值范围为-32768~32767,和Kotlin中Short类型的取值范围完全匹配,你可以根据业务场景直接计算两类常用振幅值:
- 瞬时峰值振幅:响应速度快,适合做实时跳变的峰值电平条、突发爆音检测。计算逻辑为遍历当前帧所有采样点,取绝对值的最大值。
注意必须先将Short值转为Int再取绝对值,否则Short.MIN_VALUE(-32768)取绝对值时会发生数值溢出,得到错误结果:var peakAmp = 0 for (sample in data) { val absVal = sample.toInt().absoluteValue if (absVal > peakAmp) peakAmp = absVal } // 输出范围0~32767,数值越大振幅越高 - RMS均方根振幅:反映音频帧的平均能量,更贴合人耳对响度的实际感知,不会被单个异常尖峰干扰,是普通音量检测、平均电平显示的首选方案。计算逻辑为对帧内所有采样点求平方和的均值,再开平方:
import kotlin.math.sqrt var squareSum = 0.0 for (sample in data) { val intVal = sample.toInt() squareSum += intVal * intVal } val rmsAmp = sqrt(squareSum / data.size).toInt() // 输出范围0~32767
如果需要将振幅映射到0~1的归一化区间(比如绑定UI进度条、设置音量触发阈值),直接将计算得到的振幅值除以32767.0即可:
val normalPeak = peakAmp / 32767.0f val normalRms = rmsAmp / 32767.0f
网上流传的基于ByteArray的振幅提取方案,核心逻辑是先将每两个连续字节按小端序拼接为16位Short值,再执行和上述完全一致的振幅计算。你直接读取ShortArray的方式,相当于系统已经帮你完成了字节拼接、字节序处理的底层步骤,代码更简洁,运行效率更高,也能避免手动处理字节时容易出现的高低位错位、字节序错误等问题。
内容的提问来源于stack exchange,提问作者Pavel Poley
相关产品推荐
相关产品推荐

