通过截断减少采样位深度

时间:2010-10-26 10:36:32

标签: audio 16-bit 24-bit quantization

我必须将数字音频信号的位深度从24位减少到16位。

仅取每个样本的16个最高有效位(即截断)相当于进行比例计算(out = in * 0xFFFF / 0xFFFFFF)?

4 个答案:

答案 0 :(得分:3)

在截断(a.k.a.抖动)之前,通过在原始信号上添加精心设计的噪声信号(恰好低于截断阈值),您将获得更好的声音效果。

答案 1 :(得分:1)

我认为你的意思是(in * 0xFFFF) / 0xFFFFFF,在这种情况下,是的。

答案 2 :(得分:1)

Dithering通过添加噪音一般会给你更好的效果。关键在于噪音的形状。 popula pow-r 抖动算法具有特定的形状,在许多数字音频工作站应用程序(Cakewalk的SONAR,Logic等)中非常流行。

如果你不需要完全保真的pow-r,你可以简单地以相当低的幅度产生一些noise并将它混合到你的信号中。你会发现这掩盖了一些量化效果。

答案 3 :(得分:0)

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()的大问题,为了清楚起见我会忽略。