【发布时间】:2010-10-26 10:36:31
【问题描述】:
我必须将数字音频信号的位深度从 24 位降低到 16 位。
仅取每个样本的 16 个最高有效位(即截断)相当于进行比例计算(out = in * 0xFFFF / 0xFFFFFF)?
【问题讨论】:
标签: audio 16-bit 24-bit quantization
我必须将数字音频信号的位深度从 24 位降低到 16 位。
仅取每个样本的 16 个最高有效位(即截断)相当于进行比例计算(out = in * 0xFFFF / 0xFFFFFF)?
【问题讨论】:
标签: audio 16-bit 24-bit quantization
在截断(也称为抖动)之前,将精心制作的噪声信号添加到原始信号中,略低于截断阈值,您将获得更好的声音效果。
【讨论】:
x * 0xffff / 0xffffff 过于迂腐,但如果您的样本已签名,则不是一个好的方式——而且总体上可能不是一个好的方式。
是的,您希望源范围中的最大值与目标范围中的最大值相匹配,但那里使用的值仅用于无符号范围,并且量化步长的分布意味着很少有你使用最大可能的输出值。
如果样本有符号,则正峰值将为 0x7fff 和 0x7fffff,而负峰值将为 -0x8000 和 -0x800000。您的第一个问题是确定 +1 是否等于 0x7fff,或者 -1 是否等于 -0x8000。如果您选择后者,那么这是一个简单的移位操作。如果您尝试同时拥有两者,那么零就不再是零了。
之后,您会遇到除法四舍五入为零的问题。这意味着与其他值相比,太多的值被四舍五入为零。这会导致失真。
如果您想根据峰值正值进行缩放,正确的形式是:
out = rint((float)in * 0x7fff / 0x7fffff);
如果您稍微摸索一下,您可能会找到一种有效的方法来做到这一点,它使用整数算术而不是除法。
对于任何给定的输入,这种形式应该正确地四舍五入到最接近的可用输出值,并且它应该将最大可能的输入值映射到最大可能的输出值,但是它的量化步长分布会分散在整个范围内.
大多数人喜欢:
out = (in + 128) >> 8;
if (out > 0x7fff) out = 0x7fff;
这种形式使声音变得最小,以至于正值可能会略微削波,但量化步长分布均匀。
您添加 128 是因为右移舍入到负无穷大。 平均量化误差为 -128,您添加 128 来纠正此误差以使 0 保持在 0 精确。溢出测试是必要的,因为输入值 0x7fffff 否则会给出 0x8000 的结果,当你将它存储在一个 16 位的字中,它会环绕给出一个峰值负值。
C 学究可能会在关于右移和除法行为的假设中戳破洞,但为了清楚起见,我忽略了这些。
但是,正如其他人指出的那样,您通常不应该在没有抖动的情况下降低音频的位深度,最好是噪声整形。 TPDF抖动如下:
out = (in + (rand() & 255) - (rand() & 255)) >> 8;
if (out < -0x8000) out = -0x8000;
if (out > 0x7fff) out = 0x7fff;
同样,rand() 的使用存在很大问题,为了清楚起见,我将忽略这些问题。
【讨论】:
我假设你的意思是(in * 0xFFFF) / 0xFFFFFF,在这种情况下,是的。
【讨论】:
out = in >> 8(对于无符号样本)。