音频采样

从 Android 5.0 (Lollipop) 起,音频重采样器完全基于衍生自 Kaiser 加窗 sinc 函数的 FIR 滤波器。Kaiser 加窗 sinc 函数具有以下属性:

  • 可以轻松地计算其设计参数(阻带波纹、过渡带宽、截止频率和滤波器长度)。
  • 相对于整体能量来说,此函数几乎是减弱阻带能量的最佳选择。

请参阅 P.P. Vaidyanathan 编写的 Multirate Systems and Filter Banks 第 50 页,了解 Kaiser 窗口、其最优性以及与椭圆球面窗口的关系。

设计参数将根据内部质量确定结果和所需的采样比自动计算。根据设计参数,将生成加窗 sinc 滤波器。对于音乐用途,44.1 kHz 至 48 kHz(反之亦然)重采样器的生成质量要比任意频率转换的质量高。

为了达到这一质量要求,音频重采样器提供更高的质量和速度。不过,重采样器可能会带来少量的通带波纹和混叠谐波噪声,并且它们会导致过渡带中出现一些高频丢失,因此请避免不必要地使用重采样器。

有关采样和重采样的最佳做法

本部分介绍了可以帮助您避免采样率问题的一些最佳做法。

选择适合设备的采样率

一般而言,最好选择适合设备的采样率,通常为 44.1 kHz 或 48 kHz。使用大于 48 kHz 的采样率一般会导致质量下降,因为必须使用重采样器回放文件。

使用简单的重采样比(固定与插值多相)

重采样器可以在下列几种模式下运行:

  • 固定多相模式。每个多相的滤波器系数都是预计算的。
  • 插值多相模式。每个多相的滤波器系数必须从最接近的两个预计算多相插入。

重采样器在固定多相模式下最快,此时输入速率与输出速率之比 L/M(除去最大公约数)中的 M 小于 256。例如,对于 44100 至 48000 转换,L = 147,M = 160。

在固定多相模式下,采样率被锁定,不会发生变化。在插值多相模式下,采样率为近似值。在 48-kHz 设备上播放时,采样率偏移一般为几小时内一个样本。这通常不是问题,因为近似误差比内部石英振荡器、热偏移或抖动引起的频率误差(一般为数十 ppm)小得多。

在 48-kHz 设备上回放时,请选择简单比采样率(例如 24 kHz (1:2) 和 32 kHz (2:3)),即使可以通过 AudioTrack 允许其他采样率和比例。

使用上采样(而不是降采样)来更改采样率

可以动态更改采样率。此类更改的粒度基于内部缓冲(通常为数百个样本),而不是逐个样本更改。这可以用于音效。

降采样时,请不要动态更改采样率。如果在创建音轨后更改采样率,降采样时与原始采样率存在 5%-10% 的差异可能会触发滤波器重新计算(以正确抑制混叠)。这会消耗计算资源,并且如果滤波器被实时替换,还可能听到咔哒声。

将降采样限制为不大于 6:1

降采样通常由硬件设备要求触发。如果在降采样时使用采样率转换器,为了取得良好的混叠抑制效果,请尝试将降采样比限制为不大于 6:1(例如,不大于 48000:8000 的降采样)。滤波器长度将调整以匹配降采样比,但是如果降采样比较高,您将牺牲更多的过渡带宽来避免过度增加滤波器长度。上采样则没有类似的混叠担忧。请注意,某些部分的音频管道可能会阻止大于 2:1 的降采样。

如果您对延迟感到担忧,请不要重采样

重采样会阻止音轨被置于快速混合器路径,这意味着由于普通混合器路径中存在其他更大的缓冲区,将出现显著更长的延迟时间。此外,重采样器的滤波器长度还存在隐式延迟,尽管延迟的数量级一般为一毫秒或更短,不如普通混合器路径附加缓冲的时间(一般为 20 毫秒)长。

使用浮点音频

使用浮点数表示音频数据可以显著增强高性能音频应用中的音频质量。浮点数具有以下优势:

  • 更宽的动态范围。
  • 动态范围内一致的准确性。
  • 更多余量,可以避免在中间计算和瞬态期间发生截断情况。

尽管可以增强音质,浮点数也存在特定的劣势:

  • 浮点数占用更多内存。
  • 浮点数运算具有意外特性,例如加法不遵守结合律。
  • 由于四舍五入或者数字不稳定算法,浮点运算有时会牺牲一些算数精度。
  • 若要有效使用浮点数,就需要对它有更充分的理解,才能获得准确且可重现的结果。

之前,浮点数曾因不可用或者速度慢而被诟病。这种情况仍然存在于低端和嵌入式处理器中。但是,对于现代移动设备上的处理器来说,硬件浮点数的性能已经与整数相似(某些情况下甚至比后者更快)。现代 CPU 还支持 SIMD(单指令流多数据流),这种技术可以进一步提升性能。

有关浮点音频的最佳做法

下面的最佳做法可以帮助您避免浮点运算存在的问题:

  • 对频率较低的运算(例如计算滤波器系数)使用双精度浮点数。
  • 注意运算顺序。
  • 为中间值声明显式变量。
  • 大量地使用括号。
  • 如果获得 NaN 或无穷结果,请使用二分搜索发现导致这种情况的地方。

对于浮点音频,音频格式编码 AudioFormat.ENCODING_PCM_FLOAT 的使用方式类似于使用 ENCODING_PCM_16_BITENCODING_PCM_8_BIT 指定 AudioTrack 数据格式。相应的过载方法 AudioTrack.write() 将采用浮点数组来提供数据。

Kotlin

fun write(
        audioData: FloatArray,
        offsetInFloats: Int,
        sizeInFloats: Int,
        writeMode: Int
): Int

Java

public int write(float[] audioData,
        int offsetInFloats,
        int sizeInFloats,
        int writeMode)

更多信息

本部分列出了与采样和浮点数有关的一些其他资源。

采样

采样率

重采样

高位深度与高 kHz 争论

浮点

以下维基百科页面有助于理解浮点音频:

以下文章介绍了浮点对计算机系统设计人员有直接影响的方面: