在过去的两天里,我一直试图在Android上操作16位PCM数据,但收效甚微.我目前正在使用WAV recorder捕获音频.在使用randomAccessWriter编写缓冲区之前,在onPeriodicNotification(AudioRecordrecorder)方法中,我将缓冲区发送到自定义类,以处理样本,并将样本保存回缓冲区中.我的自定义类中的方法如下:
由于缓冲区是一个字节数组,因此我首先将它们转换为短裤,现在一个短裤代表一帧(只有一个通道).一旦克服了这一障碍,我将实现FFT算法,该算法需要输入为float数组-因此我将每个short转换为float.现在,将数据写入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;
}
解决方法:
您的问题是Java中的短裤是bigendian,但是如果您从WAV文件中获取数据,则数据是little endian.