我正在将一个16位和48 kHz的单声道PCM波形文件转换为一个16位和8 kHz的单声道线性PCM AU文件,适用于使用javax.sound.sampled的电话:
public void convertSO(final String in, final String out) throws Exception {
try (final AudioInputStream ais = AudioSystem.getAudioInputStream(new File(in))) {
final AudioFormat af = new AudioFormat(Encoding.PCM_SIGNED, 8000f, 16, 1, 2, 8000, false);
try (final AudioInputStream cais = AudioSystem.getAudioInputStream(af, ais)) {
AudioSystem.write(cais, AudioFileFormat.Type.AU, new File(out));
}
}
}它的工作原理是这样的,听起来也不错,但如果我将其质量与使用SoX完成的类似转换进行比较,如下所示
sox in.wav -b 16 -r 8000 -c 1 -e signed-integer out.au使用javax.sound.sampled完成的转换的高频范围听起来很粗糙,而使用SoX则听起来相当流畅。
这两个输出文件具有相同的大小,并且它们的属性与mediainfo没有区别。
我主要想知道差异来自哪里。SoX在从48 kHz到8 kHz的采样率转换方面做得更好吗?或者SoX应用了一些花哨的滤波器或心理声学模型来改善声音质量?
发布于 2014-11-04 08:02:15
我不会接受我自己的答案作为解决方案,因为它不是一个解决方案,但对于任何感兴趣的人,我已经尝试在进行转换之前应用phrogz low pass filter:
public void convertSO(final String in, final String out) throws Exception {
try (final AudioInputStream ais = AudioSystem.getAudioInputStream(new File(in))) {
final int frameSize = ais.getFormat().getFrameSize();
if (frameSize != 2) {
throw new Exception("Works only with frame size == 2");
}
final int smoothing = 10;
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final byte[] buf = new byte[frameSize];
ais.read(buf, 0, buf.length);
int value = (buf[1] << 8) | (buf[0] & 0xff);
while (ais.read(buf, 0, buf.length) != -1) {
final int currentValue = (buf[1] << 8) | (buf[0] & 0xff);
value += (currentValue - value) / smoothing;
final byte[] smoothed = {(byte)(value & 0xff), (byte)(value >> 8)};
baos.write(smoothed);
}
final AudioInputStream smoothedAis = new AudioInputStream(new ByteArrayInputStream(
baos.toByteArray()), ais.getFormat(), baos.size() / frameSize);
final AudioFormat af = new AudioFormat(Encoding.PCM_SIGNED, 8000f, 16, 1, frameSize, 8000, false);
try (final AudioInputStream cais = AudioSystem.getAudioInputStream(af, smoothedAis)) {
AudioSystem.write(cais, AudioFileFormat.Type.AU, new File(out));
}
}
}这对我来说并不容易,因为AudioInputStream只允许你读取至少frameSize字节,也许我在每次迭代中平滑两个字节的工作很笨拙,但它是有效的,高频范围也消失了。
结果确实没有“刺激性”,但与SoX所做的转换相比也很模糊,我猜这是Ghostkeeper提到的在SoX中起作用的结转。
我现在不会尝试用Java实现它,因为我根本不理解它:-/
https://stackoverflow.com/questions/26706305
复制相似问题