CS程序和BS程序文字转语音
程序员文章站
2023-11-07 10:57:34
一、项目中一直用到了文字转语音的功能,需求也比较简单,就是将一段报警信息通过语音的方式播放出来,之前一直采用CS客户端,利用微软自带的Speech语音播放库就可以完成, 1.1 封装winSpedk类代码如下: namespace Speak { using System; using System ......
一、项目中一直用到了文字转语音的功能,需求也比较简单,就是将一段报警信息通过语音的方式播放出来,之前一直采用cs客户端,利用微软自带的speech语音播放库就可以完成,
1.1 封装winspedk类代码如下:
namespace speak { using system; using system.runtime.compilerservices; using system.speech.synthesis; using system.threading; using speechlib; public class winspeak { #region 属性 private speechsynthesizer speak; public event errorinfo errorinfoevent; private thread thvoice; private string strvoicemsg; spvoice voice = null; private static winspeak _intence; #endregion private winspeak() { voice = new spvoice(); } #region 方法 public static winspeak _init() { if (_intence == null) _intence = new winspeak(); return _intence; } /// <summary> /// 读语音 /// </summary> private void speakm() { try { if (speak != null) { this.speak.speakasync(strvoicemsg); } } catch (exception exception) { this.errinfo(exception); } } /// <summary> /// 异步播放文本语音 /// </summary> /// <param name="msg"></param> public void beginspeaktext(string msg) { try { if (speak != null) { speak.speakasynccancelall(); speak.dispose(); } if (thvoice != null && thvoice.threadstate == threadstate.running) { thvoice.abort(); } speak = new speechsynthesizer(); speak.setoutputtodefaultaudiodevice(); strvoicemsg = msg; //thvoice = new thread(new threadstart(speakm)); //thvoice.start(); speak.speakasync(msg); gc.collect(); gc.waitforpendingfinalizers(); } catch (exception exception) { this.errinfo(exception); } } /// <summary> /// 播放文本语音 /// </summary> /// <param name="msg"></param> public void speaktext(string msg) { try { this.speak = new speechsynthesizer(); this.speak.speak(msg); this.speak.setoutputtonull(); this.speak.dispose(); } catch (exception exception) { this.errinfo(exception); } } /// <summary> /// speech播放文本合成语音 /// </summary> /// <param name="msg"></param> public void speech_speaktext(string msg) { try { if (voice != null) { voice.speak(null, speechvoicespeakflags.svsfpurgebeforespeak); voice.speak(msg, speechvoicespeakflags.svsflagsasync); } } catch (exception ex) { this.errinfo(ex); } } /// <summary> /// 关闭语音释放资源 /// </summary> public void speakclose() { try { if (speak != null) { this.speak.speakasynccancelall(); this.speak.dispose(); } if (voice != null) { voice.speak(null, speechvoicespeakflags.svsfpurgebeforespeak); } } catch (exception ex) { cglobe_log.error(cglobe_log.getmethodinfo() + ex.message); } } /// <summary> /// 获取错误信息 /// </summary> /// <param name="str"></param> private void errinfo(exception str) { if (this.errorinfoevent != null) { this.errorinfoevent(str); } } #endregion ~winspeak() { try { if (speak != null) { this.speak.speakasynccancelall(); this.speak.dispose(); } } catch (exception exception) { //this.errinfo(exception); } } } }
1.2 调用如下(一个同步播放、一个异步播放):
private void btntest_click(object sender, eventargs e) { try { string strsep = txtword.text; sfbr.winspeak._init().speech_speaktext(strsep); } catch (exception ex) { } } private void button1_click(object sender, eventargs e) { try { string strsep = txtword.text; sfbr.winspeak._init().beginspeaktext(strsep); } catch (exception ex) { } }
二、 最近客户提出需求需要在bs系统实现文字语音播放的功能,因不能接入外网不能调用第三方服务等,最后想到了一个解决方案:先把文字转化为音频文件,再把音频文件以流的形式推送到bs端进行播放;
2.1 同样可以利用微软自带的speech语音播放库将一段文本转化为音频文件:
2.2 封装 speechservice文字转换音频文件类
public class speechservice { private static speechsynthesizer synth = null; /// <summary> /// 返回一个speechsynthesizer对象 /// </summary> /// <returns></returns> private static speechsynthesizer getspeechsynthesizerinstance() { if (synth == null) { synth = new speechsynthesizer(); } return synth; } /// <summary> /// 保存语音文件 /// </summary> /// <param name="text"></param> public static void savemp3(string strfilename,string sptext) { synth = getspeechsynthesizerinstance(); synth.rate = 1; synth.volume = 100; synth.setoutputtowavefile(strfilename); synth.speak(sptext); synth.setoutputtonull(); } }
2.3 接下来就是将音频文件以文件流的形式推送到前端播放:
public async task<actionresult> playwav(string id,string sptext) { string strpath = server.mappath("~\\mp4\\" + id + ".wav"); speechservice.savemp3(strpath, sptext); try { using (filestream filestream = new filestream(strpath, filemode.open)) { byte[] filebyte = new byte[filestream.length]; filestream.seek(0, seekorigin.begin); filestream.read(filebyte, 0, (int)filestream.length); long fsize = filestream.length; long startbyte = 0; long endbyte = fsize - 1; int statuscode = 200; if ((request.headers["range"] != null)) { //get the actual byte range from the range header string, and set the starting byte. string[] range = request.headers["range"].split(new char[] { '=', '-' }); startbyte = convert.toint64(range[1]); if (range.length > 2 && range[2] != "") endbyte = convert.toint64(range[2]); //if the start byte is not equal to zero, that means the user is requesting partial content. if (startbyte != 0 || endbyte != fsize - 1 || range.length > 2 && range[2] == "") { statuscode = 206; }//set the status code of the response to 206 (partial content) and add a content range header. } long dessize = endbyte - startbyte + 1; //headers response.statuscode = statuscode; response.contenttype = "audio/mpeg"; response.addheader("content-accept", response.contenttype); response.addheader("content-length", dessize.tostring()); response.addheader("content-range", string.format("bytes {0}-{1}/{2}", startbyte, endbyte, fsize)); return file(filebyte, response.contenttype); } } catch (exception ex) { throw; } }
注意:返回的必须为异步( async task)不然会报错,因为文字音频转换涉及到异步调用
2.4 前端展示
2.5 运行截图如下:
bs实现文字音频调用demo地址如下:
https://github.com/lxshwyan/speechbsdemo.git