在过去的两天里,我一直试图在Android上操纵16位PCM数据,但收效甚微。我目前正在使用WAV recorder来捕获音频。在使用onPeriodicNotification(AudioRecord recorder)
写缓冲区之前的randomAccessWriter
方法中,我将缓冲区发送到自定义类,操作样本,并将样本保存回缓冲区。我的自定义类中的方法如下:
由于缓冲区是一个字节数组,我首先将它们转换为短路,现在一个短路代表一个帧(只有一个通道)。我将实现FFT算法,一旦我越过这个障碍,需要输入为浮点数组 - 所以我将每个短路转换为浮点数。现在,将数据写入WAV文件的randomAccessWriter
接受一个字节数组,并期望每个帧为2个字节。因此,我将每个float转换回short并使用ByteBuffer重建一个字节数组,然后返回该数组。当我运行我的录音机应用程序时,缓冲区通过上面的代码发送,一切都很好。
我尝试使用简单的语音调制算法来测试录音是否被修改,算法放在TODO评论的位置:
现在如果我在我的iPhone上使用上面的代码,音频样本将被转换,尽管数据本身是32位浮点数。但是,在我重新运行录音机应用程序的Android上,插入上面的代码后,产生的所有内容都是白噪声。在使用上述代码成功修改样本之前,我无法继续使用FFT算法。
为什么会这样?如果有关于该主题的知识的人能够阐明这一主题,我将不胜感激。
已解决 - 由Bjorn Roche
潜在原因:录制在Little Endian中提供数据,而Java短片在Big Endian中;当使用两种不同形式应用函数时,会产生白噪声。下面的代码显示了如何接收Little Endian字节数组,转换为Big Endian浮点数组并返回Little Endian字节数组。虽然浮动你可以随心所欲,我现在将使用我的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;
}
答案 0 :(得分:4)
你的问题是java中的short是bigendian,但如果从WAV文件中获取数据,那么数据就是小端。