java 将字节数组转换为双精度数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15533854/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting Byte Array to Double Array
提问by Leandro T
I'm facing some problems with WAV files in Java.
我在 Java 中遇到了 WAV 文件的一些问题。
WAV format: PCM_SIGNED 44100.0 Hz, 24 bit, stereo, 6 bytes/frame, little-endian.
WAV 格式:PCM_SIGNED 44100.0 Hz,24 位,立体声,6 字节/帧,小端。
- I extracted the WAV data to a byte array with no problems.
- I'm trying to convert the byte array to a double array, but some doubles come with "NaN" value.
- 我将 WAV 数据提取到一个字节数组中,没有任何问题。
- 我正在尝试将字节数组转换为双精度数组,但有些双精度数组带有“NaN”值。
Code:
代码:
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);
}
The fact of being 16/24/32 bit, mono/stereo makes me confused.
16/24/32 位、单声道/立体声的事实让我感到困惑。
I intend to pass the double[] to a FFT algorithm and get the audio frequencies.
我打算将 double[] 传递给 FFT 算法并获取音频频率。
Thanks
谢谢
回答by user2813523
try this:
试试这个:
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;
}
回答by MvG
Your WAV format is 24 bit, but a double uses 64 bit. So the quantities stored in your wav can't be doubles. You have one 24 bit signed integer per frame and channel, which amounts to these 6 bytes mentioned.
您的 WAV 格式是 24 位,但双倍使用 64 位。所以存储在你的 wav 中的数量不能翻倍。每个帧和通道都有一个 24 位有符号整数,相当于提到的这 6 个字节。
You could do something like this:
你可以这样做:
private static double readDouble(ByteBuffer buf) {
int v = (byteBuffer.get() & 0xff);
v |= (byteBuffer.get() & 0xff) << 8;
v |= byteBuffer.get() << 16;
return (double)v;
}
You'd call that method once for the left channel and once for the right. Not sure about the correct order, but I guess left first. The bytes are read from least significant one to most significant one, as little-endian indicates. The lower two bytes are masked with 0xff
in order to treat them as unsigned. The most significant byte is treated as signed, since it will contain the sign of the signed 24 bit integer.
您将为左声道调用该方法一次,为右声道调用一次。不确定正确的顺序,但我想先离开。正如 little-endian 所指示的那样,字节从最低有效位到最高有效位读取。低两个字节被屏蔽,0xff
以便将它们视为无符号。最高有效字节被视为有符号字节,因为它将包含有符号 24 位整数的符号。
If you operate on arrays, you can do it without the ByteBuffer
, e.g. like this:
如果您对数组进行操作,则可以不使用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));
}
You will get samples for both channels interleaved, so you might want to separate these afterwards.
您将获得交错的两个通道的样本,因此您可能希望在之后将它们分开。
If you have mono, you won't have two channels interleaved but only once. For 16 bit you can use byteBuffer.getShort()
, for 32 bit you can use byteBuffer.getInt()
. But 24 bit isn't commonly used for computation, so ByteBuffer
doesn't have a method for this. If you have unsigned samples, you'll have to mask all signs, and to offset the result, but I guess unsigned WAV is rather uncommon.
如果您有单声道,则不会有两个通道交错,而只有一次。16 位可以使用byteBuffer.getShort()
,32 位可以使用byteBuffer.getInt()
。但是 24 位不常用于计算,因此ByteBuffer
没有用于此的方法。如果您有未签名的样本,则必须屏蔽所有符号并抵消结果,但我想未签名的 WAV 相当不常见。
回答by phuclv
For double they usually prefer values in the range [0, 1]. So you should divide each element by 224-1. Do like the answer of MvG above but with some changes
对于 double,他们通常更喜欢 [0, 1] 范围内的值。所以你应该将每个元素除以 2 24-1。喜欢上面 MvG 的答案,但有一些变化
int t = (byteArray[j ] & 0xff) |
((byteArray[j+1] & 0xff) << 8) |
(byteArray[j+2] << 16);
return t/double(0xFFFFFF);
But double is really a waste of space and CPU. I would recommend convert it to 32-bit int instead. There are many efficient way to do that by SIMD in this site
但是double真的很浪费空间和CPU。我建议将其转换为 32 位 int。在这个站点上有很多有效的方法可以通过 SIMD 来做到这一点