Java 有符号16位PCM变换是';不起作用。为什么?

Java 有符号16位PCM变换是';不起作用。为什么?,java,android,audio,pcm,Java,Android,Audio,Pcm,在过去的两天里,我一直在尝试在Android上操作16位PCM数据,但收效甚微。我目前正在使用它来捕获音频。在使用randomAccessWriter写入缓冲区之前,在onPeriodicNotification(录音机)方法中,我将缓冲区发送到自定义类,以操作样本,并将样本保存回缓冲区。我的自定义类中的方法如下所示: 由于缓冲区是一个字节数组,我首先将它们转换为短字符,现在一个短字符表示一个帧(只有一个通道)。一旦我越过这个障碍,我将实现FFT算法,它需要输入一个浮点数组,所以我将每个短的转换

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

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

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

现在,如果我在我的iPhone上使用上述代码,音频样本将被转换,尽管数据本机为32位浮点。然而,在Android上,当我重新运行recorder应用程序时,插入了上面的代码,所产生的只是白噪声。除非我能用上面的代码成功地修改样本,否则我不能继续我的FFT算法

为什么会发生这种情况?如果有人对这一主题有了解,我将不胜感激

已解决-由比约恩·罗氏公司解决

根本原因:录制是以小尾端给出数据,而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;

}
public byte[]操作示例(byte[]数据,
整数抽样,
int numFrames,
短数字通道){
//将字节[]转换为短[](16位)到浮点[](32位)(最终结果:Big-Endian)
ShortBuffer sbuf=ByteBuffer.wrap(data.asShortBuffer();
short[]audioShorts=新的short[sbuf.capacity()];
sbuf.get(音频短片);
float[]audioFloats=新的float[audioShorts.length];
对于(int i=0;i你的问题是java中的短裤是双二进制的,但是如果你从WAV文件中得到数据,数据是很少的。你应该把你放进去的东西拿出来。我可以建议写一些单元测试吗?您还可以尝试使用调试器单步执行此操作。我会特别注意将浮点除以整数(
(float)audioShorts[I])/0x8000
)。我一时记不起Java的升级规则,但这似乎是一个合理的原因。尝试将其重新命名为
(float)audioShorts[i])/32768.0f
。你可能在另一个方向也有同样的问题。谢谢你的输入,我试过中间没有任何处理,数据通过了,我也试过你的建议,噪音仍然存在。我对为什么会发生这种情况感到困惑,因为我不知道为什么会发生这种情况,我无法编写任何junit测试。在尝试这么复杂的测试之前,你应该尝试一些简单的方法,比如除以2。我也尝试过,而不是数学。sin(θ)I*=0.5。结果是白噪声。我是否可以将它们转换成小端,对样本进行转换,然后返回到大端(正如RandomAccessWriter所期望的),或者我必须保存wav文件,然后重新打开它,然后对样本执行我想执行的操作?等等,我只是重新阅读了你所说的。数据已经在Big-Endian中,数据正在从麦克风记录。因此,我不应该以我正在尝试的方式进行转换吗?我可能错过了它,但是查看wav记录器的代码,我没有看到录制和写入文件之间的任何字节交换。这意味着录制的endian与文件的endian相同,而WAV文件是little endian,因此录制的是little endian。为什么不尝试交换字节,除以2,然后交换回字节呢。你会知道它是否有效。我非常感谢你,我的困惑来自于使用ByteBuffers的order()函数和使用Byte.BIG_ENDIAN和Byte.LITTLE_ENDIAN,但这些都失败了。相反,我把单条短裤倒过来,效果很好。谢谢