假设 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 的好书。入门指南:
假设我有一个读取 .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 的好书。入门指南: