从 Android 5.0(Lollipop)开始,音频重采样器现在完全基于源自凯泽窗函数的 sinc 函数的 FIR 滤波器。凯泽窗函数的 sinc 函数具有以下特性:
- 对于其设计参数(阻带波纹、过渡带宽、截止频率、滤波器长度)来说,计算起来很简单。
- 与整体能量相比,它在减少阻带能量方面几乎是最优的。
请参阅 P.P. Vaidyanathan 的《多速率系统和滤波器组》,第 50 页,了解有关凯泽窗及其最优性和与 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 撰写(编辑重印版)。