背景:不知是否在博客园看到的腾讯云平台广告,被AI接口几个项目吸引住了,其中有个 语音合成 接口在这里安利一下,还挺好玩。这个接口提供将一段文字转换成语音的功能,支持中文、英文,遗憾的是暂时没法经过本身的声音进行训练,推出本身独有声音的音频文件:) 不过整体来讲,仍是至关不错啦,附件中是我用这个接口转换的样例音频文件。java
DEMO实测,代码案例简单概述:api
首先,调用接口确定得申请appkey,secrect等一堆东西,在这里申请 session
申请,完成后会得到公共请求参数必须的信息,而后接口调用分为直接http请求与使用官方版本的sdk调用2种方式,建议使用sdk调用的方式,避免还得本身加sign。sdk调用的方式很简单,测试demo以下:app
@Test public void testAi() throws TencentCloudSDKException, IOException, UnsupportedAudioFileException, LineUnavailableException { Credential cred = new Credential("你的ID", "你的key"); AaiClient aaiClient = new AaiClient(cred, "ap-beijing"); TextToVoiceRequest request = new TextToVoiceRequest(); request.setProjectId(10144947); request.setModelType(1); request.setPrimaryLanguage(1); // request.setSampleRate(); request.setSessionId("testsessionid"); request.setSpeed(1F); request.setText("你好啊,你爱我么"); request.setVoiceType(1); request.setVolume(1F); TextToVoiceResponse textToVoiceResponse = aaiClient.TextToVoice(request); String audio = textToVoiceResponse.getAudio(); if (!StringUtils.isEmpty(audio)) { System.out.println(audio); BASE64Decoder decoder = new BASE64Decoder(); try { byte[] data = decoder.decodeBuffer(audio); OutputStream out = new FileOutputStream("d://test1.wav"); out.write(data); out.flush(); out.close(); } catch (Exception ex) { } } }
本人喜欢在喜马拉雅上听书,也听小说。看到有不少连普通话都不甚标准的做者有了大量的粉丝,还有打赏。在此我有了一个大胆的想法,在不涉及版权问题的前提下,我是否能够上传一大堆小说的音频内容,以量取胜,。实际测试中发现腾讯语音合成接口默认只支持300个字符,且生成的音频文件为BASE64的String字符串,须要进行拼接转换。固然拼接并非说把api返回的string直接经过一个stringbuilder拼起来就行,由于wav文件结构中是有头尾标示的,拼接过程中须要去头尾,拼接转换部分源码以下:测试
@Scheduled(fixedDelay = 1000 * 60 * 60) public void toVoice() { String textFilePath="D://work/mywork/txt/孙子兵法/计篇.txt"; String outputPath="D://work/mywork/voice/孙子兵法/计篇.wav"; try { File output=new File(outputPath); logger.info("开始获取文件内文本数据"); List<String> stringArray = fileManService.getStringArray(textFilePath, 100); if (stringArray != null) { List<String> voiceWaves=new ArrayList<String>(); for(String tmpText :stringArray) { voiceWaves.add(voiceManService.getWavString(tmpText)); } WavBaseStringMergeUtil wavBaseStringMergeUtil=new WavBaseStringMergeUtil(); File file=new File(outputPath); wavBaseStringMergeUtil.mergeWav(voiceWaves,file); logger.info("完成"); } else { logger.info("获取到的文本内容为空"); } } catch (Exception e) { logger.error("转换出现异常", e); } }
private static Header resolveHeader(byte[] Basebytes) throws IOException { InputStream fis = new ByteArrayInputStream(Basebytes); byte[] byte4 = new byte[4]; byte[] buffer = new byte[2048]; int readCount = 0; Header header = new Header(); fis.read(byte4);//RIFF fis.read(byte4); readCount += 8; header.fileSizeOffset = 4; header.fileSize = byteArrayToInt(byte4); fis.read(byte4);//WAVE fis.read(byte4);//fmt fis.read(byte4); readCount += 12; int fmtLen = byteArrayToInt(byte4); fis.read(buffer, 0, fmtLen); readCount += fmtLen; fis.read(byte4);//data or fact readCount += 4; if (isFmt(byte4, 0)) {//包含fmt段 fis.read(byte4); int factLen = byteArrayToInt(byte4); fis.read(buffer, 0, factLen); fis.read(byte4);//data readCount += 8 + factLen; } fis.read(byte4);// data size int dataLen = byteArrayToInt(byte4); header.dataSize = dataLen; header.dataSizeOffset = readCount; readCount += 4; header.dataOffset = readCount; header.dataInputStream = fis; return header; }
至此,基本能够知足我们转换小说的须要啦!!!今天也上传了第一套专辑《孙子兵法》 到喜马拉雅试试水,你们有感兴趣的能够去听一下语音合成的效果,若是给您带来帮助,请不要吝惜动下手指 帮忙点赞哟!ui
代码、文字文本交流能够私信也能够评论中留言,this
想听书的不再用担忧没书可听了,有想听书的朋友能够私信我有版权的文本内容,帮你转换哦。走路、吃饭、开车,想听就听……url
接着上次的内容,又找了下百度和阿里的语音合成sdk,发现百度和阿里的相对腾讯的语音合成貌似更加成熟,使用方法什么的就不赘述了,直接上API地址,懂的天然懂。code
不管是百度的仍是腾讯的语音合成接口单次请求的字符数是有限制的,而咱们的小说文档都很长,在以前的处理当中我是定长100处理的。会形成明明连着的一个成语或者词组,好比 “你好啊,我亲爱的朋友”,若是按照定长2个字符来处理,就会变成“你好”、“啊,我”等等,在生成音频文件合成后,连续的读起来时会发现这种断句有明显的停顿,体验很很差,所以增长以下方式,默认按照定长字符处理,可是会智能化的去寻找离定长最近的逗号、或者句号来进行断句。这样就不会出现生硬的分开本应连在一块儿读的词语了blog
处理代码以下:
/** * 按照给定的字符串长度在指定文本中查找最接近指定长度的逗号或者句号的endindex。若找不到则以指定长度做为endindex * @param inputString * @param length * @return */ private int getEndIndex(String inputString,int length) { if(length>inputString.length()) { return inputString.length(); } int retIndex= length; for(int i=retIndex-1;i>0;i--) { if(inputString.charAt(i)=='.' || inputString.charAt(i)=='。' || inputString.charAt(i)==',' || inputString.charAt(i)==',') { retIndex =i; break; } } return retIndex; } /** * 智能拆分文本 * @param inputString * @param length * @return */ private List<String> getStrListIntelligence(String inputString,int length) { List<String> StrList=new ArrayList<String>(); int indexStart=0; while (indexStart<inputString.length()) { //查找endIndex int endIndex = this.getEndIndex(inputString.substring(indexStart,indexStart+length<inputString.length()?indexStart+length:inputString.length()),length); String tmpString = inputString.substring(indexStart,indexStart+ endIndex); StrList.add(tmpString); indexStart+=endIndex; } return StrList; }