【Java】java转换可播放的QQ/微信高质量语音格式,mp3/wav转silk格式(高质量音频),mp3转换amr格式(低质量音频),mp3/wav转pcm(非语音格式)

1、简要

参考各个博主,发现java里mp3转silk的案例真的少,几乎没有,有的都是基于 linux系统的,所以自己研究了下就有了以下代码

tips:mp3转换silk格式,需要先转换成pcm再转换silk才能行,代码仅Windows项目部署,linux系统我没试过,有兄弟试了的话要是不行可以过来评论下,我可以研究研究

2、首先准备以下转换工具放入项目当中

链接:https://pan.baidu.com/s/1-bwq7lSTJiYdYM9WHAkdKQ 
提取码:1234

【Java】java转换可播放的QQ/微信高质量语音格式,mp3/wav转silk格式(高质量音频),mp3转换amr格式(低质量音频),mp3/wav转pcm(非语音格式)_第1张图片

3、创建工具类AudioUtils,编写代码



import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 音频格式转换
 *
 * @author sqd233
 */
public class AudioUtils {

    /**
     * 工具地址
     **/
    static String path = "lib/silk_converter/";

    public static void main(String[] args) {
        // TODO: mp3 转 silk
        transferAudioSilk("路径\\", "文件名.mp3", false);
        // TODO: wav 转 silk
        transferAudioSilk("路径\\", "文件名.wav", false);
        // TODO: mp3转amr
        transferMp3Amr("路径\\文件名.mp3", "路径\\文件名.amr");
    }
    
	/**
     * MP3/WAV转SILk格式
     * @param filePath 例:D:\\file\\audio.mp3
     * @param isSource isSource 是否清空原文件
     * @return
     */
    public static String transferAudioSilk(String filePath, boolean isSource){
        Integer index = filePath.lastIndexOf("\\") + 1;
        return transferAudioSilk(filePath.substring(0, index), filePath.substring(index, filePath.length()), isSource);
    }
    
