如何在Java中将音频从一种格式转换为wav或原始格式



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

  • 16 kHz
  • 16位
  • Mono
  • 签名
  • 小endian

我在这里找到的许多帖子都是针对另一种方式,即如何从RAW获得WAV。作为音频的新手,我希望有人能发布一个例子来展示如何做到这一点。

据我所知,Java声音api没有转换为RAW音频。它可以转换为WAV,这是一种带有44字节标头的RAW音频。一旦你理解了这一点,你就可以将问题分解为两部分:

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

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

此方法将音频字节转换为给定的格式,并生成字节[]结果作为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才能使其工作,这有点复杂。我找不到更好的解决方案

进一步阅读

  • 什么是原始音频
  • 有使用示例吗
  • 如果我们上采样/下采样,我们会失去精度吗?A、 B
  • 是否有可用于比较结果的在线转换器

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

Java确实有一些内置的格式转换器。我不确定是否支持您想要的特定转换。有关支持的格式转换的文档位于音频跟踪:使用文件和格式转换器

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

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

如果没有任何头信息,则可以使用FileOutputStream将生成的字节数组写入文件。Java教程:字节流

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

相关内容

最新更新