讯飞语音合成(文字转语音java)
- 进入讯飞官网注册并创建一个应用(java):https://console.xfyun.cn/app/myapp,勾选自己需要的服务,每天有500次免费转化的机会。
- 创建好之后下载SDK,里面包含 libmsc32.so、libmsc64.so、msc32.dll、msc64.dll、json-jena-1.0.jar、Msc.jar
- ==讯飞 文字转语音 必须把 lib(jar、.so 、.dll) 包放到: idea 项目根目录、tomcat(lib 、bin) 、jre(lib、amd64)里面 ==
idea:


pom文件:
<dependency>
<groupId>com.xunfei</groupId> <!--自定义-->
<artifactId>sdk</artifactId> <!--自定义-->
<version>1.0</version> <!--自定义-->
<scope>system</scope> <!--system,类似provided,需要显式提供依赖的jar以后,Maven就不会在Repository中查找它-->
<systemPath>${basedir}/lib/Msc.jar</systemPath> <!--项目根目录下的lib文件夹下-->
</dependency>
<dependency>
<groupId>com.xunfei</groupId> <!--自定义-->
<artifactId>json</artifactId> <!--自定义-->
<version>1.0</version> <!--自定义-->
<scope>system</scope> <!--system,类似provided,需要显式提供依赖的jar以后,Maven就不会在Repository中查找它-->
<systemPath>${basedir}/lib/json-jena-1.0.jar</systemPath> <!--项目根目录下的lib文件夹下-->
</dependency>
tomcat:


jre


