假设 WAV 或 AIFF 文件中的浮点样本将被规范化是否正确?

Is it correct to assume that floating-point samples in a WAV or AIFF file will be normalized?

假设我有一个读取 .WAV 或 .AIFF 文件的程序,并且文件的音频被编码为浮点样本值。我的程序假设任何格式正确的(基于浮点数的).WAV 或 .AIFF 文件将仅包含 [-1.0f,+1.0f] 范围内的样本值是否正确?我在 WAV 或 AIFF 规范中找不到解决这一点的任何内容。

如果这不是一个有效的假设,那么如何才能知道文件中音频的完整动态范围是多少? (我可以读取整个文件并找出文件的实际最小和最大样本值是多少,但是这样做有两个问题:(1)如果文件非常大,它将是 slow/expensive 操作,并且(2) 它会丢失信息,因为如果文件的创建者希望文件有一些 "headroom" 以便不在 dbFS 的最大声点播放,我的程序将无法检测到)

我知道这个问题并不特定于给定的编程语言或框架,但我无法在任何规范中找到答案。我可以肯定地说的是,在为 .NET 框架编写的应用程序中广泛用于处理 .WAV 文件的 NAudio 库假定浮点样本在 [-1.0,+1.0].

范围内

这是其 source code 中的适用代码:

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;
        }
        ...
    }
}

所以它只是将浮点数复制到数组中,而不对其进行任何转换,并保证它在给定范围内。

如您所述,public 可用文档没有详细说明用于浮点数的范围。但是,根据过去几年的行业实践以及以浮点文件形式存在的实际数据,我认为这是一个有效的假设。

这有实际原因,而且高精度数据标准化的一个非常常见的范围是颜色、音频、3D 等。

范围在区间 [-1, 1] 的主要原因是 scale/convert 到目标位范围快速且容易。您只需要提供目标范围并相乘即可。

例如:

如果你想以 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) 时表示 min/max 值。

如果您使用 [-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, and
C)截取的整数(从 A 转换而来)

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

结果证实范围确实在[-1, 1]包含范围内,当不削波(非真实<= 0 dB)。

但也揭示了另外一个方面-

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

对此的解释可能是浮点格式旨在用于生产设置的中间使用,因为动态范围的损失很小,未来的处理(增益分级、压缩、限制等)可以恢复值(无损失)在最终和正常的 -0.2 - 0 dB 范围内;因此保留原样的值。

总结

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

但是当转换为 整数 格式时,这些值 裁剪到由位缩放的等效 [-1, 1] 范围-整数格式的范围,不管。这是自然的,因为每个宽度可以容纳的范围有限。

因此,player/DAW/edit 软件将通过归一化数据或简单地裁剪回 [-1, 1] 来处理裁剪的浮点值。


注意:所有文件的最大值都是直接从样本数据中测得的。


注:生成为裁剪浮点数 (+6 dB),然后转换为带符号的 16 位并返回到浮点数


注意:削波至 +6 dB


注意:削波至 +12 dB

可以找到简单的测试脚本和文件here

是。

Audio file formats act as carriers for one or more channels of audio data. That audio data has been encoded using a particular audio coding format. Each coding format uses an encoder algorithm。算法是重要的部分。我们可以手挥手拿走文件和编码格式的值。

AIFF 和 WAV 都使用 Pulse-Code Modulation (PCM) or its descendants. (If you check out this Oracle doc,您会注意到在 "Encoding/CompressionType" 基于 PCM 的算法列表下。)PCM 通过以固定时间间隔对音频正弦波进行采样并选择最近的数字表示。这里的重点是"sine wave".

正弦波在 -1 和 1 之间调制,因此所有 PCM 派生编码都将根据此原理运行。考虑 mu-law 实现:注意其 defining equation 范围必须是 -1 到 1。

为了简短地回答这个问题,我做了很多努力。有时我们必须lie to the kids。如果您想更深入地了解浮点数与定点数、位深度对错误的重要性等,请查看一本关于 DSP 的好书。入门指南: