/// <summary> /// 获取语法的ID /// </summary> /// <returns></returns> private string GetGrammarID() { int ret = -1; string temp = Application.dataPath; #if UNITY_ANDROID temp = Application.persistentDataPath + "/gm_continuous_digit.abnf"; #elif UNITY_STANDALONE_WIN temp = Application.streamingAssetsPath + "/gm_continuous_digit.abnf"; #endif byte[] grammarBytes = Utils.ReadFile(temp); int grammar_len = grammarBytes.Length; IntPtr ptrGrammarID = DllImports.MSPUploadData("usergram", grammarBytes, (uint)grammar_len, "dtt = abnf, sub = asr", out ret); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("MSPUploadData error, errCode=" + ((ErrorCode)ret).ToString("G")); return(null); } string grammarID = Marshal.PtrToStringAnsi(ptrGrammarID); Utils.CustomPrint("grammarID:" + grammarID + "\r\n"); return(grammarID); }
/// <summary> /// 处理错误 /// </summary> /// <param name="errorMsg">错误的函数</param> /// <param name="ret">错误的返回值</param> /// <param name="sessionID">sessionID</param> /// <param name="fs">打开的文件</param> private void HandleErrorMsg(string errorMsg, int ret, string sessionID, FileStream fs) { Utils.CustomPrint(errorMsg + " err,errCode=" + ((ErrorCode)ret).ToString("G")); DllImports.QISRSessionEnd(sessionID, errorMsg); if (fs != null) { fs.Close(); fs = null; } }
/// <summary> /// 处理错误 /// </summary> /// <param name="errorMsg">错误的函数</param> /// <param name="ret">错误的返回值</param> /// <param name="sessionID">sessionID</param> /// <param name="writer">打开的文件</param> /// <param name="fs">打开的文件</param> private static void HandleErrorMsg(string errorMsg, int ret, string sessionID, BinaryWriter writer, FileStream fs) { Utils.CustomPrint(errorMsg + " err,errCode=" + ((ErrorCode)ret).ToString("G")); DllImports.QTTSSessionEnd(sessionID, errorMsg); if (writer != null) { writer.Close(); writer = null; } if (fs != null) { fs.Close(); fs = null; } }
/// <summary> /// 运行语音合成功能 /// </summary> /// <returns></returns> public IEnumerator RunTTS() { if (text == null) { yield break; } WaveFormat waveFormat = new WaveFormat(); int nLength = 0; int nFormatChunkLength = 0x10; // Format chunk length. short shPad = 1; // File padding int ret = 0; uint audioLen = 0; int sampleCount = 0; int synthStatus = (int)TTSStatus.MSP_TTS_FLAG_STILL_HAVE_DATA; IntPtr ptrSessionID = DllImports.QTTSSessionBegin(sessionTTSBeginParams, out ret); string sessionID = Marshal.PtrToStringAnsi(ptrSessionID); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("TTSSessionBegin failed, errCode=" + ((ErrorCode)ret).ToString("G")); yield break; } FileStream waveFile = new FileStream(textPath, FileMode.OpenOrCreate); BinaryWriter writer = new BinaryWriter(waveFile); char[] chunkRiff = { 'R', 'I', 'F', 'F' }; char[] chunkType = { 'W', 'A', 'V', 'E' }; char[] chunkFmt = { 'f', 'm', 't', ' ' }; char[] chunkData = { 'd', 'a', 't', 'a' }; //RIFF块 writer.Write(chunkRiff); writer.Write(nLength); writer.Write(chunkType); //WAVE块 writer.Write(chunkFmt); writer.Write(nFormatChunkLength); writer.Write(shPad); writer.Write(waveFormat.mChannels); writer.Write(waveFormat.mSamplesPerSecond); writer.Write(waveFormat.mAverageBytesPerSecond); writer.Write(waveFormat.mBlockAlign); writer.Write(waveFormat.mBitsPerSample); //数据块 writer.Write(chunkData); writer.Write((int)0); // The sample length will be written in later. ret = DllImports.QTTSTextPut(sessionID, text, (uint)text.Length, null); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QTTSTextPut", ret, sessionID, writer, waveFile); yield break; } Utils.CustomPrint("正在合成 ...\n"); while (true) { ///获取合成音频 IntPtr data = DllImports.QTTSAudioGet(sessionID, ref audioLen, ref synthStatus, out ret); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { break; } if (IntPtr.Zero != data) { byte[] buff = new byte[audioLen]; Marshal.Copy(data, buff, 0, buff.Length); writer.Write(buff, 0, buff.Length); sampleCount += (int)audioLen;///计算data_size大小 buff = null; } if (TTSStatus.MSP_TTS_FLAG_DATA_END == (TTSStatus)synthStatus) { break; } Utils.CustomPrint(">"); yield return(new WaitForSeconds(0.2f)); } if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("QTTSAudioGet failed, errCode=" + ((ErrorCode)ret).ToString("G")); DllImports.QTTSSessionEnd(sessionID, "AudioGetError"); writer.Close(); waveFile.Close(); yield break; } //写WAV文件尾 writer.Seek(4, SeekOrigin.Begin); writer.Write((int)(sampleCount + 36)); writer.Seek(40, SeekOrigin.Begin); writer.Write(sampleCount); writer.Close(); waveFile.Close(); writer = null; waveFile = null; ///合成完毕 ret = DllImports.QTTSSessionEnd(sessionID, "Normal"); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("QTTSSessionEnd failed, errCode=" + ((ErrorCode)ret).ToString("G")); } ptrSessionID = IntPtr.Zero; Utils.CustomPrint("合成完毕"); yield break; }
/// <summary> /// 运行声音识别功能 /// </summary> /// <returns></returns> public IEnumerator RunISR() { ///模拟录音,输入音频 if (!File.Exists(path)) { Utils.CustomPrint("文件" + path + "不存在!"); yield break; } const int BUFFER_NUM = 640 * 10;/// 每次写入200ms音频(16k,16bit):1帧音频20ms,10帧=200ms。16k采样率的16位音频,一帧的大小为640Byte int ret = 0; string result = ""; int len; int audStatus = (int)AudioStatus.MSP_AUDIO_SAMPLE_CONTINUE; ///音频状态 int epStatus = (int)EpStatus.MSP_EP_NULL; ///端点检测 int recStatus = (int)RecogStatus.MSP_REC_NULL; ///识别状态 int rsltStatus = (int)RecogStatus.MSP_REC_NULL; bool first = true; int errcode = 0; Utils.CustomPrint("上传语法 ...+\r\n"); string grammarID = GetGrammarID(); if (!string.IsNullOrEmpty(grammarID)) { Utils.CustomPrint("上传语法成功\r\n"); } else { Utils.CustomPrint("MSPUploadData error"); yield break; } IntPtr ptrSessionID = DllImports.QISRSessionBegin(grammarID, sessionISRBeginParams, out errcode); string sessionID = Marshal.PtrToStringAnsi(ptrSessionID); if (ErrorCode.MSP_SUCCESS != (ErrorCode)errcode) { Utils.CustomPrint("QISRSessionBegin err,errCode=" + ((ErrorCode)errcode).ToString("G")); yield break; } FileStream fp = new FileStream(path, FileMode.Open); byte[] buff = new byte[BUFFER_NUM]; IntPtr bp = Marshal.AllocHGlobal(BUFFER_NUM); while (fp.Position != fp.Length) { len = fp.Read(buff, 0, BUFFER_NUM); Marshal.Copy(buff, 0, bp, buff.Length); audStatus = (int)AudioStatus.MSP_AUDIO_SAMPLE_CONTINUE; if (first) { audStatus = (int)AudioStatus.MSP_AUDIO_SAMPLE_FIRST; first = false; } Utils.CustomPrint(">"); ///开始向服务器发送音频数据 ret = DllImports.QISRAudioWrite(sessionID, bp, (uint)len, audStatus, ref epStatus, ref recStatus); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISRAudioWrite", ret, sessionID, fp); yield break; } if (EpStatus.MSP_EP_AFTER_SPEECH == (EpStatus)epStatus) { break; } ///sleep一下很有必要,防止MSC端无缓冲的识别结果时浪费CPU资源 yield return(new WaitForSeconds(0.2f)); } buff = null; fp.Close(); fp = null; Marshal.FreeHGlobal(bp); ret = DllImports.QISRAudioWrite(sessionID, IntPtr.Zero, 0, (int)AudioStatus.MSP_AUDIO_SAMPLE_LAST, ref epStatus, ref recStatus); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISRAudioWrite", ret, sessionID, null); yield break; } ///最后一块数据发完之后,循环从服务器端获取结果 ///考虑到网络环境不好的情况下,需要对循环次数作限定 while (RecogStatus.MSP_REC_STATUS_COMPLETE != (RecogStatus)rsltStatus) { IntPtr rec_result = DllImports.QISRGetResult(sessionID, ref rsltStatus, 0, out ret); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISRGetResult", ret, sessionID, null); yield break; } if (IntPtr.Zero != rec_result) { string tmp = Marshal.PtrToStringAnsi(rec_result); Utils.CustomPrint("---:" + tmp); result += tmp; Utils.CustomPrint("传完音频后返回结果!:" + result); } yield return(new WaitForSeconds(0.2f)); } ret = DllImports.QISRSessionEnd(sessionID, "Normal"); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("QISRSessionEnd failed, errCode=" + ((ErrorCode)ret).ToString("G")); } ptrSessionID = IntPtr.Zero; Utils.CustomPrint("识别完成\r\n"); yield break; }
/// <summary> /// 运行语音评测功能 /// </summary> /// <returns></returns> public IEnumerator RunISE() { int len; int audStatus = (int)AudioStatus.MSP_AUDIO_SAMPLE_CONTINUE; ///音频状态 int epStatus = (int)EpStatus.MSP_EP_NULL; ///端点检测 int recStatus = (int)RecogStatus.MSP_REC_NULL; ///识别状态 bool first = true; uint rlstLen = 0; IntPtr rsltPrt = IntPtr.Zero; int ret = 0; const int BUFFER_NUM = 640 * 10;/// 每次写入200ms音频(16k,16bit):1帧音频20ms,10帧=200ms。16k采样率的16位音频,一帧的大小为640Byte FileStream textFS = null; FileStream waveFS = null; string parameters, textPath, wavePath; GetValuesByCategory(category, out parameters, out textPath, out wavePath); #if UNITY_ANDROID textPath = Application.persistentDataPath + "/" + textPath; wavePath = Application.persistentDataPath + "/" + wavePath; #elif UNITY_STANDALONE_WIN textPath = Application.streamingAssetsPath + "/" + textPath; wavePath = Application.streamingAssetsPath + "/" + wavePath; #endif IntPtr ptrSessionID = DllImports.QISESessionBegin(parameters, "", out ret); string sessionID = Marshal.PtrToStringAnsi(ptrSessionID); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("QISESessionBegin err,errCode=" + ((ErrorCode)ret).ToString("G")); yield break; } if (!File.Exists(textPath) || !File.Exists(wavePath)) { Utils.CustomPrint("文件" + textPath + " 或者 " + wavePath + "不存在!"); DllImports.QISESessionEnd(sessionID, "File not exist"); yield break; } textFS = new FileStream(textPath, FileMode.Open); int textLength = (int)textFS.Length; byte[] buff = new byte[textLength]; textFS.Read(buff, 0, textLength); textFS.Close(); textFS = null; ret = DllImports.QISETextPut(sessionID, Encoding.Default.GetString(buff), (uint)textLength, ""); Utils.CustomPrint("Encoding:" + Encoding.Default.EncodingName.ToLower()); Utils.CustomPrint(Regex.Unescape(Encoding.Default.GetString(buff)) + "|length:" + textLength); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISETextPut", ret, sessionID, null); yield break; } waveFS = new FileStream(wavePath, FileMode.Open); buff = new byte[BUFFER_NUM]; IntPtr bp = Marshal.AllocHGlobal(BUFFER_NUM); while (waveFS.Position != waveFS.Length) { len = waveFS.Read(buff, 0, BUFFER_NUM); Marshal.Copy(buff, 0, bp, buff.Length); audStatus = (int)AudioStatus.MSP_AUDIO_SAMPLE_CONTINUE; if (first) { audStatus = (int)AudioStatus.MSP_AUDIO_SAMPLE_FIRST; first = false; } Utils.CustomPrint(">" + len); ///开始向服务器发送音频数据 ret = DllImports.QISEAudioWrite(sessionID, bp, (uint)len, audStatus, ref epStatus, ref recStatus); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISEAudioWrite", ret, sessionID, waveFS); yield break; } if (RecogStatus.MSP_REC_STATUS_SUCCESS == (RecogStatus)recStatus) { rsltPrt = DllImports.QISEGetResult(sessionID, ref rlstLen, ref recStatus, ref ret); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISEGetResult", ret, sessionID, waveFS); yield break; } if (IntPtr.Zero != rsltPrt) { Utils.CustomPrint("rlstLen:" + rlstLen); byte[] data = new byte[rlstLen]; Marshal.Copy(rsltPrt, data, 0, (int)rlstLen); Utils.CustomPrint("+++传完音频后返回结果!:" + GBToUnicode(data, data.Length)); } } if (EpStatus.MSP_EP_AFTER_SPEECH == (EpStatus)epStatus) { break; } ///sleep一下很有必要,防止MSC端无缓冲的识别结果时浪费CPU资源 yield return(new WaitForSeconds(0.2f)); } buff = null; waveFS.Close(); waveFS = null; Marshal.FreeHGlobal(bp); ret = DllImports.QISEAudioWrite(sessionID, IntPtr.Zero, 0, (int)AudioStatus.MSP_AUDIO_SAMPLE_LAST, ref epStatus, ref recStatus); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISEAudioWrite", ret, sessionID, null); yield break; } while (RecogStatus.MSP_REC_STATUS_COMPLETE != (RecogStatus)recStatus) { rsltPrt = DllImports.QISEGetResult(sessionID, ref rlstLen, ref recStatus, ref ret); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { HandleErrorMsg("QISEGetResult", ret, sessionID, null); yield break; } if (IntPtr.Zero != rsltPrt) { Utils.CustomPrint("rlstLen:" + rlstLen); byte[] data = new byte[rlstLen]; Marshal.Copy(rsltPrt, data, 0, (int)rlstLen); Utils.CustomPrint("---传完音频后返回结果!:" + GBToUnicode(data, data.Length)); } yield return(new WaitForSeconds(0.2f)); } rsltPrt = IntPtr.Zero; ret = DllImports.QISESessionEnd(sessionID, "Normal"); if (ErrorCode.MSP_SUCCESS != (ErrorCode)ret) { Utils.CustomPrint("QISESessionEnd failed, errCode=" + ((ErrorCode)ret).ToString("G")); } ptrSessionID = IntPtr.Zero; Utils.CustomPrint("评测完成\r\n"); yield break; }