5. 官方开发文档:https://www.xfyun.cn/doc/tts/online_tts/Java-SDK.html#合成播放
**XunfeiToVoice **
public class XunfeiToVoice {
public static String changeToVoice(String data) throws IOException {
SpeechUtility.createUtility("appid=****"); // appid :官网创建的应用的id
//合成监听器
SynthesizeToUriListener synthesizeToUriListener = XunfeiLib.getSynthesize();
// 默认是生成 pcm 文件,所以后面有一步是转换成 wav 文件才能正常播放
String fileName= XunfeiLib.getFileName("tts_test.pcm");
XunfeiLib.delDone(fileName);
//1.创建SpeechSynthesizer对象
SpeechSynthesizer mTts= SpeechSynthesizer.createSynthesizer( );
//2.合成参数设置,详见《MSC Reference Manual》SpeechSynthesizer 类
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");//设置发音人
mTts.setParameter(SpeechConstant.SPEED, "50");//设置语速,范围0~100
mTts.setParameter(SpeechConstant.PITCH, "50");//设置语调,范围0~100
mTts.setParameter(SpeechConstant.VOLUME, "50");//设置音量,范围0~100
//3.开始合成
//设置合成音频保存位置(可自定义保存位置),默认保存在“./tts_test.pcm”
mTts.synthesizeToUri(data,fileName ,synthesizeToUriListener);
//设置最长时间
int timeOut=30;
int star=0;
//校验文件是否生成
while(!XunfeiLib.checkDone(fileName)){
try {
Thread.sleep(1000);
star++;
if(star>timeOut){
throw new Exception("合成超过"+timeOut+"秒!");
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
log.error("Exception: {}",e.getMessage());
return e.getMessage();
}
}
String wavPath = fileName.replaceAll(".pcm",".wav");
pcmToWav(fileName,wavPath);
File file = new File(wavPath);
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile =new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(input));
String filePath = saveVoice(multipartFile);
deleteFile(wavPath);
deleteFile(fileName);
return filePath;
}
// 保存到服务器上的地址
private static String saveVoice(MultipartFile voiceFile) throws IOException {
Date date = new Date();
log.info("wikiVoice: {}", ResourceUtil.wikiVoice());
String dirPath = ("/voice"+ new SimpleDateFormat("yyyyMMdd").format(date));
File dir = new File("/data/file" + dirPath);
if (!dir.exists()) {
dir.mkdirs();
}
Runtime.getRuntime().exec("chmod -R 777 " + dir);
String filePath = dirPath + "/" + StringUtil.createUUID() + ".wav";
File file = new File("/data/file/voice"+ filePath);
if (!file.exists()) {
file.createNewFile();
}
Runtime.getRuntime().exec("chmod -R 777 " + file);
voiceFile.transferTo(file);
return filePath;
}
private static void deleteFile(String fileName){
File file = new File(fileName);
XunfeiLib.delDone(fileName);
file.deleteOnExit();
}
private static void pcmToWav(String src, String target) throws IOException {
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 = 16000;
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();
log.info("Convert OK!");
}
}
XunfeiLib
public class XunfeiLib {
private static Map<String,Boolean> vioceFile=new HashMap<String, Boolean>();
/**
* 设置生成文件队列
*
* @param name
* @param have
*/
public static void setVioce(String name ,Boolean have){
XunfeiLib.vioceFile.put(name, have);
}
/**
* 查看文件是否在队列中
* @param name
* @return
*/
public static Boolean checkDone(String name){
Boolean don= XunfeiLib.vioceFile.get(name);
if(don==null){
return false;
}
return don;
}
/**
* 清除队列中的信息
* @param name
*/
public static void delDone(String name){
XunfeiLib.vioceFile.remove(name);
}
/**
* 返回合成监视器
* @return
*/
public static SynthesizeToUriListener getSynthesize(){
return new SynthesizeToUriListener() {
//progress为合成进度0~100
public void onBufferProgress(int progress) {
System.out.println("当前进度:"+progress+"%");
}
//会话合成完成回调接口
//uri为合成保存地址,error为错误信息,为null时表示合成会话成功
public void onSynthesizeCompleted(String uri, SpeechError error) {
if(error!=null){
error.printStackTrace();
}else{
System.out.println("生成文件"+uri);
//将生成的文件保存到队列中
XunfeiLib.setVioce(uri, true);
}
}
@Override
public void onEvent(int arg0, int arg1, int arg2, int arg3,
Object arg4, Object arg5) {
// TODO 自动生成的方法存根
}
};
}
/**
* 获取文件名
*/
public static String getFileName(String name){
//获取文件名
StringBuffer fileName=new StringBuffer(System.getProperty("user.dir"))
.append(File.separator).append("src")
.append(File.separator).append("main")
// .append(File.separator).append("resources")
// .append(File.separator).append("webapp")
// .append(File.separator).append("WEB-INF")
// .append(File.separator).append("cache")
.append(File.separator).append(name);//获取文件路径
System.out.println(fileName.toString());
return fileName.toString();
}
/**
* @param fileLeng 转换文件长度
* @param srate 采样率 - 8000,16000等
* @param channel 通道数量 - 单声道= 1,立体声= 2等。
* @param format 每个样本的位数(这里是16)
* @throws
*/
public static byte[] getWAVHeader(long fileLeng, int srate, int channel, int format) {
byte[] header = new byte[44];
long totalDataLen = fileLeng + 36;
long bitrate = srate * channel * format;
header[0] = 'R';
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = (byte) format;
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1;
header[21] = 0;
header[22] = (byte) channel;
header[23] = 0;
header[24] = (byte) (srate & 0xff);
header[25] = (byte) ((srate >> 8) & 0xff);
header[26] = (byte) ((srate >> 16) & 0xff);
header[27] = (byte) ((srate >> 24) & 0xff);
header[28] = (byte) ((bitrate / 8) & 0xff);
header[29] = (byte) (((bitrate / 8) >> 8) & 0xff);
header[30] = (byte) (((bitrate / 8) >> 16) & 0xff);
header[31] = (byte) (((bitrate / 8) >> 24) & 0xff);
header[32] = (byte) ((channel * format) / 8);
header[33] = 0;
header[34] = 16;
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (fileLeng & 0xff);
header[41] = (byte) ((fileLeng >> 8) & 0xff);
header[42] = (byte) ((fileLeng >> 16) & 0xff);
header[43] = (byte) ((fileLeng >> 24) & 0xff);
return header;
}
}
本文介绍了如何在Java环境下配置和使用讯飞语音合成服务。首先需要在讯飞官网注册并创建应用,获取必要的SDK资源。接着,将SDK中的库文件放置到IDEA项目、Tomcat和JRE的相应目录下。最后,通过官方开发文档学习如何实现文字转语音的功能。

1万+

被折叠的 条评论
为什么被折叠?



