将 byte[] 数组的元素组合成 16 位数字

Combining elements of a byte[] array into 16-bit numbers

这是音乐调谐器应用程序的代码摘录。创建一个 byte[] 数组,将音频数据读入缓冲区数组,然后 for 循环遍历缓冲区并组合索引 nn+1 处的值以创建一个包含 16-位数是长度的一半。

byte[] buffer = new byte[2*1200];
targetDataLine.read(buffer, 0, buffer.length)
for ( int i = 0; i < n; i+=2 ) { 
    int value = (short)((buffer[i]&0xFF) | ((buffer[i+1]&0xFF) << 8)); //**Don't understand**
    a[i >> 1] = value; 
}

到目前为止,我拥有的是:

首先,我们为什么 ORing buffer[i] | buffer[i+1] << 8?这似乎破坏了原始声音信息,除非我们以相同的方式将其拉回;虽然我知道 OR 会将它们组合成一个值,但我看不出该值在以后的计算中有何用处或用途。以后访问此数据的唯一方法是作为其文字值:

diff += Math.abs(a[j]-a[i+j];

如果我有 101111,加在一起我应该得到 12,或者 1100。然而 101 | 111 << 3 给出 111101,它等于 61。我最接近的理解是 101 (5) | 111000 (56) 是与添加 5+56=61 相同。但是顺序很重要——反过来 101 <<3 | 111 是完全不同的。我真的不明白数据如何在以这种方式进行 OR 时仍然有用。

我遇到的另一个问题是,因为Java使用有符号字节,所以第八位不表示值,而是表示符号。如果我 ORing 两个二进制有符号数,那么在生成的 16 位数字中,2⁷ 处的位现在充当值而不是占位符。如果我在 运行 和 OR 之前有一个负字节,那么在我的最终值 post-operation 中,它现在会错误地表现得好像原始数字中有一个正数 2⁷。 0xff 没有去掉这个,因为它保留了第八个带符号的字节,所以这不应该成为问题吗?

例如,1111 (-1) 和 0101,当进行或运算时,可能会得到 01011111。但是 1111 不代表 POSITIVE 1111,它代表签名版本;但在最终答案中,它现在充当正 2³。


更新:我标记了已接受的答案,但是我花了一些额外的时间来找出我哪里出错了。对于将来可能阅读本文的任何人:

<pre>/* The Javadoc explains that the targetDataLine will only read to a byte-typed array. However, because the sample size is 16-bit, it is actually storing 16-bit numbers there (shorts), auto-parsing them every eight bits. Additionally, because it is storing them in little-endian, bits [2^0,2^7] are stored in index[i] in normal order (powers <code>76543210) while bits [2^8,2^15] are stored in index[i+1]. So, together they currently read as [7-6-5-4-3-2-1-0 15-14-13-12-11-10-9-8], which is a problem. In the next for loop, we take care of this and re-organize the bytes by swapping every pair (remember the bits are ok, but the bytes are out of order). Also, although the array is signed, this will not matter when we combine bytes, because the sign-bit (2^15) will be placed back at the beginning like it normally is; although 2^7 currently exists as the most significant bit in its byte, it is not a sign-indicating bit, because it is really the middle of the short which was split. */

这是将低字节第一字节顺序的输入字节流组合到内部字节顺序的短裤流。

符号扩展更多的是原始字节流的符号编码问题。如果原始字节流是无符号的(编码值从 0 到 255),则克服了 java 将值视为有符号时的不良影响。所以有根据的猜测是外部字节 strem 编码无符号字节。

判断代码是否合理需要有关正在处理的外部编码以及使用的内部编码的信息。例如。 (疯狂的猜测可能完全错误!):读作 coud 的两个字节垃圾属于立体声编码的 2 个通道,为了便于内部处理,它们被放入单个短片中。您应该查看正在读取的编码以及应用程序中转换后数据的使用。