源于最近的项目接触到了音频文件的转换及相关操作,所以做个记录以供大家参考。
一.需求
由于当前的一批音频文件格式参差不齐,且采样率也不一致。在进行音频文件的统一处理前,需要将文件格式和采样率进行统一。
思路,将非wav格式的音频文件统一转换为wav格式,且将采样率统一为8k。
二.依赖
使用javazoom的Converter进行统一转换处理。
<dependency>
<groupId>javazoom</groupId>
<artifactId>jlayer</artifactId>
<version>1.0.1</version>
</dependency>
三.源码(存在瑕疵,建议先看第四块的补充说明)
talk is cheap,show me the code.
import com.sun.media.sound.WaveFileReader;
import com.sun.media.sound.WaveFileWriter;
import javazoom.jl.converter.Converter;
import javazoom.jl.decoder.JavaLayerException;
import javax.sound.sampled.*;
import java.io.*;
import java.nio.file.Files;
/**
* @author: Vainycos
* @description 录音文件工具类
* @date: 2023/4/17 17:14
*/
public class VoiceFileUtils {
/**
* 统一转换8k采样率。根据实际需求可进行调整,或者将此变量抽取至配置文件
*/
public static final int TARGET_SAMPLE_RATE = 8000;
/**
* 转换wav格式
* @param inputFilePath
* @param outputFilePath
* @return
*/
public static boolean toWav(String inputFilePath, String outputFilePath){
Converter converter = new Converter();
try {
converter.convert(inputFilePath, outputFilePath);
} catch (JavaLayerException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 将wav转换为8k采样率
* @param inputFilePath
* @param outputFilePath
*/
public static void toStandardWav(String inputFilePath, String outputFilePath){
try {
byte[] bytes = Files.readAllBytes(new File(inputFilePath).toPath());
WaveFileReader reader = new WaveFileReader();
AudioInputStream audioIn = reader.getAudioInputStream(new ByteArrayInputStream(bytes));
AudioFormat srcFormat = audioIn.getFormat();
AudioFormat dstFormat = new AudioFormat(srcFormat.getEncoding(),
TARGET_SAMPLE_RATE,
srcFormat.getSampleSizeInBits(),
srcFormat.getChannels(),
srcFormat.getFrameSize(),
srcFormat.getFrameRate(),
srcFormat.isBigEndian());
AudioInputStream convertedIn = AudioSystem.getAudioInputStream(dstFormat, audioIn);
File file = new File(outputFilePath);
WaveFileWriter writer = new WaveFileWriter();
writer.write(convertedIn, AudioFileFormat.Type.WAVE, file);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String filePath = "C:\\data\\test.mp3";
String wavTargetPath = "C:\\data\\convert-wav-result.wav";
String standardWavPath = "C:\\data\\standard-result.wav";
toWav(filePath, wavTargetPath);
toStandardWav(wavTargetPath, standardWavPath);
}
唯一需要注意的是,如果调用toWav()传入的inputFilePath的源音频文件本来就是wav格式则会报异常,所以需要判断一下只有非wav格式才需要调用toWav()方法,否则直接调用toStandardWav()方法转换采样率即可。
四.补充
在mp3->wav的过程中,偶尔会遇到转换出错的情况。通过debug发现在convert()过程的源码javazoom.jl.converter.Converter读取Header会出现null的情况。
正常转换录音情况:
异常转换录音文件的情况:
目前暂时未做原理深究,初步推测是源文件音频文件头缺失。
在此补充另一种转换的方法,若上述转换失败则可以使用该方法作为替补方案,并可直接在mp3转换wav格式的过程中将采样率,比特率等参数进行统一设置:
public static void main(String[] args) throws IOException, IllegalArgumentException, InputFormatException, EncoderException {
File source = new File("C:\\data\\test.mp3");
File target = new File("C:\\data\\test.wav");
trans(source,target);
}
public static void trans(File source, File target) throws IllegalArgumentException, InputFormatException, EncoderException {
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
// 设置比特率
audio.setBitRate(new Integer(16000));
// 设置音频通道数
audio.setChannels(new Integer(2));
// 设置采样率,此处设置为8k采样率
audio.setSamplingRate(new Integer(8000));
EncodingAttributes attrs = new EncodingAttributes();
// 目标文件的格式
attrs.setFormat("wav");
// 将上述设置的参数设置到目标文件中
attrs.setAudioAttributes(audio);
Encoder encoder = new Encoder();
MultimediaObject sourceObj = new MultimediaObject(source);
encoder.encode(sourceObj, target, attrs);
}
五.补充2,使用java2
使用java实现格式转换:
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-all-deps</artifactId>
<version>3.3.1</version>
</dependency>
public boolean m4aToWav() {
boolean succeeded = true;
try {
File source = new File("source.m4a");
File target = new File("target.wav");
//Audio Attributes
AudioAttributes audio = new AudioAttributes();
audio.setCodec("pcm_s16le");
audio.setBitRate(16000);
audio.setChannels(1);
audio.setBitRate(16000);
audio.setSamplingRate(16000);
//Encoding attributes
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat("wav");
attrs.setAudioAttributes(audio);
//Encode
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(source), target, attrs);
} catch (Exception ex) {
ex.printStackTrace();
succeeded = false;
}
return succeeded;
}
参考资料: