20

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

如果这不是一个有效的假设,那么如何知道文件中音频的完整动态范围是什么?(我可以阅读整个文件并找出文件的实际最小和最大样本值是多少,但是有两个问题:(1)如果文件非常大,这将是一个缓慢/昂贵的操作,以及(2 ) 它会丢失信息,因为如果文件的创建者打算让文件有一些“净空”,以免在 dbFS 的最大声点播放,我的程序将无法检测到)

4

3 回答 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] 来处理剪辑的浮点值。

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

文件2
注:产生为削波浮点 (+6 dB),然后转换为有符号 16 位并返回浮点

文件 3
注释:削波至 +6 dB

文件4
注释:削波至 +12 dB

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

于 2015-04-30T01:00:40.927 回答
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;
        }
        ...
    }
}

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

于 2015-04-28T19:31:55.030 回答
1

是的。

音频文件格式充当一个或多个音频数据通道的载体。该音频数据已使用特定的音频编码格式进行编码。每种编码格式都使用一种编码器算法。算法是重要的部分。我们可以放弃文件和编码格式的价值。

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

正弦波在 -1 和 1 之间调制,因此所有 PCM 派生的编码都将按照此原理运行。考虑 mu-law 的实现:注意在其定义方程中,范围需要为 -1 到 1。

我做了很多挥手来简要回答这个问题。有时我们必须对孩子撒谎。如果您想更深入地研究浮点与定点、位深度对错误的重要性等,请查看一本关于 DSP 的好书。为了让你开始:

于 2015-04-30T02:51:18.913 回答