我必须为学校做一个小程序,通过计算两个立体声通道之间的平均值将立体声文件转换为单声道(标准16位wav)。
我有一个参考单声道文件来检查我的结果,我发现我的结果文件中有一些字节被一个位关闭(顶部文件是引用,底部是我从代码中生成的文件):
以下是我用来进行“转化”的方法的代码:
/**
*
*/
@Override
public void process() {
int byteCount = 0;
byte[] header = null;
header = _input.pop(44);
if (Convert.toInt(Arrays.copyOfRange(header, 22, 24)) == 2 && Convert.toInt(Arrays.copyOfRange(header, 34, 36)) == 16) {
byteCount = Convert.toInt(Arrays.copyOfRange(header, 40, 44));
_output.push(Arrays.copyOfRange(header, 0,4)); // ChunkID
_output.push(Convert.toByte(byteCount/2 + 36)); // ChunkSize
_output.push(Arrays.copyOfRange(header, 8, 22)); // Format & Subchunk1ID & Subchunk1Size & AudioFormat
_output.push(Convert.toByte(1)); // NumChannels
_output.push(Arrays.copyOfRange(header, 24, 28)); // SampleRate
int SampleRate = Convert.toInt(Arrays.copyOfRange(header, 24, 28));
int BitsPerSample = Convert.toInt(Arrays.copyOfRange(header, 34, 36));
_output.push(Convert.toByte(SampleRate * 1 * BitsPerSample/8)); // ByteRate (SampleRate * NumChannels * BitsPerSample/8)
_output.push(Convert.toByte(1 * Convert.toInt(Arrays.copyOfRange(header, 34, 36))/8));// BlockAlign (NumChannels * BitsPerSample/8)
_output.push(Arrays.copyOfRange(header, 34, 40)); // BitsPerSample & Subchunk2ID
_output.push(Convert.toByte(byteCount/2)); // Subchunk2Size
for (int i = 0; i < byteCount; i+=4) { // 4 bytes at a time
short left = ByteBuffer.wrap(_input.pop(2)).order(ByteOrder.LITTLE_ENDIAN).getShort();
short right = ByteBuffer.wrap(_input.pop(2)).order(ByteOrder.LITTLE_ENDIAN).getShort();
short mean = (short) ((left + right) / 2); // Mono is the mean between both channels
_output.push(ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(mean).array());
}
_input.close();
_output.close();
} else {
System.out.println("Error! The file provided is not stereo or 16-bits! Aborting...");
_input.close();
_output.close();
}
}
其中“_output.push()”和“_input.pop()”只是实用工具。它们将从/向文件返回或写入一个字节数组。 “Convert”只是一个从字节数组转换的类。
无论如何,我怀疑短路上的算术计算正在失去精度或类似的东西。知道问题来自哪里,理想情况下如何解决?
答案 0 :(得分:0)
这已在评论中提及,但我稍后会详细说明。
您正在进行2的整数除法,这将导致结果始终被截断。例如,(2+1)/2 == 3/2 == 1
为纯整数运算。这解释了您的结果比参考文件少一个的每种情况。解决它的方法是使用浮点进行中间计算:
short mean = (short)(Math.round((left + right) / 2.0f));
我不确定在您的值大于参考文件的情况下发生了什么。如果您为一个或多个案例发布左右一些样本值,我可以更新我的答案。