2014-11-03 93 views
2

我转换与16位单声道PCM波形文件和48 kHz至单质量问题签署了16位,并适用于电话8kHz的线性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是否应用了一些奇特的过滤器或心理声学模型来改善音质?

+3

更好的程序可能会做的抽样前过滤掉高频噪声。如果没有完成,它将围绕新的采样频率(它本身处于可听范围!)。你可以尝试用大胆的东西来观察光谱能量。你也可以记录从1-24 KHz的斜坡,看看每个程序用它做什么 - 理想情况下,你应该得到一个斜坡到3.5 KHz,然后褪去任何东西。相反,如果您获得了一系列反射斜坡,则转换过程不会进行别名过滤。 – 2014-11-03 02:12:27

+1

在SoX中执行缩减采样的源代码在这里:http://sourceforge.net/p/sox/code/ci/master/tree/src/downsample.c它没有很好的记录,但它看起来像他们使用'p-> carry'中样本之间的某种结转。这可能是原因。 – Ghostkeeper 2014-11-03 02:27:26

回答

0

我不会接受我自己的答案是解决方案,因为它不是一个解决方案,但有兴趣的人士,我曾尝试做转换之前申请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实现,因为我根本不明白这一点: -/