科大讯飞语音合成
科大讯飞语音合成(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;
}