/// <summary> /// 把文本转换成声音,写入指定的内存流 /// </summary> /// <param name="speekText">要转化成语音的文字</param> /// <param name="mStream">合成结果输出的音频流</param> private void Speek(string speekText, ref MemoryStream mStream) { if (speekText == "" || _speed == "" || _vol == "" || _speeker == "") { return; } var szParams = "ssm=1," + _speeker + ",spd=" + _speed + ",aue=speex-wb;7,vol=" + _vol + ",auf=audio/L16;rate=16000"; var ret = 0; try { _sessionID = Ptr2Str(TtsDll.QTTSSessionBegin(szParams, ref ret)); if (ret != 0) { throw new Exception("初始化TTS引会话错误,错误代码:" + ret); } ret = TtsDll.QTTSTextPut(_sessionID, speekText, (uint)Encoding.Default.GetByteCount(speekText), string.Empty); if (ret != 0) { throw new Exception("向服务器发送数据,错误代码:" + ret); } uint audioLen = 0; var synthStatus = SynthStatus.TtsFlagStillHaveData; mStream = new MemoryStream(); mStream.Write(new byte[44], 0, 44); while (true) { IntPtr source = TtsDll.QTTSAudioGet(_sessionID, ref audioLen, ref synthStatus, ref ret); byte[] array = new byte[(int)audioLen]; if (audioLen > 0) { Marshal.Copy(source, array, 0, (int)audioLen); } mStream.Write(array, 0, array.Length); Thread.Sleep(1000); if (synthStatus == SynthStatus.TtsFlagDataEnd || ret != 0) { break; } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } finally { ret = TtsDll.QTTSSessionEnd(_sessionID, ""); if (ret != 0) { throw new Exception("结束TTS会话错误,错误代码:" + ret); } } }
/// <summary> /// 构造函数,初始化引擎 /// </summary> /// <param name="configs">初始化引擎参数</param> /// <param name="szParams">开始会话用参数</param> public FlyTts(string configs) { _dSpeeker.Add(EnuSpeeker.小燕青年女声中英文普通话, "ent=intp65,vcn=xiaoyan"); _dSpeeker.Add(EnuSpeeker.小宇青年男声中英文普通话, "ent=intp65,vcn=xiaoyu"); _dSpeeker.Add(EnuSpeeker.凯瑟琳青年女声英语, "ent=intp65_en,vcn=Catherine"); _dSpeeker.Add(EnuSpeeker.亨利青年男声英语, "ent=intp65_en,vcn=henry"); _dSpeeker.Add(EnuSpeeker.玛丽青年女声英语, "ent=vivi21,vcn=vimary"); _dSpeeker.Add(EnuSpeeker.小研青年女声中英文普通话, "ent=vivi21,vcn=vixy"); _dSpeeker.Add(EnuSpeeker.小琪青年女声中英文普通话, "ent=vivi21,vcn=vixq"); _dSpeeker.Add(EnuSpeeker.小峰青年男声中英文普通话, "ent=vivi21,vcn=vixf"); _dSpeeker.Add(EnuSpeeker.小梅青年女声中英文粤语, "ent=vivi21,vcn=vixm"); _dSpeeker.Add(EnuSpeeker.小莉青年女声中英文台普, "ent=vivi21,vcn=vixl"); _dSpeeker.Add(EnuSpeeker.小蓉青年女声汉语四川话, "ent=vivi21,vcn=vixr"); _dSpeeker.Add(EnuSpeeker.小芸青年女声汉语东北话, "ent=vivi21,vcn=vixyun"); _dSpeeker.Add(EnuSpeeker.小坤青年男声汉语河南话, "ent=vivi21,vcn=vixk"); _dSpeeker.Add(EnuSpeeker.小强青年男声汉语湖南话, "ent=vivi21,vcn=vixqa"); _dSpeeker.Add(EnuSpeeker.小莹青年女声汉语陕西话, "ent=vivi21,vcn=vixying"); _dSpeeker.Add(EnuSpeeker.小新童年男声汉语普通话, "ent=vivi21,vcn=vixx"); _dSpeeker.Add(EnuSpeeker.楠楠童年女声汉语普通话, "ent=vivi21,vcn=vinn"); _dSpeeker.Add(EnuSpeeker.老孙老年男声汉语普通话, "ent=vivi21,vcn=vils"); _dSpeekerName.Add("xiaoyan", "ent=intp65,vcn=xiaoyan"); _dSpeekerName.Add("xiaoyu", "ent=intp65,vcn=xiaoyu"); _dSpeekerName.Add("catherine", "ent=intp65_en,vcn=Catherine"); _dSpeekerName.Add("henry", "ent=intp65_en,vcn=henry"); _dSpeekerName.Add("mary", "ent=vivi21,vcn=vimary"); _dSpeekerName.Add("xy", "ent=vivi21,vcn=vixy"); _dSpeekerName.Add("xq", "ent=vivi21,vcn=vixq"); _dSpeekerName.Add("xf", "ent=vivi21,vcn=vixf"); _dSpeekerName.Add("xm", "ent=vivi21,vcn=vixm"); _dSpeekerName.Add("xl", "ent=vivi21,vcn=vixl"); _dSpeekerName.Add("xr", "ent=vivi21,vcn=vixr"); _dSpeekerName.Add("xyun", "ent=vivi21,vcn=vixyun"); _dSpeekerName.Add("xk", "ent=vivi21,vcn=vixk"); _dSpeekerName.Add("xqa", "ent=vivi21,vcn=vixqa"); _dSpeekerName.Add("xying", "ent=vivi21,vcn=vixying"); _dSpeekerName.Add("xx", "ent=vivi21,vcn=vixx"); _dSpeekerName.Add("nn", "ent=vivi21,vcn=vinn"); _dSpeekerName.Add("ls", "ent=vivi21,vcn=vils"); _buffting = iFlyResource.ding; var ret = TtsDll.MSPLogin(null, null, configs); if (ret != 0) { throw new Exception("初始化TTS引擎错误,错误代码:" + ret); } }
/// <summary> /// 把文字转化为声音,单路配置,一种语音 /// </summary> /// <param name="speekText">要转化成语音的文字</param> /// <param name="outWaveFlie">把声音转为文件,默认为不生产wave文件</param> private void Speek(string speekText, string outWaveFlie = null) { if (speekText == "" || _speed == "" || _vol == "" || _speeker == "") { return; } _dSpeeker.TryGetValue(Speeker, out _speeker); var szParams = "ssm=1," + _speeker + ",spd=" + _speed + ",aue=speex-wb;7,vol=" + _vol + ",auf=audio/L16;rate=16000"; var ret = 0; try { _sessionID = Ptr2Str(TtsDll.QTTSSessionBegin(szParams, ref ret)); if (ret != 0) { throw new Exception("初始化TTS引会话错误,错误代码:" + ret); } ret = TtsDll.QTTSTextPut(_sessionID, speekText, (uint)Encoding.Default.GetByteCount(speekText), string.Empty); if (ret != 0) { throw new Exception("向服务器发送数据,错误代码:" + ret); } IntPtr audioData; uint audioLen = 0; var synthStatus = SynthStatus.TtsFlagStillHaveData; var fs = new MemoryStream(); fs.Write(new byte[44], 0, 44); //写44字节的空文件头 while (synthStatus == SynthStatus.TtsFlagStillHaveData) { audioData = TtsDll.QTTSAudioGet(_sessionID, ref audioLen, ref synthStatus, ref ret); if (ret != 0) { break; } var data = new byte[audioLen]; if (audioLen > 0) { Marshal.Copy(audioData, data, 0, (int)audioLen); } fs.Write(data, 0, data.Length); } var header = getWave_Header((int)fs.Length - 44); //创建wav文件头 var headerByte = StructToBytes(header); //把文件头结构转化为字节数组 //写入文件头 fs.Position = 0; //定位到文件头 fs.Write(headerByte, 0, headerByte.Length); //写入文件头 fs.Position = 0; var pl = new System.Media.SoundPlayer(fs); pl.Stop(); pl.Play(); if (outWaveFlie != null) { var ofs = new FileStream(outWaveFlie, FileMode.Create); fs.WriteTo(ofs); fs.Close(); ofs.Close(); fs = null; ofs = null; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } finally { ret = TtsDll.QTTSSessionEnd(_sessionID, ""); if (ret != 0) { throw new Exception("结束TTS会话错误,错误代码:" + ret); } } }
/// <summary> /// 把文字转化为声音,多路配置,多种语音 /// </summary> /// <param name="speekText">要转化成语音的文字</param> /// <param name="outWaveFlie">把声音转为文件,默认为不生产wave文件</param> public void MultiSpeek(string speekText, string outWaveFlie = null) { Console.WriteLine("开始,now=" + DateTime.Now); var mStream = new MemoryStream(); try { var speekTexts = System.Text.RegularExpressions.Regex.Split(speekText, "\r\n"); mStream.Write(new byte[44], 0, 44); for (var i = 0; i < speekTexts.Length; i++) { var thisStr = speekTexts[i]; thisStr = thisStr.Trim(); //去除前后的空白 if (thisStr == "") { continue; //空段的处理 } var pos = thisStr.IndexOf('#'); //#在段中的位置 if (pos > 0) { //设定了讲话者时用指定的讲话者说 _dSpeekerName.TryGetValue(thisStr.Substring(0, pos).ToLower(), out _speeker); Speek(thisStr.Substring(pos + 1, thisStr.Length - pos - 1), ref mStream); } else { if (thisStr.Length < 4) {//没有指定讲话者文本长度小于4 Speek(thisStr, ref mStream); continue; } if (thisStr.Substring(0, 4).ToLower() == "stop") {//暂停一段时间 var s = Convert.ToInt32(thisStr.Substring(4, thisStr.Length - 4)); var bs = new byte[32000]; for (var j = 0; j < s; j++) { mStream.Write(new byte[32000], 0, 32000); } } else if (thisStr.Substring(0, 4).ToLower() == "ting") {//插入叮铃声 mStream.Write(_buffting, 0, _buffting.Length); } else {//没有指定讲话者文本长度大于等于4 Speek(thisStr, ref mStream); } } var e = new JinDuEventArgs(speekTexts.Length, i, thisStr.Length, 0); Finished?.Invoke(this, e); } var ret = TtsDll.MSPLogout(); if (ret != 0) { throw new Exception("逆初始化TTS引擎错误,错误代码:" + ((ErrorCode)ret).ToString("G")); } var header = getWave_Header((int)mStream.Length - 44); //创建wav文件头 var headerByte = StructToBytes(header); //把文件头结构转化为字节数组 //写入文件头 mStream.Position = 0; //定位到文件头 mStream.Write(headerByte, 0, headerByte.Length); //写入文件头 //mStream.Position = 0; //System.Media.SoundPlayer pl = new System.Media.SoundPlayer(mStream); //pl.Stop(); //pl.Play(); if (outWaveFlie != null) { var ofs = new FileStream(outWaveFlie, FileMode.Create); mStream.WriteTo(ofs); ofs.Close(); ofs = null; } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { var ret = TtsDll.MSPLogout(); mStream.Close(); mStream = null; } Console.WriteLine("完成,now=" + DateTime.Now); }