【问题标题】:How do I convert audio from one format to wav or raw in Java?如何在 Java 中将音频从一种格式转换为 wav 或 raw?
【发布时间】:2020-03-10 21:53:26
【问题描述】:

我试图弄清楚如何使用java.sound api 将 WAV 文件转换为 RAW/PCM 格式。我需要将 WAV 文件从某种给定的音频格式转换为编码如下的 RAW 文件:

  • 16 kHz
  • 16 位
  • 单声道
  • 已签名
  • 小端序

我在这里找到的许多帖子都是相反的,即如何从 RAW 获取 WAV。作为音频新手,我希望有人可以发布一个示例来说明如何做到这一点。

【问题讨论】:

  • 你能用一句话概括你的问题是什么,或者你到底在努力解决什么问题吗?
  • 如果您说您已经解决了自己的问题,您可以将解决方案作为答案发布,而不是在问题中发布吗? (我理解正确吗?)
  • 您是否有效地询问如何创建一个文件,该文件是另一个文件的副本,但删除了前 44 个字节?
  • @andrewjames 对于发布堆栈溢出问题我还是个新手。现在好些了吗?

标签: java audio wav pcm


【解决方案1】:

据我所知,Java 声音 api 不会转换为 RAW 音频。它确实转换为 WAV,即RAW audio with a 44-byte header。一旦你理解了这一点,你就可以把问题分解成两部分:

1.将音频从任何格式转换为 WAV 格式。

下面的代码示例仅在 WAV 到 WAV(不同的音频格式)之间进行了测试,但理论上对 AudioSystem.getAudioInputStream(audioFormat, originalAudioStream); 的调用应该会找到合适的编解码器(如果有的话)。

此方法会将音频字节转换为给定的格式,并生成一个 byte[] 结果作为 WAV。

 private static final AudioFormat EXAMPLE_FORMAT = new AudioFormat(
        16_000,
        16,
        1,
        true,
        false
    );

    public byte[] formatAudioToWav(@NotNull final byte[] audioFileContent,
                                   @NotNull final AudioFormat audioFormat) throws
                                                                           IOException,
                                                                           UnsupportedAudioFileException {

        try (
            final AudioInputStream originalAudioStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(audioFileContent));
            final AudioInputStream formattedAudioStream = AudioSystem.getAudioInputStream(audioFormat, originalAudioStream);
            final AudioInputStream lengthAddedAudioStream = new AudioInputStream(formattedAudioStream, audioFormat, audioFileContent.length);
            final ByteArrayOutputStream convertedOutputStream = new ByteArrayOutputStream()
        ) {
            AudioSystem.write(lengthAddedAudioStream, AudioFileFormat.Type.WAVE, convertedOutputStream);
            return convertedOutputStream.toByteArray();
        }
    }

2。从步骤 1 中创建的 WAV 文件中去除标题。

   public byte[] formatWavToRaw(@NotNull final byte[] audioFileContent) {
        return Arrays.copyOfRange(audioFileContent, 44, audioFileContent.length);
    }

备注

  • 该代码的优点是可以正确关闭所有流,但缺点是直接使用 byte[],因此不适用于大文件。它可以转换为纯流,但请注意,在对new AudioInputStream(formattedAudioStream, audioFormat, audioFileContent.length); 的调用中,您需要其中一个流的长度。
  • 另一个缺点是,即使代码清晰易读,也需要创建/包装 3 个 AudioInputStream 才能使其工作,这有点令人费解。我找不到更好的解决方案。

进一步阅读

【讨论】:

  • 我添加这篇文章是为了帮助遇到同样问题的任何人,因为我无法找到解释如何执行此操作的帖子。当然,我自己的解决方案非常适合我的情况。
【解决方案2】:

您可以通过使用AudioInputStream 读取WAV 文件轻松获取PCM 数据(以原始字节为单位),或许将数据存储在ByteBuffer 中。

Java 确实有一些内置的格式转换器。我不确定是否支持您想要的特定转换。有关支持的格式转换的文档位于 Audio Trail: Using Files and Format Converters

如果您必须进行某种抽取,例如,从 44.1kHz 采样率的 wav 到 16kHz,我猜使用线性插值会很好。

  1. 将传入字节转换为 PCM 数据值(可能标准化为浮点数)
  2. 以 2.76625 的增量(源自 44.1 / 16)迭代生成的数组,使用线性插值来获取新值
  3. 将新的 PCM 值转换回字节

如果没有任何标题信息,可以使用FileOutputStream 将生成的字节数组写入文件。 Java Tutorials: Byte Streams

具有浮点精度的线性插值通常被认为足以保持音频保真度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-03
    • 2013-02-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多