首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >音频转换的质量问题

音频转换的质量问题
EN

Stack Overflow用户
提问于 2014-11-03 08:53:06
回答 1查看 222关注 0票数 2

我正在将一个16位和48 kHz的单声道PCM波形文件转换为一个16位和8 kHz的单声道线性PCM AU文件,适用于使用javax.sound.sampled的电话:

代码语言:javascript
复制
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完成的类似转换进行比较,如下所示

代码语言:javascript
复制
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应用了一些花哨的滤波器或心理声学模型来改善声音质量?

EN

回答 1

Stack Overflow用户

发布于 2014-11-04 08:02:15

我不会接受我自己的答案作为解决方案,因为它不是一个解决方案,但对于任何感兴趣的人,我已经尝试在进行转换之前应用phrogz low pass filter

代码语言:javascript
复制
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实现它,因为我根本不理解它:-/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26706305

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档