有符号的 16 位 PCM 转换不起作用。为什么?

Joh*_*ale 4 java audio android pcm

在过去的两天里,我一直试图在 Android 上操作 16 位 PCM 数据,但收效甚微。我目前正在使用WAV 录音机来捕捉音频。在onPeriodicNotification(AudioRecord recorder)写入缓冲区之前的方法中,randomAccessWriter我将缓冲区发送到自定义类,以操作样本,并将样本保存回缓冲区。我的自定义类中的方法如下:

由于缓冲区是一个字节数组,我首先将它们转换为 shorts,现在一个 short 表示一帧(只有一个通道)。我将实施 FFT 算法,一旦我克服了这个障碍,需要输入是一个浮点数组 - 所以我将每个空头转换为一个浮点数。现在,randomAccessWriter将数据写入 WAV 文件的 接受一个字节数组并期望每帧为 2 个字节。因此,我将每个浮点数转换回 short 并使用 ByteBuffer 重建一个字节数组,然后返回该数组。当我运行我的记录器应用程序时,通过上面的代码发送缓冲区,一切都很好。

我尝试使用一个简单的语音调制算法来测试录音是否被修改,该算法放置在 TODO 注释所在的位置:

现在,如果我在 iPhone 上使用上述代码,音频样本将被转换,尽管数据本身是 32 位浮点数。但是,在 Android 上,当我重新运行记录器应用程序并插入上述代码时,产生的只是白噪声。在我可以使用上述代码成功修改样本之前,我无法继续使用我的 FFT 算法。

为什么会出现这种情况?如果有关于该主题的知识的人可以阐明该主题,我将不胜感激。

已解决 - 比约恩·罗奇 (Bjorn Roche)

根本原因:录制以小端格式提供数据,而 Java 短片以大端格式提供;当应用使用两种不同形式的函数时,会产生白噪声。下面的代码显示了如何接收小端字节数组,转换为大端浮点数组并返回小端字节数组。虽然浮动你可以做任何你想做的事情,我现在将使用我的 FFT 算法:

public byte[] manipulateSamples(byte[] data,
                                int samplingRate,
                                int numFrames,
                                short numChannels) {

    // Convert byte[] to short[] (16 bit) to float[] (32 bit) (End result: Big Endian)
    ShortBuffer sbuf = ByteBuffer.wrap(data).asShortBuffer();
    short[] audioShorts = new short[sbuf.capacity()];
    sbuf.get(audioShorts);

    float[] audioFloats = new float[audioShorts.length];

    for (int i = 0; i < audioShorts.length; i++) {
        audioFloats[i] = ((float)Short.reverseBytes(audioShorts[i])/0x8000);
    }

    // Do your tasks here.

    // Convert float[] to short[] to byte[] (End result: Little Endian)
    audioShorts = new short[audioFloats.length];
    for (int i = 0; i < audioFloats.length; i++) {
        audioShorts[i] = Short.reverseBytes((short) ((audioFloats[i])*0x8000));
    }

    byte byteArray[] = new byte[audioShorts.length * 2];
    ByteBuffer buffer = ByteBuffer.wrap(byteArray);
    sbuf = buffer.asShortBuffer();
    sbuf.put(audioShorts);
    data = buffer.array();

    return data;

}
Run Code Online (Sandbox Code Playgroud)

Bjo*_*che 5

您的问题是 java 中的 shorts 是 bigendian,但是如果您从 WAV 文件中获取数据,则数据是 little endian。