    /**
     * MP3/WAV转SILk格式
     *
     * @param path 文件路径 例:D:\\file\\
     * @param name 文件名称 例:audio.mp3/audio.wav
     * @param isSource 是否清空原文件
     * @return silk文件路径
     * @throws Exception
     */
    public static String transferAudioSilk(String path, String name, boolean isSource) {
        try {
            // 判断后缀格式
            String suffix = name.split("\\.")[1];
            if (!suffix.toLowerCase().equals("mp3") && !suffix.toLowerCase().equals("wav")) {
                throw new ServiceException("文件格式必须是mp3/wav");
            }
            String filePath = path + name;
            File file = new File(filePath);
            if (!file.exists()) {
                throw new Exception("文件不存在!");
            }
            // 文件名时拼接
            SimpleDateFormat ttime = new SimpleDateFormat("yyyyMMddhhMMSS");
            String time = ttime.format(new Date());
            // 导出的pcm格式路径
            String pcmPath = path + "PCM_" + time + ".pcm";
            // 先将mp3/wav转换成pcm格式
            transferAudioPcm(filePath, pcmPath);
            // 导出的silk格式路径
            String silkPath = path + "SILK_" + time + ".silk";
            // 转换成silk格式
            transferPcmSilk(pcmPath, silkPath);
            // 删除pcm文件
            File pcmFile = new File(pcmPath);
            if (pcmFile.exists()) {
                pcmFile.delete();
            }
            if (isSource) {
                File audioFile = new File(filePath);
                if (audioFile.exists()) {
                    audioFile.delete();
                }
            }
            return silkPath;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

	/**
     * 调用ffmpeg,wav转 pcm
     *
     * @param wavPath wav文件地址
     * @param target  转后文件地址
     */
    public static void transferWavPcm (String wavPath, String target) {
        // ffmpeg -i input.wav -f s16le -ar 44100 -acodec pcm_s16le output.raw
        transferAudioPcm(wavPath, target);
    }

    /**
     * 调用ffmpeg,mp3转 pcm
     *
     * @param mp3Path mp3文件地址
     * @param target  转后文件地址
     */
    public static void transferMp3Pcm(String mp3Path, String target) {
        //ffmpeg -y -i 源文件 -f s16le -ar 24000 -ac 1 转换后文件位置
        transferAudioPcm(mp3Path, target);
    }

    /**
     * mp3/wav 通用
     * @param fpath
     * @param target
     */
    private static void transferAudioPcm(String fpath, String target) {
        List commend = new ArrayList();
        commend.add(path + "ffmpeg.exe");
        commend.add("-y");
        commend.add("-i");
        commend.add(fpath);
        commend.add("-f");
        commend.add("s16le");
        commend.add("-ar");
        commend.add("24000");
        commend.add("-ac");
        commend.add("-2");
        commend.add(target);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            Process p = builder.start();
            p.waitFor();
            p.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * silk_v3_encoder.exe,转成Silk格式
     * @param pcmPath pcm 文件地址
     * @param target  转换后的silk地址
     * silk_v3_encoder.exe 路径
     * pcm文件地址
     * silk输出地址
     * -Fs_API             : API sampling rate in Hz, default: 24000
     * -Fs_maxInternal     : Maximum internal sampling rate in Hz, default: 24000
     * -packetlength       : Packet interval in ms, default: 20
     * -rate             : Target bitrate;   default: 25000
     * -loss           : Uplink loss estimate, in percent (0-100);  default: 0
     * -complexity    : Set complexity, 0: low, 1: medium, 2: high; default: 2
     * -DTX           : Enable DTX (0/1); default: 0
     * -quiet               : Print only some basic values
     * -tencent             : Compatible with QQ/Wechat
     */
    public static void transferPcmSilk(String pcmPath, String target) {
        Process process = null;
        try {
        	/**
            // 1、这一节的,语音长度太长会使音频长度丢失
            List commend = new ArrayList<>();
            // 指令,可参照方法注释, 请不要在commend.add()里同时写【-参数 值】
            commend.add(path + "silk_v3_encoder.exe");
            commend.add(pcmPath);
            commend.add(target);
            commend.add("-tencent");
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            process = builder.start();
            // 如果删除下班这行写process.waitFor() ,太长的语音会阻塞,BufferedReader 打印出来太长的语音也会阻塞
            process = Runtime.getRuntime().exec("taskkill -f -t -im silk_v3_encoder.exe");
            */
            // 方法2,除了会弹出弹窗,没什么问题 cmd /c 极为重要,执行完毕后会自动关闭
			process = Runtime.getRuntime().exec("cmd /c start " + path + "silk_v3_encoder.exe "  + pcmPath + " " + target + " -tencent");
            process .waitFor();
            Thread.sleep(1000);
            // 有更好的方法会后续慢慢更新..
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }


    /**
     * mp3转amr(低质量qq语音)
     * @param mp3Path MP3文件地址
     * @param target 转换后文件地址
     * return
     */
    public static void transferMp3Amr(String mp3Path, String target) {
        // 被转换文件地址
        File source = new File(path);
        try {
            if (!source.exists()) {
                throw new Exception("文件不存在!");
            }
            List commend = new ArrayList();
            commend.add(path + "ffmpeg.exe");
            commend.add("-y");
            commend.add("-i");
            commend.add(mp3Path);
            commend.add("-ac");
            commend.add("1");
            commend.add("-ar");
            commend.add("8000");
            commend.add(target);
            try {
                ProcessBuilder builder = new ProcessBuilder();
                builder.command(commend);
                Process p = builder.start();
                p.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            ErrorLogger.printError("mp3转amr异常", e);
        }
    }

    /**
     * 一个音频转byte类型的方法
     * @param filePath
     * @return
     */
    public static byte[] byteAudio(String filePath) {
        try {
            InputStream inStream = new FileInputStream(filePath);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inStream.read(buffer)) > 0) {
                baos.write(buffer, 0, bytesRead);
            }
            inStream.close();
            baos.close();
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

4、其他

非常不建议用AMR格式的,音质非常差

你可能感兴趣的:(java,windows,开发语言)