读取(并存储)24位采样非常简单。正如你所说的,该框架中不存在3字节整型,这意味着你只有两个选择;要么创建自己的类型,要么在样本的字节数组开头插入一个空字节(0
),从而使它们成为32位采样(因此您可以使用int
来存储/操作它们)。
我将解释并演示如何执行后者(在我看来也是更简单的方法)。
首先我们必须看一下 int
中如何存储 24位采样,
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 最高有效字节 ~ ~ 次高有效字节 ~ ~ 次低有效字节 ~ ~ 最低有效字节 ~ ~
24位采样: 11001101 01101001 01011100 00000000
32位采样: 11001101 01101001 01011100 00101001
MSB = 最高有效字节, LSB = 最低有效字节。
正如你所看到的,24位采样的LSB是0
,因此你只需要声明一个长度为4
个元素的byte[]
,然后将采样的3个字节读入该数组(从第1
个元素开始),使得你的数组如下所示(实际上是向左移动了8位):
myArray[0]: 00000000
myArray[1]: 01011100
myArray[2]: 01101001
myArray[3]: 11001101
填满字节数组之后,你可以将其传递给 BitConverter.ToInt32(myArray, 0);
,然后需要将采样向右移动8
位才能以正确的24位整数表示形式获取采样(从-8388608
到8388608
);然后除以8388608
以获得浮点值。
因此,将所有这些放在一起,你应该得到像这样的东西:
请注意,我编写以下代码时意图是“易于理解”,因此这不是最有效的方法;对于更快速的解决方案,请参见此代码下面的代码。
private List<float> Read24BitSamples(FileStream stream, int startIndex, int endIndex)
{
var samples = new List<float>();
var bytes = ReadChannelBytes(stream, Channels.Left, startIndex, endIndex);
var temp = new List<byte>();
var paddedBytes = new byte[bytes.Length / 3 * 4];
for (var i = 0; i < bytes.Length; i += 3)
{
temp.Add(0);
temp.Add(bytes[i]);
temp.Add(bytes[i + 1]);
temp.Add(bytes[i + 2]);
}
paddedBytes = temp.ToArray();
temp = null;
bytes = null;
for (var i = 0; i < paddedBytes.Length / 4; i++)
{
samples.Add(BitConverter.ToInt32(paddedBytes, i * 4) / 2147483648f);
}
return samples;
}
为了实现更快的1效果,您可以改用以下方法:
private List<float> Read24BitSamples(FileStream stream, int startIndex, int endIndex)
{
var bytes = ReadChannelBytes(stream, Channels.Left, startIndex, endIndex);
var samples = new float[bytes.Length / 3];
for (var i = 0; i < bytes.Length; i += 3)
{
samples[i / 3] = (bytes[i] << 8 | bytes[i + 1] << 16 | bytes[i + 2] << 24) / 2147483648f;
}
return samples.ToList();
}
1在将上述代码与先前方法进行基准测试后,此解决方案的速度大约快450%至550%。
dynamic
,但对于这种特定情况,必须尽可能保留 SQ,因此转换为和从浮点数将只会使 THD+N 增加更多。 - Sam