音频采样

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

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

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

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

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

采样和重新采样的最佳做法

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

选择适合设备的采样率

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

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

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

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

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

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

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

更改采样率时请使用上采样,而不是下采样

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

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

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

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

浮点

以下 Wikipedia 页面有助于理解浮点音频:

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