【问题标题】:When using floating point numbers, what is the range of values used to represent audio samples使用浮点数时,用于表示音频样本的值的范围是多少
【发布时间】:2020-03-16 01:48:10
【问题描述】:

我了解浮点数是什么,以及使用它们来表示声音样本的优点。但是阅读介绍性文档this 或that 我无法准确找到存储和内部处理常用的比例尺。

所以当使用浮点数时,样本*通常会被存储吗:

  • 在[0.0,-1.0]范围内,0.0对应0dBFS
  • 在[1.0,-1.0]范围内,0.0对应0dBFS
  • 在[1.0, 0.0]范围内,1.0对应0dBFS
  • 还有别的吗?

似乎没有什么能与 2 的补码有符号整数范围的不对称性质完美匹配。


* 不包括 超出范围 样本

【问题讨论】:

  • 在浏览this 文章时肯定不清楚,但通常浮点音频在[-1.0, 1.0] 的范围内。分贝满量程,dBFS 是相对于最大幅度的幅度单位,其中 0 dBFS 是绝对最大值。这本身就令人困惑,因为 dB 通常是响度的度量。
  • 注意:来自维基百科 dBFS 文章 单位 dB FS 或 dBFS 在 AES 标准 AES17-1998、[13] IEC 61606、[14] 和 ITU-T P.38x 中定义,[ 15][16] 使得满量程正弦波的 RMS 值指定为 0dB FS。这意味着满量程方波的 RMS 值为 +3dB FS。[17][18]
  • 感谢 cmets @fdcpp!我认为您的第一条评论是对我问题的明确回答。所以不要犹豫,把它贴出来。关于您的第二条评论,这解释了为什么最大幅度的方波信号实际上会削波。在 D/A 转换期间,由于某些谐波(全部?)需要超过 0dBFS 限制,因此无法重建信号。还是我误解了你的报价?
  • 老实说,+3dBFS 的概念想想就觉得很奇怪。引用只是希望表明有一个标准,无论它是否有意义
  • 您对方波的看法是正确的。数字信号中的完美方波是最大饱和度的方波。从谐波序列重建将意味着超过奈奎斯特的频率内容。所以,你应该总是在数字域中看到一些gibbs phenomena。

标签: audio floating-point sampling representation


【解决方案1】:

来自@fdcpp 的评论,“浮点音频在 [-1.0, 1.0] 的范围内”。注意边界是包容性的。

当涉及到有符号整数的转换时,这让事情变得非常复杂。问题是对于 16 位有符号整数,最大正值为 32767,但最小值为 -32768:

>>> int.from_bytes(b"\x7F\xFF", 'big', signed=True)
32767
>>> int.from_bytes(b"\x80\x00", 'big', signed=True)
-32768

无论位长是多少,当使用 2 的补码有符号整数时,负值总是比正值多一个。因此,使用简单的除法(或乘法)你不能同时:

  • 将完整的整数范围映射到(或从)到完整的 [-1;+1] 范围
  • 和将 int(0) 映射到 float(0.0)。

对于保留 0 -> 0.0 映射的简单实现,请查看以下代码:

FLOAT32 = 'f'
FLOAT64 = 'd'

def simple_conv_test(nbits, floatFormat):
    """ Map the full scale of nbit signed integers to float
        and back to int. Display if the process is transparent
        (i.e. there is no loss of precision)
    """
    input = array('l', [-(1<<nbits-1), -1, 0, 1, (1<<nbits-1)-1])
    for factor in -input[0], input[-1]:
        print('Factor=', factor)
        int2float = array(floatFormat, [i/factor for i in input])
        float2int = array('l', [int(i*factor) for i in int2float])
        print(input)
        print(int2float)
        print(float2int)
        print("Transparent?", float2int == input)

您可以看到是否使用两个明显因素中的任何一个(16 位的 32768 或 32767),我们不使用浮点表示中的 [-1;+1] 范围满量程:

>>> simple_conv_test(16, FLOAT32)
Factor= 32768
array('l', [-32768, -1, 0, 1, 32767])
array('f', [-1.0, -3.0517578125e-05, 0.0, 3.0517578125e-05, 0.999969482421875])
array('l', [-32768, -1, 0, 1, 32767])
Transparent? True
Factor= 32767
array('l', [-32768, -1, 0, 1, 32767])
array('f', [-1.000030517578125, -3.0518509447574615e-05, 0.0, 3.0518509447574615e-05, 1.0])
array('l', [-32767, 0, 0, 0, 32767])
Transparent? False

我让你测试其他位大小。但是在使用 float32 中间表示时,除以 (1&lt;&lt;nbits-1)-1 最多只能透明到 24 位。

另一方面,如果你想将全范围映射到全范围,你必须牺牲 0 到 0.0 的映射:

>>> [(v+0.5)/(32767.5) for v in [-32768, -1, 0, 1, 32767]]
[-1.0, -1.5259021896696422e-05, 1.5259021896696422e-05, 4.5777065690089265e-05, 1.0]

选择一种解决方案而不是另一种解决方案完全是权衡问题。在blog post by Bjorn Roche 上解释得更好,但似乎没有一个完善的约定将声音样本从有符号整数映射到浮点数并返回。而不同的硬件制造商或软件开发商似乎做出了不同的选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-23
    • 2010-12-22
    • 1970-01-01
    • 2019-06-16
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多