gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 08:39:16 29 4
gpt4 key购买 nike

这是音乐调谐器应用程序中的代码摘录。创建一个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;
}


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


a different SO post中,我了解到,以较大类型存储的每个字节都必须是0xFF的 &,这是因为它将转换为32位数字。我想前24位用 1填充(尽管我不知道为什么它不用零填充...不能用 1开头改变数字的值吗? 000000000010 (2)毕竟与 111111110010(-14)不同),因此 0xff的目的是仅获取最后8位(即整个字节)。
buffer[i+1]向左移动8位时,这使得 OR时,来自 buffer[i+1]的八位位于最高有效位,而来自 buffer[i]的八位位于最低有效位。八位。我们最后得到一个格式为 buffer[i+1] + buffer[i]的16位数字。 (我正在使用 +,但我知道它更接近串联。)


首先,为什么我们要 OR ing 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完全不同。我真的不明白当以这种方式对数据进行或运算时,数据如何保持有用。

我遇到的另一个问题是,因为Java使用带符号的字节,所以第八个位置不是指示值,而是指示符号。如果我要对两个二进制有符号数进行 OR运算,则在生成的16位数字中,2 at处的位现在用作值而不是占位符。如果在运行 OR之前我有一个负字节,那么在我的最终值后运算中,它现在会错误地表现为原始数字中包含正2⁷。 0xff不会消除它,因为它保留了第八个带符号的字节,所以这不是问题吗?

例如, 1111(-1)和 0101在进行“或”运算时可能会给出 01011111。但是 1111并不代表POSITIVE 1111,而是代表签名版本;但在最后的答案中,它现在是正2³。



更新:我标记了可接受的答案,但是这花了一点点额外的工作才能弄清楚我哪里出了问题。对于以后可能会阅读此书的任何人:


就签名而言,我拥有的代码使用签名字节。我对此唯一的猜测是,为什么接收到的所有值都可能是正号。除了没有意义外,给定波形的幅度从[-1,1]变化。我将尝试解决这个问题。如果存在负号,则在执行ORing时,此处的代码实现似乎不会删除 1,因此我怀疑它不会对计算产生太大影响(假设我们正在处理非常大的值(< cc>表示 diff +=会很大-考虑到代码及其所依赖的比较,另外几个 diff不应损害结果。所以这全都错了。我给了它更多的思考,确实很简单,实际上-这是一个问题的唯一原因是因为我不知道big-endian,然后一旦我读到它,我就误解了它的实现方式。
关于位的放置顺序,破坏声音等。我正在使用的代码设置了 1,这意味着字节顺序从最低有效字节到最高有效字节。因此,将 bigEndian=false的两个索引相结合需要使用第二个索引,将其位放置在第一位,然后将第一个索引放置在第二个位置(因此,我们现在处于big-endian字节顺序)。我遇到的问题之一是印象,即“字节顺序”决定了位顺序。我以为 buffer大端将成为 10010101小端。事实并非如此-每个字节中的位保持原始顺序;区别在于字节是“向后”排序的。因此 10101001 big-endian变为 10110101 111000001-每个字节中的位顺序相同;但是,字节顺序不同。
最后,我不确定为什么,但是接受的答案是正确的: 11100001 10110101可能仅将这些位放入字节数组中(不仅在我的代码中,而且在所有使用targetDataLine的Java代码中- targetDataLine.read()仅接受参数其中目标var是字节数组),但实际上数据是一个 read()分成两个 short。因此,每两个索引必须合并在一起。
回到签名,到现在为止为什么这不是问题已经很明显了。这是我现在在代码中的注释,它更连贯地解释了之前所有这些^解释的内容:


byte
/* 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. */

最佳答案

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

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

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

关于java - 将byte []数组的元素组合成16位数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36252466/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com