问题描述
讯飞语音合成有多个发音人,如何选择一个合适的发音人呢?我的解决方法是,选择符合要求的,然后每个都听一遍.最后选出一个合适的.
我的要求
我是用来朗读技术文章的,文章中要英文也有中文,所以我要选择支持中英文的发音人。发音人列表
符合我条件的发音人如下:
名称 |
属性 |
语言 |
参数名称 |
引擎参数 |
备注 |
小燕 |
青年女声 |
中英文(普通话) |
xiaoyan |
默认 |
|
小宇 |
青年男声 |
中英文(普通话) |
xiaoyu |
|
|
小研 |
青年女声 |
中英文(普通话) |
vixy |
|
|
小琪 |
青年女声 |
中英文(普通话) |
vixq |
xiaoqi |
|
小峰 |
青年男声 |
中英文(普通话) |
vixf |
|
|
无法直接循环下载
下面写个demo,要求输入一段文字,然后使用上述的多个发音人分别来合成.下载下来我再一个个的听,选出一个英文清晰,阅读节奏合适的发音人.
因为要批量下载,我首先想到的是,循环调用下载方法不就行了如下所示:
1 2 3 4 5 6 7 8
| for (......) { SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer(); ...... mTts.synthesizeToUri(Input, fileName, synthesizeToUriListener); }
|
但是我失败了,这样并不会合成多个音频。只会合成一个。经过测试之后,我发现,调用完毕下载方法后,主线程就结束了.
……最后经过一番思索解决方案如下.
创建下载线程
线程的知识我有点忘了,合成音频的方法最后会回调onSynthesizeCompleted
这个方法,我在下载线程DemoListRunable
中设置一个isEnd标记,当开始下载一个音频的时候,把isEnd设置为flase,下载完毕后设置为true.
在主线程中,通过不断的来查询这个标记,从而知道是否下载完毕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| package demo; import com.iflytek.cloud.speech.SpeechConstant; import com.iflytek.cloud.speech.SpeechError; import com.iflytek.cloud.speech.SpeechSynthesizer; import com.iflytek.cloud.speech.SynthesizeToUriListener; public class DemoListRunable implements Runnable { public static boolean isEnd=false; String fileName; String Input; String voiceName; public DemoListRunable(String voiceName, String fileName, String Input) { this.voiceName = voiceName; this.fileName = fileName; this.Input = Input; } public void run() { SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer(); mTts.setParameter(SpeechConstant.VOICE_NAME, voiceName); mTts.setParameter(SpeechConstant.SPEED, "50"); mTts.setParameter(SpeechConstant.PITCH, "50"); mTts.setParameter(SpeechConstant.VOLUME, "50"); System.out.println( " 正在合成 " + fileName.substring(0, fileName.lastIndexOf(".")) + " 朗读样例" + " 下载位置:" + fileName); mTts.synthesizeToUri(Input, fileName, synthesizeToUriListener); } static SynthesizeToUriListener synthesizeToUriListener = new SynthesizeToUriListener() { public void onBufferProgress(int progress) { } public void onSynthesizeCompleted(String uri, SpeechError error) { isEnd=true; if(error==null) System.out.println(" 合成成功"); else System.out.println(" 合成失败"); } @Override public void onEvent(int arg0, int arg1, int arg2, int arg3, Object arg4, Object arg5) { } }; }
|
主线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package demo; import java.util.Scanner; import com.iflytek.cloud.speech.SpeechConstant; import com.iflytek.cloud.speech.SpeechUtility; import replace.Replace; public class DemoList { static Scanner scanner = new Scanner(System.in); public static void main(String[] args) { SpeechUtility.createUtility(SpeechConstant.APPID + "=XXXXXXXX"); System.out.println( "######################################## 讯飞语音合成系统 ########################################"); System.out.println("输入要合成的文字(以: \"#exit\"作为结束符):"); StringBuffer sbBuffer = new StringBuffer(10240); String line = null; while (scanner.hasNext()) { line = scanner.nextLine(); if ("#exit".equals(line)) { break; } sbBuffer.append(line.concat("\r\n")); } System.out.println( "---------------------------------- 特殊字符处理 ----------------------------------"); String Input = Replace.replaceTitle(sbBuffer.toString()); Input = Replace.replaceEnglish(Input); System.out.println(Input); System.out.println( "---------------------------------- 特殊字符处理 ----------------------------------"); String[] fileNameArr = new String[] {"小燕xiaoyan.pcm", "小研vixy.pcm", "小琪vixq.pcm", "小宇xiaoyu.pcm", "小峰vixf.pcm"}; String[] voiceNameArr = new String[] {"xiaoyan", "vixy", "vixq", "xiaoyu", "vixf"}; for (int i = 0; i < fileNameArr.length; i++) { DemoListRunable runable=new DemoListRunable(voiceNameArr[i], fileNameArr[i], Input); DemoListRunable.isEnd=false; Thread thread=new Thread(runable); thread.start(); while(!DemoListRunable.isEnd) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
|
其中Replace
这个类用来预处理朗读的文本.包括替换容易读错的字符,添加空格以加入停顿等。代码参见讯飞语音合成 发音不准确怎么解决
实验结果
下载好音频后,逐个听一半,比较一番,我的到如下结果:
发音人 |
连贯性 |
英文准确性 |
小燕xiaoyan |
可以 |
英文准确 |
小研vixy |
可以 |
英文准确 |
小琪vixq |
慢 |
英文可能不准确 |
小峰vixf |
慢没有节奏 |
英文发音不全 |
小宇xiaoyu |
可以 |
英文发音不好 |
通过比较我发现:
- 女发音人中,
小燕xiaoyan
和小研vixy
这两个发音人可以用,还有就是小燕xiaoyan(默认)
读的时候有写破音,最后我选择小研vixy
这个发音人。
小琪vixq
读的有点慢,但是中英文之间切换比较好。
- 而男发音人
小峰vixf
和小宇xiaoyu
读英文的时候声音小不清晰,读音不标准。
具体情况还是以实验为主.