[英]Converting Byte Array to Double Array
我在 Java 中遇到了 WAV 文件的一些问题。
WAV 格式:PCM_SIGNED 44100.0 Hz,24 位,立体声,6 字节/帧,小端。
NaN
值。代码:
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
double[] doubles = new double[byteArray.length / 8];
for (int i = 0; i < doubles.length; i++) {
doubles[i] = byteBuffer.getDouble(i * 8);
}
16/24/32 位、单声道/立体声的事实让我感到困惑。
我打算将double[]
传递给 FFT 算法并获取音频。
试试这个:
public static byte[] toByteArray(double[] doubleArray){
int times = Double.SIZE / Byte.SIZE;
byte[] bytes = new byte[doubleArray.length * times];
for(int i=0;i<doubleArray.length;i++){
ByteBuffer.wrap(bytes, i*times, times).putDouble(doubleArray[i]);
}
return bytes;
}
public static double[] toDoubleArray(byte[] byteArray){
int times = Double.SIZE / Byte.SIZE;
double[] doubles = new double[byteArray.length / times];
for(int i=0;i<doubles.length;i++){
doubles[i] = ByteBuffer.wrap(byteArray, i*times, times).getDouble();
}
return doubles;
}
public static byte[] toByteArray(int[] intArray){
int times = Integer.SIZE / Byte.SIZE;
byte[] bytes = new byte[intArray.length * times];
for(int i=0;i<intArray.length;i++){
ByteBuffer.wrap(bytes, i*times, times).putInt(intArray[i]);
}
return bytes;
}
public static int[] toIntArray(byte[] byteArray){
int times = Integer.SIZE / Byte.SIZE;
int[] ints = new int[byteArray.length / times];
for(int i=0;i<ints.length;i++){
ints[i] = ByteBuffer.wrap(byteArray, i*times, times).getInt();
}
return ints;
}
您的 WAV 格式是 24 位,但双倍使用 64 位。 所以存储在你的 wav 中的数量不能翻倍。 每个帧和通道都有一个 24 位有符号整数,相当于提到的这 6 个字节。
你可以这样做:
private static double readDouble(ByteBuffer buf) {
int v = (byteBuffer.get() & 0xff);
v |= (byteBuffer.get() & 0xff) << 8;
v |= byteBuffer.get() << 16;
return (double)v;
}
您将为左声道调用该方法一次,为右声道调用一次。 不确定正确的顺序,但我想先离开。 正如 little-endian 所指示的那样,字节从最低有效位到最高有效位读取。 低两个字节用0xff
屏蔽,以便将它们视为无符号。 最高有效字节被视为有符号字节,因为它将包含有符号 24 位整数的符号。
如果您对数组进行操作,则可以在没有ByteBuffer
情况下进行操作,例如:
double[] doubles = new double[byteArray.length / 3];
for (int i = 0, j = 0; i != doubles.length; ++i, j += 3) {
doubles[i] = (double)( (byteArray[j ] & 0xff) |
((byteArray[j+1] & 0xff) << 8) |
( byteArray[j+2] << 16));
}
您将获得交错的两个通道的样本,因此您可能希望在之后将它们分开。
如果您有单声道,则不会有两个通道交错,而只有一次。 对于 16 位,您可以使用byteBuffer.getShort()
,对于 32 位,您可以使用byteBuffer.getInt()
。 但是 24 位不常用于计算,因此ByteBuffer
没有用于此的方法。 如果您有未签名的样本,则必须屏蔽所有符号并抵消结果,但我想未签名的 WAV 相当不常见。
对于 DSP 中的浮点类型,它们通常更喜欢 [0, 1] 或 [0, 1) 范围内的值,因此您应该将每个元素除以 2 24 -1。 喜欢上面 MvG 的答案,但有一些变化
int t = ((byteArray[j ] & 0xff) << 0) |
((byteArray[j+1] & 0xff) << 8) |
(byteArray[j+2] << 16);
return t/double(0xFFFFFF);
但是对于数据处理而言, double
确实浪费了空间和 CPU 。 我建议将其转换为 32 位 int,或具有相同精度(24 位)但范围更大的float
。 实际上,当您进行音频或视频处理时,32 位 int 或 float 是数据通道的最大类型
最后,您可以利用多线程和SIMD来加速转换
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.