科大讯飞语音合成

本文介绍了如何使用科大讯飞的语音合成技术,特别是在Linux环境下解决返回错误码20021的问题,包括放置动态库、引入jar包、编写合成代码、转换PCM格式以及使用UUID进行文件命名的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

科大讯飞语音合成(java)

最近总是有朋友问科大语音合成的问题,包括在linux 部署合成语音,返回错误码:20021的问题,说百度了很多都不好使,今天有时间给出一版自己实际项目中写的一个流程。部分代码也是整合网上所得。分享如下~

1、放置动态库(放置不对会返回错误码: 20021)
msc32.dll、msc64.dll、libmsc32.so、libmsc64.so  放到自己的 C:\Windows\System32下即可,linux 放在 根目录的lib下,以64位为例:libmsc64.so ->/lib64
2、将iflytek的Msc的jar包引入项目
3、合成代码
SynthesizeToUriListener synthesizeToUriListener = new SynthesizeToUriListener() {
        //progress为合成进度0~100
        public void onBufferProgress(int progress) {}
        //会话合成完成回调接口
        //uri为合成保存地址,error为错误信息,为null时表示合成会话成功
        public void onSynthesizeCompleted(String uri, SpeechError error) {
            try {

                System.out.println("uri0"+uri);
                System.out.println("error"+error);
                if(null == error){
                    String newUri = uri.replace(".pcm",".wav");
                    //因为科大讯飞转换为 .pcm 文件,这里自己转换成 .wav
                    ConvertAudioFiles.convertAudioFiles(uri,newUri);
                }
                tedisUtil.tedisSetString("lock_tl","true");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onEvent(int arg0, int arg1, int arg2, int arg3,
                            Object arg4, Object arg5) {
            // TODO Auto-generated method stub

        }
    };

 public String start (String text,String sex) throws IOException {
        SpeechUtility.createUtility( SpeechConstant.APPID +"=xxxx");
        //1.创建 SpeechSynthesizer 对象
        SpeechSynthesizer mTts= SpeechSynthesizer.createSynthesizer( );
        //2.合成参数设置,详见《MSC Reference Manual》SpeechSynthesizer 类
        if("1".equals(sex)){
            mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaofeng");//设置发音人
        }else{
            mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");//设置发音人
        }

        mTts.setParameter(SpeechConstant.SPEED, "67");//设置语速,范围 0~100
        mTts.setParameter(SpeechConstant.PITCH, "50");//设置语调,范围 0~100
        mTts.setParameter(SpeechConstant.VOLUME, "50");//设置音量,范围 0~100
        //3.开始合成
        // 设置合成音频保存位置(可自定义保存位置),默认保存在“./tts_test.pcm”
        String url = getSavePath();
        System.out.println("url2:"+url);
        mTts.synthesizeToUri(text,url,synthesizeToUriListener);
        url = url.replace(".pcm",".wav");
        String urlEnd = url.substring(url.lastIndexOf("/")-8,url.length());
        urlEnd = Constants.SAVE_FILE_VOICE_DIALOGUE+urlEnd;
        System.out.println("urlEnd:"+urlEnd);
        return urlEnd;
    }
4、将.pcm 转换成自己需要的格式文件
public class ConvertAudioFiles {
	public static void convertAudioFiles(String src, String target) throws Exception {
		   FileInputStream fis = new FileInputStream(src);
		   FileOutputStream fos = new FileOutputStream(target);

		   //计算长度
		   byte[] buf = new byte[1024 * 4];
		   int size = fis.read(buf);
		   int PCMSize = 0;
		   while (size != -1) {
		      PCMSize += size;
		      size = fis.read(buf);
		    }
		   fis.close();

		   //填入参数,比特率等等。这里用的是16位单声道 8000 hz
		   WaveHeader header = new WaveHeader();
		   //长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
		   header.fileLength = PCMSize + (44 - 8);
		   header.FmtHdrLeth = 16;
		   header.BitsPerSample = 16;
		   header.Channels = 1;
		   header.FormatTag = 0x0001;
		   header.SamplesPerSec = 14500;
		   header.BlockAlign = (short)(header.Channels * header.BitsPerSample / 8);
		   header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
		   header.DataHdrLeth = PCMSize;

		   byte[] h = header.getHeader();

		   assert h.length == 44; //WAV标准,头部应该是44字节
		   //write header
		   fos.write(h, 0, h.length);
		   //write data stream
		   fis = new FileInputStream(src);
		   size = fis.read(buf);
		   while (size != -1) {
		      fos.write(buf, 0, size);
		      size = fis.read(buf);
		   }
		   fis.close();
		   fos.close();
		   System.out.println("Convert OK!");
		}
}

直接调用 start()方法即可。

5、命名小序

命名的时候可以用uuid
这里因为uuid有间隔符,则过滤掉即可:
uFileName.substring(0,8)+uFileName.substring(9,13)+uFileName.substring(14,18)+uFileName.substring(19,23)+uFileName.substring(24);

 public static String reFileNameByUUID(String filePath){
        String fileName = "";
        String uFileName = UUID.randomUUID().toString();
        uFileName = uFileName.substring(0,8)+uFileName.substring(9,13)+uFileName.substring(14,18)+uFileName.substring(19,23)+uFileName.substring(24);
        fileName = filePath+uFileName+".pcm";
        File file =new File(fileName);
        if(file.exists()){
            fileName = reFileNameByUUID(filePath);
        }
        return fileName;
    }

    private static String getSavePath() throws IOException {
        String saveFilePath = FileUploadConstants.getPropValue("FILE_PATH_VOICE_DIALOGUE");
        if (saveFilePath == null || saveFilePath.equals("")) {
            return null;
        }
        System.out.println("saveFilePath:"+saveFilePath);
        //加上日期文件夹
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String dateFolder = dateFormat.format(Calendar.getInstance().getTime());
        saveFilePath = saveFilePath + "/" + dateFolder;
        if (!saveFilePath.endsWith("/")) {
            saveFilePath += "/";
        }
        //System.out.println("saveFilePath1:"+saveFilePath);
        // 生成文件保存路径

        File aSaveFile = new File(saveFilePath);
        System.out.println("aSaveFile:"+aSaveFile.isDirectory());
        if (!aSaveFile.isDirectory()){
            aSaveFile.mkdirs();
            aSaveFile.setWritable(true, false);
            //Runtime.getRuntime().exec("chmod 777 -R " + aSaveFile);
        }

        String uri = reFileNameByUUID(saveFilePath);
        System.out.println("uri:"+uri);
        return uri;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人在旅途我渐行渐远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值