将字节数组转换为双数组
我在Java中遇到了一些WAV文件的问题。将字节数组转换为双数组
WAV格式:PCM_SIGNED 44100.0赫兹,24位,立体声,6字节/帧,小端。
- 我将WAV数据提取到一个没有问题的字节数组中。
- 我试图将字节数组转换为双数组,但有些双打来与“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算法并获取音频。
感谢
你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是不常见的。
谢谢,我会检查这个! – 2013-03-21 11:38:57
尝试:
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;
}
对于双它们通常在范围偏爱值[0,1]。所以你应该把每个元素除以2 -1。做像上面的MvG的答案,但有一些变化
int t = (byteArray[j ] & 0xff) |
((byteArray[j+1] & 0xff) << 8) |
(byteArray[j+2] << 16);
return t/double(0xFFFFFF);
但是双重真的是浪费空间和CPU。我建议将其转换为32位整数。有许多有效的方法来做到这一点SIMD本网站
你的代码看起来有点混乱。你在循环内赋值为't',但不赋予'双精度'。所以最后你要得到的是最后一个采样的整数值,存储在't'中。你划分,但'double(0xFFFFFF)'不是有效的Java; '(双)0xFFFFFF'是。 – MvG 2013-09-25 08:45:17
@MvG对不起,我的意思是在一个循环。编辑 – 2013-09-25 08:47:37
听起来像一些这些数字实际上不能解释为'double' ... – 2013-03-20 20:22:52
复制以http://计算器。com/questions/2905556/how-can-i-convert-a-byte-array-into-a-two-and-back? – maszter 2013-03-20 20:24:44
@maszter:不是重复的,因为字节不代表双打。 – MvG 2013-03-20 22:33:49