如果这不是一个有效的假设,那么人们如何知道文件中音频的完整动态范围是什么?(我可以读取整个文件并找出文件的实际最小和最大采样值,但是会有两个问题:(1)如果文件非常大,则这将是一个缓慢/昂贵的操作,(2)它会丢失信息,因为如果文件的创建者打算使文件具有一些“余地”,以便在最响亮的点上不以dbFS播放,则我的程序将无法检测到)
正如您所述,公共可用的文档并没有详细说明浮点数使用的范围。然而,根据过去几年在行业中的实践经验以及现有的浮点文件数据,我认为这是一个有效的假设。
实际上,对于高精度数据的归一化,如颜色、音频、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]来处理削波的浮点值。
注:所有文件的最大值均直接从样本数据中测量得出。
注:产生为剪辑浮点数(+6 dB),然后转换为有符号16位,再转回浮点数
注:剪辑到+6 dB
注:剪辑到+12 dB
可以在这里找到简单的测试脚本和文件。
[-1,+1]
,还是[-1,+1)
?
换句话说:+1
的值本身是否包含在编码值范围内? [似乎这需要为正值范围(即> 0的值)使用不同的量化步骤] - Blissnamespace 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;
}
...
}
}
因此,它只是将浮点数复制到数组中,而不对其进行任何转换,并承诺它在给定范围内。
是的。
音频文件格式作为一个或多个音频数据通道的载体。这些音频数据已经使用特定的音频编码格式进行编码。每种编码格式都使用编码器算法。算法是重要的部分。我们可以将文件和编码格式的价值置之不理。
AIFF和WAV都使用脉冲编码调制(PCM)或其后代。(如果您查看此Oracle文档, 您会注意到在"Encoding/CompressionType"下列出了基于PCM的算法列表。) PCM通过在固定时间间隔内对音频正弦波进行采样并选择最近的数字表示来工作。这里的重要点是“正弦波”。
Sine波在-1到1之间调制,因此所有基于PCM的编码都将遵循这个原则。考虑mu-law实现:请注意其defining equation中所需的范围为-1到1。