WAV或AIFF文件中的浮点采样值是否已经被标准化,这种假设是否正确?

20
假设我有一个读取.WAV或.AIFF文件的程序,并且该文件的音频已编码为浮点采样值。那么,我的程序是否正确假定任何格式良好(基于浮点数)的.WAV或.AIFF文件只包含范围在[-1.0f,+1.0f]之间的采样值?我在WAV或AIFF规范中找不到涉及此点的内容。
如果这不是一个有效的假设,那么人们如何知道文件中音频的完整动态范围是什么?(我可以读取整个文件并找出文件的实际最小和最大采样值,但是会有两个问题:(1)如果文件非常大,则这将是一个缓慢/昂贵的操作,(2)它会丢失信息,因为如果文件的创建者打算使文件具有一些“余地”,以便在最响亮的点上不以dbFS播放,则我的程序将无法检测到)

1
“规范化”是指“夹紧”(在这种情况下为[-1,+1])吗?在浮点数上下文中,“规范化”通常指IEEE-754浮点格式中有效数字/尾数的规范化要求。实际上,在这些浮点格式中,非常小的数据被存储为非规范化数字,这可能会在某些处理器上触发大量减速,除非将这些操作数刷新为零。 - njuffa
是的,我的意思是“落在-1.0到+1.0的范围内”。 - Jeremy Friesner
.WAV和.AIFF仅仅是指定容器格式,可以与众多音频编码格式一起使用。并不清楚数据不能超过任何支持的音频编码格式中的[-1,+1]范围。其中一些PCM定点编码似乎被限制在该范围内。 - njuffa
njuffa,你对第二段提出的问题有什么想法吗? - Jeremy Friesner
抱歉,我没有任何想法。我甚至不确定我理解第二个问题在问什么。 - njuffa
显示剩余2条评论
3个回答

12

正如您所述,公共可用的文档并没有详细说明浮点数使用的范围。然而,根据过去几年在行业中的实践经验以及现有的浮点文件数据,我认为这是一个有效的假设。

实际上,对于高精度数据的归一化,如颜色、音频、3D等,存在一个非常常见的范围。

将范围设置为区间[-1,1]的主要原因是它快速且容易缩放/转换到目标位范围。您只需要提供目标范围并进行乘法运算即可。

例如:

如果您想播放16位音频,则应执行以下操作(伪代码,假定有符号结果四舍五入到整数):

sample = in < 0 ? in * 0x8000 : in * 0x7fff;

或 24 位:

sample = in < 0 ? in * 0x800000 : in * 0x7fffff;

或8位:

sample = in < 0 ? in * 0x80 : in * 0x7f;

等等。在任何情况下,都不需要调整原始输入值即可实现转换。-1和1代表最小/最大值,当它们被转换为目标(1x = x)时。

如果你使用的范围是[-0.5,0.5],那么你首先(或在某个时候)必须调整输入值,这样转换为16位就需要额外的步骤-这具有额外的成本,不仅因为多了一步,而且因为我们将在浮点数域中工作,这是更加繁重的计算(后者可能是一个有些过时的理由,因为浮点数处理现在相当快速,但无论如何)。

in = in * 2;
sample = in < 0 ? in * 0x8000 : in * 0x7fff;

将其保持在[-1, 1]范围内,而不是一些预先缩放的范围(例如[-32768,32767]),也允许使用更多位进行精度(使用IEEE 754表示)。

更新2017/07

测试

基于评论中的问题,我决定通过使用三个带有1秒正弦波的文件进行三重检查:

A)浮点剪辑
B)浮点最大0dB,以及
C)整数剪辑(从A转换而来)

然后扫描文件以查找正值<= -1.0和>= 1.0,从data块和大小字段开始,以使最小/最大值反映在音频数据中找到的实际值。

结果证实,当不剪辑(非真实<= 0 dB)时,范围确实在[-1,1]包括范围内。

但它还揭示了另一个方面-

保存为浮点数的WAV文件确实允许超出0 dB范围的值。这意味着该范围实际上超出了[-1,1]对于通常会剪辑的值。

这可以解释为浮点格式旨在用于生产设置中的中间使用,由于动态范围损失非常小,因此未来的处理(增益分级、压缩、限制等)可以将值(无损失)带回到最终和正常的-0.2 - 0 dB范围内;因此保留值不变。

总结

使用浮点数的WAV文件在未削波(≤0dB)时会将值保存在[-1,1]中,但允许被认为是削波的值。

但是,当转换为整数格式时,这些值削波到相应的[-1,1]范围,该范围由整数格式的位范围缩放而来。这是自然的,因为每个宽度可以容纳的范围有限。

因此,播放器/DAW/编辑软件需要通过归一化数据或简单地削减至[-1,1]来处理削波的浮点值。

file1
注:所有文件的最大值均直接从样本数据中测量得出。

file2
注:产生为剪辑浮点数(+6 dB),然后转换为有符号16位,再转回浮点数

file3
注:剪辑到+6 dB

file4
注:剪辑到+12 dB

可以在这里找到简单的测试脚本和文件。


感谢您发布这个答案。 可编码值范围确实是[-1,+1],还是[-1,+1)? 换句话说:+1的值本身是否包含在编码值范围内? [似乎这需要为正值范围(即> 0的值)使用不同的量化步骤] - Bliss
这里是包含[-1,+1]的范围,这就是为什么需要两个不同的比例值(如所示)以至少保持超级准确。如果超级准确度不重要,当然可以使用[-1,+1>并使用0x7fff等来表示两个符号的正值1。话虽如此,这通常不是一个真实的问题(我只是挑剔而已):) - user1693593
@Bliss 我进行了一些测试,并将结果添加到答案中。范围是[0,1],实际上超出了这个范围,但为了保持文件无剪辑(<= 0dB,当转换为例如整数时),绝对范围是[0,1]包括在内。 - user1693593
*) 抱歉,我的意思是[-1,1]而不是[0,1]。 - user1693593
我明白了(即[0,1]是指样本的绝对值)。谢谢! - Bliss
显示剩余2条评论

3
我知道这个问题不限于任何编程语言或框架,但我在任何规范中都找不到答案。可以确定的是,广泛用于处理.NET框架应用程序中的.WAV文件的NAudio库假定浮点样本在[-1.0,+1.0]范围内。
以下是适用代码,源自源代码
namespace NAudio.Wave
{
    public class WaveFileReader : WaveStream
    {
        ...
        /// <summary>
        /// Attempts to read the next sample or group of samples as floating point normalised into the range -1.0f to 1.0f
        /// </summary>
        /// <returns>An array of samples, 1 for mono, 2 for stereo etc. Null indicates end of file reached
        /// </returns>
        public float[] ReadNextSampleFrame()
        {
            ...
            var sampleFrame = new float[waveFormat.Channels];
            int bytesToRead = waveFormat.Channels*(waveFormat.BitsPerSample/8);
            ...
            for (int channel = 0; channel < waveFormat.Channels; channel++)
            {
                if (waveFormat.BitsPerSample == 16)
                ...
                else if (waveFormat.BitsPerSample == 32 && waveFormat.Encoding == WaveFormatEncoding.IeeeFloat)
                {
                    sampleFrame[channel] = BitConverter.ToSingle(raw, offset);
                    offset += 4;
                }
                ...
            }
            return sampleFrame;
        }
        ...
    }
}

因此,它只是将浮点数复制到数组中,而不对其进行任何转换,并承诺它在给定范围内。


1

是的。

音频文件格式作为一个或多个音频数据通道的载体。这些音频数据已经使用特定的音频编码格式进行编码。每种编码格式都使用编码器算法。算法是重要的部分。我们可以将文件和编码格式的价值置之不理。

AIFF和WAV都使用脉冲编码调制(PCM)或其后代。(如果您查看此Oracle文档, 您会注意到在"Encoding/CompressionType"下列出了基于PCM的算法列表。) PCM通过在固定时间间隔内对音频正弦波进行采样并选择最近的数字表示来工作。这里的重要点是“正弦波”。

Sine波在-1到1之间调制,因此所有基于PCM的编码都将遵循这个原则。考虑mu-law实现:请注意其defining equation中所需的范围为-1到1。
我必须进行很多揣测来简要回答这个问题。有时我们必须 向孩子们说谎。如果您想深入了解浮点数与定点数、位深度对误差的重要性等,请查阅一本好的DSP书籍。以下是一些入门资料:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接