【问题标题】:Convert signed int (2bytes, 16 bits) in double format. With Java将带符号的 int(2 字节,16 位)转换为双精度格式。使用 Java
【发布时间】:2011-01-06 15:04:19
【问题描述】:

我有一个问题。 在 Java 中,我需要从 wav 文件中读取样本。 文件格式为:wav, PCM_SIGNED, signed int of 2bytes = 16bits, little endian... 该对象读取 BYTES 中的音频样本,我需要将这两个字节转换为一个双精度值。 我尝试使用这个公式,但它并不完全正确:

mono = (double)((audioBytes[k] & 0xFF) | (audioBytes[k + 1] << 8));

将结果与 Matlab 进行比较,我总是注意到 Matlab 中的实际值与 Java 中转换后的值之间的差异。 有人可以帮我吗? 谢谢, 戴夫

【问题讨论】:

  • 你有一个短字节序列的例子,你的预期输出是什么,你的实际输出是什么?
  • 如果audioBytes[k]是一个字节,audioBytes[k] & 0xFF == audioBytes[k],所以掩码没用。
  • 如果 audioBytes[k] == -1, audioBytes[k] & 0xFF == 255(在我将结果传递给 System.out.println 之后)。
  • 你是对的,我错了......而且很尴尬:)
  • 这是我在 Matlab 中的期望值:-3.295876945438848e-05,而在 Java 中是:-3.0517578125E-5。奇怪的事实是 Matlab*32768 = -1.0800 而 Java*32768 = .1

标签: java double wav signed pcm


【解决方案1】:

您没有向我们提供足够的信息来了解为什么您在 Matlab 和 Java 中得到不同的结果。通常,您将短通道数据 [-32768..32767] 缩放为范围 [-1..1] 的两倍,看起来您正在尝试这样做。您的 java 结果:-3.0517578125E-5 对于短值 -1 是正确的:-1/32768。我不知道为什么你的 Matlab 结果不同。您还没有向我们展示您是如何得出 Matlab 结果的。

如果你有一个大字节序列(我猜你有),并且你不想担心 BIG-ENDIAN 与 LITTLE-ENDIAN 或移位位和字节,让 java 来处理它你:

import java.nio.*;
...
ByteBuffer buf = ByteBuffer.wrap(audioBytes);
buf.order(ByteOrder.LITTLE_ENDIAN);

while (buf.remaining() >= 2) {
    short s = buf.getShort();
    double mono = (double) s;
    double mono_norm = mono / 32768.0;
    ...
}

ByteBuffer.getShort() 读取缓冲区的下两个字节,处理 Little-Endian 排序,将字节转换为短字节,并为下一次 getXXX() 调用定位。

【讨论】:

  • 我觉得这个方法最好。
  • 这真的取决于你在 MATLAB 中做什么。你在运行什么代码/命令?
【解决方案2】:

这是正确的方法:

double sampleValue = (double)(( bytes[0]<<8 ) | ( bytes[1]&0x00FF ));

(更改索引以交换小/大)

【讨论】:

    【解决方案3】:

    你不能只做 most_significant byte * 256 + least_significant_byte 然后转换为 double 吗?

    【讨论】:

    • 我不会这么认为,因为 Java 中的字节值是从 -128 到 127。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多