以前公司下达了一个需求,要求用语音做广播,因为广播里面包含姓名,所以不能难以直接录制,需要使用合成语音。
一开始考虑到时间以及优先级问题,这边使用了百度的合成语音。
但是百度语音相对僵硬,而且没有感情,效果不甚满意。
不久前时间相对充沛,这边就使用了觉得最完美的方案——使用微软云的人工智能合成语音。
因为这个语音可以设置感情,没有机器合成那种僵硬的感觉,可以说是比真人还真人。
微软云合成语音demo网站:https://azure.microsoft.com/zh-cn/services/cognitive-services/text-to-speech/
感觉确实有需要的话,接下来就应该创建微软云账号,开始使用了,可以参考这个视频:https://www.bilibili.com/video/av670457802
不过要注意一点,创建微软云账号,需要绑定一张visa卡。如果没有的话,可以淘宝或者申请微软云学生账号。
申请微软云学生账号:https://www.daniao.org/6693.html
创建好微软云合成语音服务之后,就可以直接使用了。
文档地址:https://docs.microsoft.com/zh-cn/azure/cognitive-services/speech-service/get-started-text-to-speech?tabs=script%2Cwindowsinstall&pivots=programming-language-javascript
收费:
每个月都有25万字的合成额度,如果需求量不大的话,已经够用了。如果需求量大,可以将通用的语音保存到服务器,将不通用项,如姓名,以单字的形式,请求后再存入服务器。每次访问时,先检查服务器存不存在这个字,如没有再请求api接口。
下面是简单使用的具体代码:
<script type="text/javascript">const sdk = SpeechSDKvar synthesizer = null;/*** 初始化微软语音*/function synthesizeMsSpeech() {const speechConfig = sdk.SpeechConfig.fromSubscription("你的密匙", "你的地区,如 eastus 不能输入中文");synthesizer = new sdk.SpeechSynthesizer(speechConfig);}/*** 使用微软语音说话* @param {Object} word*/function msSpeek(text) {//微软人工智能语音,需要使用xml字符串做配置let ssml = `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="en-US"><voice name="zh-cn-XiaoxiaoNeural"><mstts:express-as style="cheerful">${text}</mstts:express-as></voice></speak>`synthesizer.speakSsmlAsync(ssml,result => {if (result.errorDetails) {console.error(result.errorDetails);} else {// console.log(JSON.stringify(result));}synthesizer.close();},error => {console.log(error);synthesizer.close();});}synthesizeMsSpeech();msSpeek("你好,我是你的优乐美!")</script>
</body>
密匙就不解释了,微软云控制台可以看到,地区可以选eastus eastus2,以及另外几个, 具体看控制台上显示的地区
另外为方便理解,附带一个带界面的语音合成网页:
欢快 闲聊 冷静 生气 紧张 哭泣 轻蔑 严肃 亲切 温和 伤感 客服 数字助理 新闻
</select><br><br><button type="button" onclick="clickPlayBtn()">播放</button><button type="button" onclick="clickDownBtn()">下载</button></div><!-- 去除语音直接播放的sdk。在sdi.min.js,搜索play(),去除第二个play,这样不会输入到流的时候,依然先自动播放语音,形成干扰 --><script src="static/js/microsoft.speech.sdk.1.js"></script><script type="text/javascript">const sdk = SpeechSDKvar synthesizer = null;//还有很多种const STYLE = {cheerful: "cheerful", //欢快chat: "chat", //闲聊calm: "calm", //冷静angry: "angry", //生气fearful: "fearful" //紧张}/*** 初始化微软语音*/function synthesizeMsSpeech() {const speechConfig = sdk.SpeechConfig.fromSubscription("你的微软云密匙", "你的地区,如eastus");synthesizer = new sdk.SpeechSynthesizer(speechConfig);}/*** 请求微软语音* @param {Object} text*/function requestMsAudio(text, style="cheerful") {return new Promise((resolve, reject) => {let xmlObj = `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="en-US"><voice name="zh-cn-XiaoxiaoNeural"><mstts:express-as style="${style}">${text}</mstts:express-as></voice></speak>`const ssml = xmlObj;synthesizer.speakSsmlAsync(ssml,result => {// synthesizer.close(); //关闭后,会只获取一轮if (result.errorDetails) {console.error(result.errorDetails);reject(result)} else {let arrayBuffer = result.audioDatalet blob = new Blob([arrayBuffer], {type: 'autio/wave'});var src = URL.createObjectURL(blob);resolve(src)}},error => {console.log(error);reject(error)// synthesizer.close();});})}/*** 使用微软语音说话* @param {Object} text*/function msSpeek(text, style="cheerful") {return new Promise((resolve, reject) => {requestMsAudio(text, style).then((src) => {var mp3 = new Audio(src);//播放完之后,执行事件mp3.addEventListener("ended", () => {resolve();})mp3.play().catch(playError); //播放语音});})}/*** 合并播放,先播放完一个,再播放另一个* @param {Object} src 资源链接* @param {Object} text 要生成的文字*/function mergeSpeek(src, text, style="cheerful"){return new Promise((resolve, reject) => {requestMsAudio(text, style).then((msSrc) => {playAudio(src).then(()=>{var mp3 = new Audio(msSrc);//播放完之后,执行事件mp3.addEventListener("ended", () => {resolve();})mp3.play().catch(playError); //播放语音})});})}/*** 下载微软语音* @param {Object} text*/function msDownload(text, style) {return new Promise((resolve, reject) => {requestMsAudio(text, style).then((src) => {const pattern=/[`~!@#$^&*()=|{}':;',\\\[\]\.<>\/?~!@#¥……&*()——|{}【】';:""'。,、?\s]/g;let name = text.replace(pattern," ");_download(src, name +".wav")});})};/*** 播放音频,then为播放完后的回调* @param {Object} src*/function playAudio(src) {return new Promise((resolve, reject) => {var mp3 = new Audio(src);//播放完之后,执行事件mp3.addEventListener("ended", () => {resolve();})mp3.play().catch(playError); //播放语音})}/*** 播放失败后的统一回调*/const playError = function(){console.error("播放失败,播放前,请先点击页面,以允许播放。")}// 下载function _download(src, filename) {var eleLink = document.createElement('a');eleLink.download = filename;eleLink.style.display = 'none';// 字符内容转变成blob地址 eleLink.href = src;// 自动触发点击 document.body.appendChild(eleLink);eleLink.click();// 然后移除 document.body.removeChild(eleLink);};synthesizeMsSpeech();/*** 点击下载后触发*/function clickPlayBtn(){let text = document.getElementById("mainTxt").value;let style = document.getElementById("style").valueif(text.length > 0){msSpeek(text, style)}}/*** 点击下载后触发*/function clickDownBtn(){let text = document.getElementById("mainTxt").value;let style = document.getElementById("style").valueif(text.length > 0){msDownload(text, style)}}</script>
</body>