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

1、简要

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

tips:mp3转换silk格式,需要先转换成pcm再转换silk才能行,代码仅Windows项目部署

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

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

在这里插入图片描述

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<String> commend = new ArrayList<String>();
        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 <Hz>            : API sampling rate in Hz, default: 24000
     * -Fs_maxInternal <Hz>    : Maximum internal sampling rate in Hz, default: 24000
     * -packetlength <ms>      : Packet interval in ms, default: 20
     * -rate <bps>            : Target bitrate;   default: 25000
     * -loss <perc>          : Uplink loss estimate, in percent (0-100);  default: 0
     * -complexity <comp>   : Set complexity, 0: low, 1: medium, 2: high; default: 2
     * -DTX <flag>          : 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<String> 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<String> commend = new ArrayList<String>();
            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格式的,音质非常差
在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
1、Java实现wav音频文件转换pcm音频文件(AudioUtils.java) 2、Java实现播放pcm音频文件(PCMPlay.javaWAVwav是一种无损的音频文件格式WAV符合 PIFF(Resource Interchange File Format)规范。所有的WAV都有一个文件头,这个文件头音频流的编码参数。WAV音频流的编码没有硬性规定,除了PCM之外,还有几乎所有支持ACM规范的编码都可以为WAV音频流进行编码。 PCM:PCM(Pulse Code Modulation----脉码调制录音)。所谓PCM录音就是将声音等模拟信号变成符号化的脉冲列,再予以记录。PCM信号是由[1]、[0]等符号构成的数字信号,而未经过任何编码和压缩处理。与模拟信号比,它不易受传送系统的杂波及失真的影响。动态范围宽,可得到音质相当好的影响效果。 简单来说:wav是一种无损的音频文件格式pcm是没有压缩的编码方式。 WAVPCM的关系 WAV可以使用多种音频编码来压缩其音频流,不过我们常见的都是音频流被PCM编码处理的WAV,但这不表示WAV只能使用PCM编码,MP3编码同样也可以运用在WAV中,和AVI一样,只要安装好了相应的Decode,就可以欣赏这些WAV了。在Windows平台下,基于PCM编码的WAV是被支持得最好的音频格式,所有音频软件都能完美支持,由于本身可以达到较高的音质的要求,因此,WAV也是音乐编辑创作的首选格式,适合保存音乐素材。因此,基于PCM编码的WAV被作为了一种中介的格式,常常使用在其他编码的相互转换之中,例如MP3转换成WMA。 简单来说:pcm是无损wav文件中音频数据的一种编码方式,但wav还可以用其它方式编码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值