我正试图弄清楚如何使用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,我想使用线性插值会很好。
- 将传入字节转换为PCM数据值(可能标准化为浮点(
- 以2.76625的增量(源自44.1/16(迭代得到的数组,使用线性插值获得新值
- 将新PCM值转换回字节
如果没有任何头信息,则可以使用FileOutputStream
将生成的字节数组写入文件。Java教程:字节流
具有浮点精度的线性插值通常被认为足以保持音频保真度。