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

Java 将字节[]数组的元素组合成16位数字,java,arrays,bit-manipulation,Java,Arrays,Bit Manipulation,这是音乐调谐器应用程序的代码摘录。创建字节[]数组,将音频数据读入缓冲区数组,然后for循环在缓冲区中迭代并组合索引n,n+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) | ((

这是音乐调谐器应用程序的代码摘录。创建字节[]数组,将音频数据读入缓冲区数组,然后for循环在缓冲区中迭代并组合索引
n
n+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; 
}

如果我有
101
111
,加起来应该是12,或者
1100
。然而,
101 | 111这是以低字节第一字节顺序将输入的字节流组合到内部字节顺序的短路流

对于符号扩展,更多的是原始字节流的符号编码问题。如果原始字节流是无符号的(将值从0编码到255),则克服了java将值视为有符号的不必要影响。因此,外部字节strem对无符号字节进行编码


判断代码是否合理需要处理什么外部编码和使用什么内部编码的信息。例如(胡乱猜测可能是完全错误的!):读取的两个字节的垃圾可能属于立体声编码的两个通道,为了便于内部处理,它们被放在一个单独的短字符中。您应该查看正在读取的编码以及应用程序中转换数据的使用情况。

是否有理由不使用注释
getInt()
方法。这不是我的代码——这是我在网上找到的一个应用程序(我运行并测试了它——它工作正常),我一直在尝试理解代码。除了这一部分,我对大部分内容都进行了评论,并完全理解。我觉得这段代码应该会把它搞砸,但事实并非如此,所以很明显我缺乏一些理解。签名并不重要,只要字节和短字符都不是数字。为了满足这一要求,使用位运算代替加法。rpy为您提供了一个关于为什么以及如何使用此功能的示例&0xFF确保字节的签名位不会移动到short的签名位,并保持其位置,但不会用1填充任何内容(0xFF是一个int,至少有8位用1填充,按位排列,仅确保生成的int与原始值保持8位)这可能是为什么用1 int/shortArr表示2个字节的另一个原因。在旁注中,所有这些处理都可以用对NIO缓冲区类的调用来代替,开销很小:
ByteBuffer.wrap(byteArr).order(ByteOrder.little_ENDIAN).asShortBuffer().get(shortArr)
它是44100Hz,16位采样率,1个通道,
signed=true
bigendian=false
。所有这些属性都打包到AudioFormat对象中,然后
format
被提供给
new DataLine.Info
的构造函数。打开
targetDataLine
时,它的参数为
(format,(int)sampleRate)
,这意味着每个数据块读取1秒。一旦接收到该信息并将其读入字节数组,则执行上述操作以将其转换为16位;然后,代码尝试使用我的问题中的一行代码来找出不同点的振幅之间的差异。然后很明显:外部字节流实际上是一个短串(16位值),因此代码只确保内部值反映用ByTestStream编码的值。读取的单个字节是“无符号”的,因为该值需要全部8位-不涉及符号。从中,它看起来像是
read()
将数据专门转储到字节数组中,那么为什么它会是一个短路流呢?另外,
signed=true
,所以我认为你的最后一句话对我来说没有意义。而且,在你解释之后,
初始化对我来说现在有意义了-
缓冲区[I+1]
被放在
缓冲区[I]
的左边是因为它是小尾端格式。然而,在将这个小小的endian数指定给值以及将其强制转换时。。。。我们不需要告诉编译器这个数字是“向后”写的吗?我觉得就目前的情况而言,计算机将接收二进制值,并以大端格式读取。不,代码在任何(目标)端都“做正确的事情”。它将要读取的低位字节放入目标变量的低位字节。符号性也仅对结果(组合)值有影响。生成的short将根据报头信息而不是组成字节来解释<代码>读取
始终读取字节。有趣的部分是,写了什么或者外部数据是什么。标题说明了这一点:一系列有符号的短值编码为little endian。这需要在读取时重新建立。
diff += Math.abs(a[j]-a[i+j];
/* 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
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. */