假设我有一个读取.WAV或.AIFF文件的程序,该文件的音频被编码为浮点样本值。我的程序假设任何格式良好(基于浮点的).WAV或.AIFF文件只包含[-1.0f,+ 1.0f]范围内的样本值是否正确?我找不到解决这一问题的WAV或AIFF规范中的任何内容。
如果这不是一个有效的假设,那么如何才能知道文件中音频的完整动态范围是什么? (我可以读取整个文件并找出文件的实际最小和最大样本值是什么,但是有两个问题:(1)如果文件非常大,那将是一个缓慢/昂贵的操作,(2) )它会丢失信息,因为如果文件的创建者打算让文件有一些“余量”,以免在dbFS最大点播放,我的程序将无法检测到这一点)
答案 0 :(得分:7)
正如您所述,公共可用文档不会详细介绍浮点使用的范围。但是,根据过去几年的行业实践,以及作为浮点文件存在的实际数据,我认为这是一个有效的假设。
这有实际的原因以及高精度数据标准化的常见范围,如彩色,音频,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转换)
然后在data
块和大小字段之后开始扫描正值&lt; = -1.0和&gt; = 1.0的文件,以使min / max值反映在音频数据中找到的实际值。< / p>
当不削波(非真&lt; = 0 dB)时,结果证实该范围确实在[-1,1]包含范围内。
但它也揭示了另一个方面 -
保存为浮点的的WAV文件允许超过0 dB范围的值。这意味着对于通常会剪辑的值,范围实际上超出[-1,1]。
对此的解释可能是浮点格式旨在用于生产设置中的中间使用,因为动态范围的损失非常小,未来的处理(增益分段,压缩,限制等)可以带回值(没有损失)在最终和正常-0.2 - 0 dB范围内;因此保留了原样。
使用浮点的WAV文件将在不裁剪时(&lt; = 0dB)保存[-1,1]中的值,但允许被视为裁剪的值
但是当转换为整数格式时,这些值将剪辑到由整数格式的位范围缩放的等效[-1,1]范围,无论。由于每个宽度可以容纳的范围有限,这是很自然的。
通过标准化数据或简单地剪回[-1,1],播放器/ DAW /编辑软件可以处理剪切的浮点值。
注意:所有文件的最大值都是直接从样本数据中测量的。
注意:产生为限幅浮点数(+6 dB),然后转换为带符号的16位并返回浮点数
注意:剪辑为+6 dB
注意:剪辑为+12 dB
可以找到简单的测试脚本和文件here。
答案 1 :(得分:3)
我知道问题不是特定于给定的编程语言或框架,但我在任何规范中都找不到答案。我可以肯定地说,广泛用于处理为.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;
}
...
}
}
所以它只是将float复制到数组中而不对其进行任何转换,并保证它在给定的范围内。
答案 2 :(得分:1)
是强>
Audio file formats充当一个或多个音频数据通道的载体。该音频数据已使用特定audio coding format进行编码。每种编码格式都使用encoder algorithm。算法是重要的部分。我们可以挥手消除文件和编码格式的价值。
AIFF和WAV都使用Pulse-Code Modulation (PCM)或其后代。 (如果您查看此Oracle doc,您会注意到在“Encoding / CompressionType”基于PCM的算法列表下。)PCM通过以固定的时间间隔对音频正弦波进行采样并选择最近的数字表示来工作。这里重要的是“正弦波”。
正弦波在-1和1之间调制,因此所有PCM衍生编码都将按此原理运行。考虑mu-law实现:在defining equation中注意,范围必须是-1到1.
我正在做很多动手,简短地回答这个问题。有时我们必须lie to the kids。如果你想更深入地研究浮点与定点,比特深度对错误的重要性等,请查阅一本关于DSP的好书。为了帮助您入门: