从 Android 5.0 (Lollipop) 开始,音频重采样器现在完全基于源自 Kaiser 窗函数的 FIR 滤波器。Kaiser 窗函数提供以下属性
- 对于其设计参数(阻带纹波、过渡带宽、截止频率、滤波器长度)来说,它很容易计算。
- 与总能量相比,它几乎是最优的阻带能量降低方法。
请参阅 P.P. Vaidyanathan 的著作, Multirate Systems and Filter Banks,第 50 页,了解有关 Kaiser 窗及其最优性和与 Prolate 球面窗的关系的讨论。
设计参数会根据内部质量确定和所需的采样率自动计算。根据设计参数,生成窗函数 sinc 滤波器。对于音乐使用,44.1 到 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。
如果您担心延迟,请勿重新采样
重新采样会阻止轨道放置在 FastMixer 路径中,这意味着由于普通 Mixer 路径中额外的、更大的缓冲区,会发生明显更高的延迟。此外,重新采样器的滤波器长度会产生一个隐式延迟,尽管这通常在一毫秒或更短的时间内,这不像普通 Mixer 路径的额外缓冲区那样大(通常为 20 毫秒)。
使用浮点音频
使用浮点数表示音频数据可以在高性能音频应用中显着提高音频质量。浮点具有以下优点
- 更宽的动态范围。
- 在整个动态范围内保持一致的精度。
- 在中间计算和瞬态期间避免削波的更多裕量。
虽然浮点可以提高音频质量,但它确实存在一些缺点
- 浮点数占用更多内存。
- 浮点运算采用意想不到的属性,例如,加法不具有结合律。
- 浮点计算有时会由于舍入或数值不稳定算法而丢失算术精度。
- 有效使用浮点需要更深入的了解才能获得准确且可重复的结果。
以前,浮点以不可用或速度慢而闻名。对于低端和嵌入式处理器,情况仍然如此。但现代移动设备上的处理器现在拥有硬件浮点,其性能与整数类似(或者在某些情况下甚至更快)。现代 CPU 还支持 SIMD(单指令,多数据),这可以进一步提高性能。
浮点音频的最佳实践
以下最佳实践可以帮助您避免浮点计算出现的问题
- 对于不频繁的计算(例如计算滤波器系数),请使用双精度浮点。
- 注意操作顺序。
- 为中间值声明显式变量。
- 适度使用括号。
- 如果您得到 NaN 或无穷大结果,请使用二分搜索来发现它是在哪里引入的。
对于浮点音频,音频格式编码 AudioFormat.ENCODING_PCM_FLOAT
用于类似于 ENCODING_PCM_16_BIT
或 ENCODING_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 的争议
- D/A 和 A/D | 数字展示和讲述 由 Xiph.Org 的 Christopher "Monty" Montgomery 制作的视频。
- 采样率的科学 (何时更高更好 - 何时不更好).
- 音频神话与 DAW 战争
- 192kHz/24bit 与 96kHz/24bit "辩论" - 有趣的揭示
浮点
以下维基百科页面有助于理解浮点音频
- 音频位深
- 浮点运算
- IEEE 754 浮点
- 显著性丢失(灾难性抵消)
- 数值稳定性
以下文章提供有关浮点的那些对计算机系统设计人员有直接影响方面的的信息
- 每个计算机科学家应该了解的浮点运算 由 Xerox PARC 的 David Goldberg 撰写(编辑转载)。