采样音频

从 Android 5.0 (Lollipop) 开始,音频重采样器完全基于源自 Kaiser 窗函数加窗 Sinc 函数的 FIR 滤波器。Kaiser 窗函数加窗 Sinc 函数具有以下特性:

  • 其设计参数(阻带纹波、过渡带宽、截止频率、滤波器长度)计算直观。
  • 与总能量相比,它在降低阻带能量方面几乎是最佳的。

关于 Kaiser 窗函数及其最优性以及与长球形窗函数的关系,请参阅 P.P. Vaidyanathan 的《Multirate Systems and Filter Banks》(第 50 页)。

根据内部质量确定和所需的采样比率自动计算设计参数。基于设计参数生成加窗 Sinc 滤波器。对于音乐用途,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 设备上播放时,即使 AudioTrack 可能允许其他采样率和比率,也请选择简单比率的采样率,例如 24 kHz (1:2) 和 32 kHz (2:3)。

使用升采样而不是降采样来更改采样率

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

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

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

降采样通常由硬件设备要求触发。当使用采样率转换器进行降采样时,请尝试将降采样比率限制在不大于 6:1,以获得良好的混叠抑制(例如,降采样不超过 48,000 到 8,000)。滤波器长度会调整以匹配降采样比率,但在较高的降采样比率下,您会牺牲更多的过渡带宽,以避免过度增加滤波器长度。升采样没有类似的混叠问题。请注意,音频管道的某些部分可能会阻止大于 2:1 的降采样。

如果您担心延迟,请勿重采样

重采样会阻止轨道进入 FastMixer 路径,这意味着由于普通 Mixer 路径中额外更大的缓冲区,会发生明显更高的延迟。此外,重采样器的滤波器长度会产生隐式延迟,尽管这通常在毫秒或更短的范围内,不如普通 Mixer 路径的额外缓冲(通常为 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 页面有助于理解浮点音频:

以下文章提供了对计算机系统设计者有直接影响的浮点相关信息: