【发布时间】:2022-01-22 22:18:00
【问题描述】:
我正在尝试在android上使用AudioRecord录制音频并将左右声道录音分成两个不同的文件,然后将其转换为wav以便能够在手机上播放。但是录制的文件速度很快,而且音高高。
我阅读了所有示例并编写了这段代码,但我不确定是哪个部分导致了问题。
这是我的 AudioRecord 定义。
minBufLength = AudioTrack.getMinBufferSize(48000,AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 48000, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufLength);
然后我读取短数据,然后将短数据转换为字节并最终将其分离为两个通道的字节数组。
shortData = new short[minBufLength/2];
int readSize = recorder.read(shortData,0,minBufLength/2);
byte bData[] = short2byte(shortData);
for(int i = 0; i < readSize/2; i++)
{
final int offset = i * 2 * 2; // two bytes per sample and 2 channels
rightChannelFos.write(bData, offset , 2);
leftChannelFos.write(bData, offset + 2 , 2 );
}
File rightChannelF1 = new File("/sdcard/rightChannelaudio"); // The location of your PCM file
File leftChannelF1 = new File("/sdcard/leftChannelaudio"); // The location of your PCM file
File rightChannelF2 = new File("/sdcard/rightChannelaudio.wav"); // The location where you want your WAV file
File leftChannelF2 = new File("/sdcard/leftChannelaudio.wav"); // The location where you want your WAV file
rawToWave(rightChannelF1, rightChannelF2);
rawToWave(leftChannelF1, leftChannelF2);
// convert short to byte
private byte[] short2byte(short[] sData) {
int shortArrsize = sData.length;
byte[] bytes = new byte[shortArrsize * 2];
for (int i = 0; i < shortArrsize; i++) {
bytes[i * 2] = (byte) (sData[i] & 0x00FF);
bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
sData[i] = 0;
}
return bytes;
}
这是 rawToWave 函数。我没有包含其他写入函数以保持帖子简单。
private void rawToWave(final File rawFile, final File waveFile) throws IOException {
byte[] rawData = new byte[(int) rawFile.length()];
DataInputStream input = null;
try {
input = new DataInputStream(new FileInputStream(rawFile));
input.read(rawData);
} finally {
if (input != null) {
input.close();
}
}
DataOutputStream output = null;
try {
output = new DataOutputStream(new FileOutputStream(waveFile));
// WAVE header
// see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
writeString(output, "RIFF"); // chunk id
writeInt(output, 36 + rawData.length); // chunk size
writeString(output, "WAVE"); // format
writeString(output, "fmt "); // subchunk 1 id
writeInt(output, 16); // subchunk 1 size
writeShort(output, (short) 1); // audio format (1 = PCM)
writeShort(output, (short) 2); // number of channels
writeInt(output, 48000); // sample rate
writeInt(output, 48000 * 2); // byte rate
writeShort(output, (short) 2); // block align
writeShort(output, (short) 16); // bits per sample
writeString(output, "data"); // subchunk 2 id
writeInt(output, rawData.length); // subchunk 2 size
// Audio data (conversion big endian -> little endian)
short[] shorts = new short[rawData.length / 2];
ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
for (short s : shorts) {
bytes.putShort(s);
}
output.write(fullyReadFileToBytes(rawFile));
} finally {
if (output != null) {
output.close();
}
}
}
更新:
我将其添加为更新,以防其他人遇到此类问题。由于某种我不明白的原因,频道更新循环无法纠正。所以我分别更新了每个通道的字节数组。现在因为它是一个 16 位方案,所以这意味着每个样本有 2 个字节,所以来自原始数据的样本是这种格式 [LL][RR][LL][RR] 这就是为什么循环应该基于以下
for(int i = 0; i < readSize; i= i + 2)
{
leftChannelAudioData[i] = bData[2*i];
leftChannelAudioData[i+1] = bData[2*i+1];
rightChannelAudioData[i] = bData[2*i+2];
rightChannelAudioData[i+1] = bData[2*i+3];
}
【问题讨论】:
-
什么是
short2byte?为什么要使用尽可能小的缓冲区长度? -
输出文件的格式是什么?如果它们是“立体声”,那么您需要为每个样本编写两次(左右声道)
-
对不起,我刚刚更新了代码并添加了 short2bye 功能。我不确定缓冲区的值应该是多少,所以我使用了基于采样频率的最小可能值。
-
我不确定您所说的文件格式是什么意思。我只想将两个通道分开,这样我就可以保存两个具有相同数据的文件,每个麦克风一个(因此录制立体声)。