2014-11-03 120 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實現,因爲我根本不明白這一點: -/