问题描述
讯飞语音合成有多个发音人,如何选择一个合适的发音人呢?我的解决方法是,选择符合要求的,然后每个都听一遍.最后选出一个合适的.
我的要求
我是用来朗读技术文章的,文章中要英文也有中文,所以我要选择支持中英文的发音人。发音人列表
![这里有一张图片]()
符合我条件的发音人如下:
| 名称 | 
属性 | 
语言 | 
参数名称 | 
引擎参数 | 
备注 | 
| 小燕 | 
青年女声 | 
中英文(普通话) | 
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读英文的时候声音小不清晰,读音不标准。 
具体情况还是以实验为主.