|
C#文本转语音(科大讯飞离线版)
引言
文本转语音(Text To Speech),简称TTS,在很多业务场景会用到,比如广播大厅,人机互动等。C#要实现TTS有不少选择,比如调用System.Speech,此处就不细说了,下面主要介绍一下C#调用科大讯飞的离线语音合成SDK来实现文本转语音。
产品介绍
地址:[https://www.xfyun.cn/service/offline_tts]
步骤
一、创建科大讯飞应用
进入科大讯飞控制台创建一个应用:[https://console.xfyun.cn/app/myapp],没有账号的可以先注册一个。
创建应用后会有一个APPID,先记下来,后面写代码会用到。
二、下载对应平台的SDK
点击刚创建的应用,进去应用服务界面,在左侧点击语音合成下面的离线语音合成(普通版/高品质版),如下
如果是windows平台,那么只能选择普通版。Linux的话可以选择高品质版,两者的效果在我看来相差还是比较大的。
下载完解压出来,目录如下
里面我们需要用到的是bin目录内的文件,当然你也可以参考samples里面的c语言代码,跟后面我提供的C#代码差不多
三、编写C#代码
Windows版- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Runtime.InteropServices;
- using System.IO;
- namespace Speech
- {
- /// <summary>
- /// 讯飞语音合成
- /// Author:String Lee
- /// Date:2021年12月15日 14:06:00
- /// </summary>
- public class WindowsXFTTSUtils
- {
- #region TTS枚举常量
- public enum ErrorCode
- {
- MSP_SUCCESS = 0,
- MSP_ERROR_FAIL = -1,
- MSP_ERROR_EXCEPTION = -2,
- /* General errors 10100(0x2774) */
- MSP_ERROR_GENERAL = 10100, /* 0x2774 */
- MSP_ERROR_OUT_OF_MEMORY = 10101, /* 0x2775 */
- MSP_ERROR_FILE_NOT_FOUND = 10102, /* 0x2776 */
- MSP_ERROR_NOT_SUPPORT = 10103, /* 0x2777 */
- MSP_ERROR_NOT_IMPLEMENT = 10104, /* 0x2778 */
- MSP_ERROR_ACCESS = 10105, /* 0x2779 */
- MSP_ERROR_INVALID_PARA = 10106, /* 0x277A */
- MSP_ERROR_INVALID_PARA_VALUE = 10107, /* 0x277B */
- MSP_ERROR_INVALID_HANDLE = 10108, /* 0x277C */
- MSP_ERROR_INVALID_DATA = 10109, /* 0x277D */
- MSP_ERROR_NO_LICENSE = 10110, /* 0x277E */
- MSP_ERROR_NOT_INIT = 10111, /* 0x277F */
- MSP_ERROR_NULL_HANDLE = 10112, /* 0x2780 */
- MSP_ERROR_OVERFLOW = 10113, /* 0x2781 */
- MSP_ERROR_TIME_OUT = 10114, /* 0x2782 */
- MSP_ERROR_OPEN_FILE = 10115, /* 0x2783 */
- MSP_ERROR_NOT_FOUND = 10116, /* 0x2784 */
- MSP_ERROR_NO_ENOUGH_BUFFER = 10117, /* 0x2785 */
- MSP_ERROR_NO_DATA = 10118, /* 0x2786 */
- MSP_ERROR_NO_MORE_DATA = 10119, /* 0x2787 */
- MSP_ERROR_SKIPPED = 10120, /* 0x2788 */
- MSP_ERROR_ALREADY_EXIST = 10121, /* 0x2789 */
- MSP_ERROR_LOAD_MODULE = 10122, /* 0x278A */
- MSP_ERROR_BUSY = 10123, /* 0x278B */
- MSP_ERROR_INVALID_CONFIG = 10124, /* 0x278C */
- MSP_ERROR_VERSION_CHECK = 10125, /* 0x278D */
- MSP_ERROR_CANCELED = 10126, /* 0x278E */
- MSP_ERROR_INVALID_MEDIA_TYPE = 10127, /* 0x278F */
- MSP_ERROR_CONFIG_INITIALIZE = 10128, /* 0x2790 */
- MSP_ERROR_CREATE_HANDLE = 10129, /* 0x2791 */
- MSP_ERROR_CODING_LIB_NOT_LOAD = 10130, /* 0x2792 */
- /* Error codes of network 10200(0x27D8)*/
- MSP_ERROR_NET_GENERAL = 10200, /* 0x27D8 */
- MSP_ERROR_NET_OPENSOCK = 10201, /* 0x27D9 */ /* Open socket */
- MSP_ERROR_NET_CONNECTSOCK = 10202, /* 0x27DA */ /* Connect socket */
- MSP_ERROR_NET_ACCEPTSOCK = 10203, /* 0x27DB */ /* Accept socket */
- MSP_ERROR_NET_SENDSOCK = 10204, /* 0x27DC */ /* Send socket data */
- MSP_ERROR_NET_RECVSOCK = 10205, /* 0x27DD */ /* Recv socket data */
- MSP_ERROR_NET_INVALIDSOCK = 10206, /* 0x27DE */ /* Invalid socket handle */
- MSP_ERROR_NET_BADADDRESS = 10207, /* 0x27EF */ /* Bad network address */
- MSP_ERROR_NET_BINDSEQUENCE = 10208, /* 0x27E0 */ /* Bind after listen/connect */
- MSP_ERROR_NET_NOTOPENSOCK = 10209, /* 0x27E1 */ /* Socket is not opened */
- MSP_ERROR_NET_NOTBIND = 10210, /* 0x27E2 */ /* Socket is not bind to an address */
- MSP_ERROR_NET_NOTLISTEN = 10211, /* 0x27E3 */ /* Socket is not listenning */
- MSP_ERROR_NET_CONNECTCLOSE = 10212, /* 0x27E4 */ /* The other side of connection is closed */
- MSP_ERROR_NET_NOTDGRAMSOCK = 10213, /* 0x27E5 */ /* The socket is not datagram type */
- /* Error codes of mssp message 10300(0x283C) */
- MSP_ERROR_MSG_GENERAL = 10300, /* 0x283C */
- MSP_ERROR_MSG_PARSE_ERROR = 10301, /* 0x283D */
- MSP_ERROR_MSG_BUILD_ERROR = 10302, /* 0x283E */
- MSP_ERROR_MSG_PARAM_ERROR = 10303, /* 0x283F */
- MSP_ERROR_MSG_CONTENT_EMPTY = 10304, /* 0x2840 */
- MSP_ERROR_MSG_INVALID_CONTENT_TYPE = 10305, /* 0x2841 */
- MSP_ERROR_MSG_INVALID_CONTENT_LENGTH = 10306, /* 0x2842 */
- MSP_ERROR_MSG_INVALID_CONTENT_ENCODE = 10307, /* 0x2843 */
- MSP_ERROR_MSG_INVALID_KEY = 10308, /* 0x2844 */
- MSP_ERROR_MSG_KEY_EMPTY = 10309, /* 0x2845 */
- MSP_ERROR_MSG_SESSION_ID_EMPTY = 10310, /* 0x2846 */
- MSP_ERROR_MSG_LOGIN_ID_EMPTY = 10311, /* 0x2847 */
- MSP_ERROR_MSG_SYNC_ID_EMPTY = 10312, /* 0x2848 */
- MSP_ERROR_MSG_APP_ID_EMPTY = 10313, /* 0x2849 */
- MSP_ERROR_MSG_EXTERN_ID_EMPTY = 10314, /* 0x284A */
- MSP_ERROR_MSG_INVALID_CMD = 10315, /* 0x284B */
- MSP_ERROR_MSG_INVALID_SUBJECT = 10316, /* 0x284C */
- MSP_ERROR_MSG_INVALID_VERSION = 10317, /* 0x284D */
- MSP_ERROR_MSG_NO_CMD = 10318, /* 0x284E */
- MSP_ERROR_MSG_NO_SUBJECT = 10319, /* 0x284F */
- MSP_ERROR_MSG_NO_VERSION = 10320, /* 0x2850 */
- MSP_ERROR_MSG_MSSP_EMPTY = 10321, /* 0x2851 */
- MSP_ERROR_MSG_NEW_RESPONSE = 10322, /* 0x2852 */
- MSP_ERROR_MSG_NEW_CONTENT = 10323, /* 0x2853 */
- MSP_ERROR_MSG_INVALID_SESSION_ID = 10324, /* 0x2854 */
- /* Error codes of DataBase 10400(0x28A0)*/
- MSP_ERROR_DB_GENERAL = 10400, /* 0x28A0 */
- MSP_ERROR_DB_EXCEPTION = 10401, /* 0x28A1 */
- MSP_ERROR_DB_NO_RESULT = 10402, /* 0x28A2 */
- MSP_ERROR_DB_INVALID_USER = 10403, /* 0x28A3 */
- MSP_ERROR_DB_INVALID_PWD = 10404, /* 0x28A4 */
- MSP_ERROR_DB_CONNECT = 10405, /* 0x28A5 */
- MSP_ERROR_DB_INVALID_SQL = 10406, /* 0x28A6 */
- MSP_ERROR_DB_INVALID_APPID = 10407, /* 0x28A7 */
- /* Error codes of Resource 10500(0x2904)*/
- MSP_ERROR_RES_GENERAL = 10500, /* 0x2904 */
- MSP_ERROR_RES_LOAD = 10501, /* 0x2905 */ /* Load resource */
- MSP_ERROR_RES_FREE = 10502, /* 0x2906 */ /* Free resource */
- MSP_ERROR_RES_MISSING = 10503, /* 0x2907 */ /* Resource File Missing */
- MSP_ERROR_RES_INVALID_NAME = 10504, /* 0x2908 */ /* Invalid resource file name */
- MSP_ERROR_RES_INVALID_ID = 10505, /* 0x2909 */ /* Invalid resource ID */
- MSP_ERROR_RES_INVALID_IMG = 10506, /* 0x290A */ /* Invalid resource image pointer */
- MSP_ERROR_RES_WRITE = 10507, /* 0x290B */ /* Write read-only resource */
- MSP_ERROR_RES_LEAK = 10508, /* 0x290C */ /* Resource leak out */
- MSP_ERROR_RES_HEAD = 10509, /* 0x290D */ /* Resource head currupt */
- MSP_ERROR_RES_DATA = 10510, /* 0x290E */ /* Resource data currupt */
- MSP_ERROR_RES_SKIP = 10511, /* 0x290F */ /* Resource file skipped */
- /* Error codes of TTS 10600(0x2968)*/
- MSP_ERROR_TTS_GENERAL = 10600, /* 0x2968 */
- MSP_ERROR_TTS_TEXTEND = 10601, /* 0x2969 */ /* Meet text end */
- MSP_ERROR_TTS_TEXT_EMPTY = 10602, /* 0x296A */ /* no synth text */
- /* Error codes of Recognizer 10700(0x29CC) */
- MSP_ERROR_REC_GENERAL = 10700, /* 0x29CC */
- MSP_ERROR_REC_INACTIVE = 10701, /* 0x29CD */
- MSP_ERROR_REC_GRAMMAR_ERROR = 10702, /* 0x29CE */
- MSP_ERROR_REC_NO_ACTIVE_GRAMMARS = 10703, /* 0x29CF */
- MSP_ERROR_REC_DUPLICATE_GRAMMAR = 10704, /* 0x29D0 */
- MSP_ERROR_REC_INVALID_MEDIA_TYPE = 10705, /* 0x29D1 */
- MSP_ERROR_REC_INVALID_LANGUAGE = 10706, /* 0x29D2 */
- MSP_ERROR_REC_URI_NOT_FOUND = 10707, /* 0x29D3 */
- MSP_ERROR_REC_URI_TIMEOUT = 10708, /* 0x29D4 */
- MSP_ERROR_REC_URI_FETCH_ERROR = 10709, /* 0x29D5 */
- /* Error codes of Speech Detector 10800(0x2A30) */
- MSP_ERROR_EP_GENERAL = 10800, /* 0x2A30 */
- MSP_ERROR_EP_NO_SESSION_NAME = 10801, /* 0x2A31 */
- MSP_ERROR_EP_INACTIVE = 10802, /* 0x2A32 */
- MSP_ERROR_EP_INITIALIZED = 10803, /* 0x2A33 */
- /* Error codes of TUV */
- MSP_ERROR_TUV_GENERAL = 10900, /* 0x2A94 */
- MSP_ERROR_TUV_GETHIDPARAM = 10901, /* 0x2A95 */ /* Get Busin Param huanid*/
- MSP_ERROR_TUV_TOKEN = 10902, /* 0x2A96 */ /* Get Token */
- MSP_ERROR_TUV_CFGFILE = 10903, /* 0x2A97 */ /* Open cfg file */
- MSP_ERROR_TUV_RECV_CONTENT = 10904, /* 0x2A98 */ /* received content is error */
- MSP_ERROR_TUV_VERFAIL = 10905, /* 0x2A99 */ /* Verify failure */
- /* Error codes of IMTV */
- MSP_ERROR_IMTV_SUCCESS = 11000, /* 0x2AF8 */ /* 成功 */
- MSP_ERROR_IMTV_NO_LICENSE = 11001, /* 0x2AF9 */ /* 试用次数结束,用户需要付费 */
- MSP_ERROR_IMTV_SESSIONID_INVALID = 11002, /* 0x2AFA */ /* SessionId失效,需要重新登录通行证 */
- MSP_ERROR_IMTV_SESSIONID_ERROR = 11003, /* 0x2AFB */ /* SessionId为空,或者非法 */
- MSP_ERROR_IMTV_UNLOGIN = 11004, /* 0x2AFC */ /* 未登录通行证 */
- MSP_ERROR_IMTV_SYSTEM_ERROR = 11005, /* 0x2AFD */ /* 系统错误 */
- /* Error codes of HCR */
- MSP_ERROR_HCR_GENERAL = 11100,
- MSP_ERROR_HCR_RESOURCE_NOT_EXIST = 11101,
- /* Error codes of http 12000(0x2EE0) */
- MSP_ERROR_HTTP_BASE = 12000, /* 0x2EE0 */
- /*Error codes of ISV */
- MSP_ERROR_ISV_NO_USER = 13000, /* 32C8 */ /* the user doesn't exist */
- }
- public enum SynthStatus
- {
- MSP_TTS_FLAG_STILL_HAVE_DATA = 1,
- MSP_TTS_FLAG_DATA_END = 2,
- MSP_TTS_FLAG_CMD_CANCELED = 0
- }
- #endregion
- #region TTS dll import
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern int MSPLogin(string user, string password, string configs);
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern int MSPLogout();
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern IntPtr QTTSSessionBegin(string _params, ref int errorCode);
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern int QTTSTextPut(string sessionID, string textString, uint textLen, string _params);
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern IntPtr QTTSAudioGet(string sessionID, ref uint audioLen, ref SynthStatus synthStatus, ref int errorCode);
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern IntPtr QTTSAudioInfo(string sessionID);
- [DllImport("msc.dll", CallingConvention = CallingConvention.Winapi)]
- public static extern int QTTSSessionEnd(string sessionID, string hints);
- #endregion
- /// <summary>
- /// 生成语音文件
- /// </summary>
- /// <param name="text"></param>
- /// <param name="filename"></param>
- /// <param name="speaker"></param>
- /// <param name="speed"></param>
- /// <returns></returns>
- public static bool GetAudio(string text, string filename, string speaker, int speed)
- {
- IntPtr session_ID = IntPtr.Zero;
- try
- {
- string login_configs = $"appid =xxx ";//登录参数,自己注册后获取的appid
- string type = speaker;
- uint audio_len = 0;
- SynthStatus synth_status = SynthStatus.MSP_TTS_FLAG_STILL_HAVE_DATA;
- var ret = WindowsXFTTSUtils.MSPLogin(string.Empty, string.Empty, login_configs);
- //MSPLogin方法返回失败
- if (ret != (int)ErrorCode.MSP_SUCCESS)
- {
- return false;
- }
- string _params = $"engine_type = local,rdn = 2, speed = {speed}, volume = 100, rcn = 0, voice_name={type}, tts_res_path =fo|res\\tts\\{type}.jet;fo|res\\tts\\common.jet, sample_rate = 16000";
- //string _params = "ssm=1,ent=sms16k,vcn=xiaoyan,spd=medium,aue=speex-wb;7,vol=x-loud,auf=audio/L16;rate=16000";
- //string @params = "engine_type = local,voice_name=xiaoyan,speed=50,volume=50,pitch=50,rcn=1, text_encoding = UTF8, background_sound=1,sample_rate = 16000";
- session_ID = WindowsXFTTSUtils.QTTSSessionBegin(_params, ref ret);
- //QTTSSessionBegin方法返回失败
- if (ret != (int)ErrorCode.MSP_SUCCESS)
- {
- return false;
- }
- ret = WindowsXFTTSUtils.QTTSTextPut(Ptr2Str(session_ID), text, (uint)Encoding.Default.GetByteCount(text), string.Empty);
- //QTTSTextPut方法返回失败
- if (ret != (int)ErrorCode.MSP_SUCCESS)
- {
- return false;
- }
- MemoryStream memoryStream = new MemoryStream();
- memoryStream.Write(new byte[44], 0, 44);
- while (true)
- {
- IntPtr source = WindowsXFTTSUtils.QTTSAudioGet(Ptr2Str(session_ID), ref audio_len, ref synth_status, ref ret);
- if (source != IntPtr.Zero)
- {
- byte[] array = new byte[(int)audio_len];
- if (audio_len > 0)
- {
- Marshal.Copy(source, array, 0, (int)audio_len);
- }
- memoryStream.Write(array, 0, array.Length);
- }
- if (synth_status == SynthStatus.MSP_TTS_FLAG_DATA_END || ret != 0)
- break;
- }
- WAVE_Header wave_Header = GetWave_Header((int)memoryStream.Length - 44);
- byte[] array2 = StructToBytes(wave_Header);
- memoryStream.Position = 0L;
- memoryStream.Write(array2, 0, array2.Length);
- memoryStream.Position = 0L;
- if (filename != null)
- {
- var dir = Path.GetDirectoryName(filename);
- if (!Directory.Exists(dir))
- Directory.CreateDirectory(dir);
- FileStream fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write);
- memoryStream.WriteTo(fileStream);
- memoryStream.Close();
- fileStream.Close();
- }
- return true;
- }
- catch (Exception ex)
- {
- return false;
- }
- finally
- {
- WindowsXFTTSUtils.QTTSSessionEnd(Ptr2Str(session_ID), "");
- WindowsXFTTSUtils.MSPLogout();//退出登录
- }
- }
- /// <summary>
- /// 结构体转字符串
- /// </summary>
- /// <param name="structure"></param>
- /// <returns></returns>
- private static byte[] StructToBytes(object structure)
- {
- int num = Marshal.SizeOf(structure);
- IntPtr intPtr = Marshal.AllocHGlobal(num);
- byte[] result;
- try
- {
- Marshal.StructureToPtr(structure, intPtr, false);
- byte[] array = new byte[num];
- Marshal.Copy(intPtr, array, 0, num);
- result = array;
- }
- finally
- {
- Marshal.FreeHGlobal(intPtr);
- }
- return result;
- }
- /// <summary>
- /// 结构体初始化赋值
- /// </summary>
- /// <param name="data_len"></param>
- /// <returns></returns>
- private static WAVE_Header GetWave_Header(int data_len)
- {
- return new WAVE_Header
- {
- RIFF_ID = 1179011410,
- File_Size = data_len + 36,
- RIFF_Type = 1163280727,
- FMT_ID = 544501094,
- FMT_Size = 16,
- FMT_Tag = 1,
- FMT_Channel = 1,
- FMT_SamplesPerSec = 16000,
- AvgBytesPerSec = 32000,
- BlockAlign = 2,
- BitsPerSample = 16,
- DATA_ID = 1635017060,
- DATA_Size = data_len
- };
- }
- /// <summary>
- /// 语音音频头
- /// </summary>
- private struct WAVE_Header
- {
- public int RIFF_ID;
- public int File_Size;
- public int RIFF_Type;
- public int FMT_ID;
- public int FMT_Size;
- public short FMT_Tag;
- public ushort FMT_Channel;
- public int FMT_SamplesPerSec;
- public int AvgBytesPerSec;
- public ushort BlockAlign;
- public ushort BitsPerSample;
- public int DATA_ID;
- public int DATA_Size;
- }
- /// 指针转字符串
- /// </summary>
- /// <param name="p">指向非托管代码字符串的指针</param>
- /// <returns>返回指针指向的字符串</returns>
- public static string Ptr2Str(IntPtr p)
- {
- List<byte> lb = new List<byte>();
- while (Marshal.ReadByte(p) != 0)
- {
- lb.Add(Marshal.ReadByte(p));
- p = p + 1;
- }
- return Encoding.Default.GetString(lb.ToArray());
- }
- }
- }
复制代码 Linux版- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Runtime.InteropServices;
- using System.IO;
- namespace Speech
- {
- /// <summary>
- /// 讯飞语音合成
- /// Author:String Lee
- /// Date:2021年12月15日 14:06:00
- /// </summary>
- public class LinuxXFTTSUtils
- {
- #region TTS枚举常量
- public enum ErrorCode
- {
- MSP_SUCCESS = 0,
- MSP_ERROR_FAIL = -1,
- MSP_ERROR_EXCEPTION = -2,
- /* General errors 10100(0x2774) */
- MSP_ERROR_GENERAL = 10100, /* 0x2774 */
- MSP_ERROR_OUT_OF_MEMORY = 10101, /* 0x2775 */
- MSP_ERROR_FILE_NOT_FOUND = 10102, /* 0x2776 */
- MSP_ERROR_NOT_SUPPORT = 10103, /* 0x2777 */
- MSP_ERROR_NOT_IMPLEMENT = 10104, /* 0x2778 */
- MSP_ERROR_ACCESS = 10105, /* 0x2779 */
- MSP_ERROR_INVALID_PARA = 10106, /* 0x277A */
- MSP_ERROR_INVALID_PARA_VALUE = 10107, /* 0x277B */
- MSP_ERROR_INVALID_HANDLE = 10108, /* 0x277C */
- MSP_ERROR_INVALID_DATA = 10109, /* 0x277D */
- MSP_ERROR_NO_LICENSE = 10110, /* 0x277E */
- MSP_ERROR_NOT_INIT = 10111, /* 0x277F */
- MSP_ERROR_NULL_HANDLE = 10112, /* 0x2780 */
- MSP_ERROR_OVERFLOW = 10113, /* 0x2781 */
- MSP_ERROR_TIME_OUT = 10114, /* 0x2782 */
- MSP_ERROR_OPEN_FILE = 10115, /* 0x2783 */
- MSP_ERROR_NOT_FOUND = 10116, /* 0x2784 */
- MSP_ERROR_NO_ENOUGH_BUFFER = 10117, /* 0x2785 */
- MSP_ERROR_NO_DATA = 10118, /* 0x2786 */
- MSP_ERROR_NO_MORE_DATA = 10119, /* 0x2787 */
- MSP_ERROR_SKIPPED = 10120, /* 0x2788 */
- MSP_ERROR_ALREADY_EXIST = 10121, /* 0x2789 */
- MSP_ERROR_LOAD_MODULE = 10122, /* 0x278A */
- MSP_ERROR_BUSY = 10123, /* 0x278B */
- MSP_ERROR_INVALID_CONFIG = 10124, /* 0x278C */
- MSP_ERROR_VERSION_CHECK = 10125, /* 0x278D */
- MSP_ERROR_CANCELED = 10126, /* 0x278E */
- MSP_ERROR_INVALID_MEDIA_TYPE = 10127, /* 0x278F */
- MSP_ERROR_CONFIG_INITIALIZE = 10128, /* 0x2790 */
- MSP_ERROR_CREATE_HANDLE = 10129, /* 0x2791 */
- MSP_ERROR_CODING_LIB_NOT_LOAD = 10130, /* 0x2792 */
- /* Error codes of network 10200(0x27D8)*/
- MSP_ERROR_NET_GENERAL = 10200, /* 0x27D8 */
- MSP_ERROR_NET_OPENSOCK = 10201, /* 0x27D9 */ /* Open socket */
- MSP_ERROR_NET_CONNECTSOCK = 10202, /* 0x27DA */ /* Connect socket */
- MSP_ERROR_NET_ACCEPTSOCK = 10203, /* 0x27DB */ /* Accept socket */
- MSP_ERROR_NET_SENDSOCK = 10204, /* 0x27DC */ /* Send socket data */
- MSP_ERROR_NET_RECVSOCK = 10205, /* 0x27DD */ /* Recv socket data */
- MSP_ERROR_NET_INVALIDSOCK = 10206, /* 0x27DE */ /* Invalid socket handle */
- MSP_ERROR_NET_BADADDRESS = 10207, /* 0x27EF */ /* Bad network address */
- MSP_ERROR_NET_BINDSEQUENCE = 10208, /* 0x27E0 */ /* Bind after listen/connect */
- MSP_ERROR_NET_NOTOPENSOCK = 10209, /* 0x27E1 */ /* Socket is not opened */
- MSP_ERROR_NET_NOTBIND = 10210, /* 0x27E2 */ /* Socket is not bind to an address */
- MSP_ERROR_NET_NOTLISTEN = 10211, /* 0x27E3 */ /* Socket is not listenning */
- MSP_ERROR_NET_CONNECTCLOSE = 10212, /* 0x27E4 */ /* The other side of connection is closed */
- MSP_ERROR_NET_NOTDGRAMSOCK = 10213, /* 0x27E5 */ /* The socket is not datagram type */
- /* Error codes of mssp message 10300(0x283C) */
- MSP_ERROR_MSG_GENERAL = 10300, /* 0x283C */
- MSP_ERROR_MSG_PARSE_ERROR = 10301, /* 0x283D */
- MSP_ERROR_MSG_BUILD_ERROR = 10302, /* 0x283E */
- MSP_ERROR_MSG_PARAM_ERROR = 10303, /* 0x283F */
- MSP_ERROR_MSG_CONTENT_EMPTY = 10304, /* 0x2840 */
- MSP_ERROR_MSG_INVALID_CONTENT_TYPE = 10305, /* 0x2841 */
- MSP_ERROR_MSG_INVALID_CONTENT_LENGTH = 10306, /* 0x2842 */
- MSP_ERROR_MSG_INVALID_CONTENT_ENCODE = 10307, /* 0x2843 */
- MSP_ERROR_MSG_INVALID_KEY = 10308, /* 0x2844 */
- MSP_ERROR_MSG_KEY_EMPTY = 10309, /* 0x2845 */
- MSP_ERROR_MSG_SESSION_ID_EMPTY = 10310, /* 0x2846 */
- MSP_ERROR_MSG_LOGIN_ID_EMPTY = 10311, /* 0x2847 */
- MSP_ERROR_MSG_SYNC_ID_EMPTY = 10312, /* 0x2848 */
- MSP_ERROR_MSG_APP_ID_EMPTY = 10313, /* 0x2849 */
- MSP_ERROR_MSG_EXTERN_ID_EMPTY = 10314, /* 0x284A */
- MSP_ERROR_MSG_INVALID_CMD = 10315, /* 0x284B */
- MSP_ERROR_MSG_INVALID_SUBJECT = 10316, /* 0x284C */
- MSP_ERROR_MSG_INVALID_VERSION = 10317, /* 0x284D */
- MSP_ERROR_MSG_NO_CMD = 10318, /* 0x284E */
- MSP_ERROR_MSG_NO_SUBJECT = 10319, /* 0x284F */
- MSP_ERROR_MSG_NO_VERSION = 10320, /* 0x2850 */
- MSP_ERROR_MSG_MSSP_EMPTY = 10321, /* 0x2851 */
- MSP_ERROR_MSG_NEW_RESPONSE = 10322, /* 0x2852 */
- MSP_ERROR_MSG_NEW_CONTENT = 10323, /* 0x2853 */
- MSP_ERROR_MSG_INVALID_SESSION_ID = 10324, /* 0x2854 */
- /* Error codes of DataBase 10400(0x28A0)*/
- MSP_ERROR_DB_GENERAL = 10400, /* 0x28A0 */
- MSP_ERROR_DB_EXCEPTION = 10401, /* 0x28A1 */
- MSP_ERROR_DB_NO_RESULT = 10402, /* 0x28A2 */
- MSP_ERROR_DB_INVALID_USER = 10403, /* 0x28A3 */
- MSP_ERROR_DB_INVALID_PWD = 10404, /* 0x28A4 */
- MSP_ERROR_DB_CONNECT = 10405, /* 0x28A5 */
- MSP_ERROR_DB_INVALID_SQL = 10406, /* 0x28A6 */
- MSP_ERROR_DB_INVALID_APPID = 10407, /* 0x28A7 */
- /* Error codes of Resource 10500(0x2904)*/
- MSP_ERROR_RES_GENERAL = 10500, /* 0x2904 */
- MSP_ERROR_RES_LOAD = 10501, /* 0x2905 */ /* Load resource */
- MSP_ERROR_RES_FREE = 10502, /* 0x2906 */ /* Free resource */
- MSP_ERROR_RES_MISSING = 10503, /* 0x2907 */ /* Resource File Missing */
- MSP_ERROR_RES_INVALID_NAME = 10504, /* 0x2908 */ /* Invalid resource file name */
- MSP_ERROR_RES_INVALID_ID = 10505, /* 0x2909 */ /* Invalid resource ID */
- MSP_ERROR_RES_INVALID_IMG = 10506, /* 0x290A */ /* Invalid resource image pointer */
- MSP_ERROR_RES_WRITE = 10507, /* 0x290B */ /* Write read-only resource */
- MSP_ERROR_RES_LEAK = 10508, /* 0x290C */ /* Resource leak out */
- MSP_ERROR_RES_HEAD = 10509, /* 0x290D */ /* Resource head currupt */
- MSP_ERROR_RES_DATA = 10510, /* 0x290E */ /* Resource data currupt */
- MSP_ERROR_RES_SKIP = 10511, /* 0x290F */ /* Resource file skipped */
- /* Error codes of TTS 10600(0x2968)*/
- MSP_ERROR_TTS_GENERAL = 10600, /* 0x2968 */
- MSP_ERROR_TTS_TEXTEND = 10601, /* 0x2969 */ /* Meet text end */
- MSP_ERROR_TTS_TEXT_EMPTY = 10602, /* 0x296A */ /* no synth text */
- /* Error codes of Recognizer 10700(0x29CC) */
- MSP_ERROR_REC_GENERAL = 10700, /* 0x29CC */
- MSP_ERROR_REC_INACTIVE = 10701, /* 0x29CD */
- MSP_ERROR_REC_GRAMMAR_ERROR = 10702, /* 0x29CE */
- MSP_ERROR_REC_NO_ACTIVE_GRAMMARS = 10703, /* 0x29CF */
- MSP_ERROR_REC_DUPLICATE_GRAMMAR = 10704, /* 0x29D0 */
- MSP_ERROR_REC_INVALID_MEDIA_TYPE = 10705, /* 0x29D1 */
- MSP_ERROR_REC_INVALID_LANGUAGE = 10706, /* 0x29D2 */
- MSP_ERROR_REC_URI_NOT_FOUND = 10707, /* 0x29D3 */
- MSP_ERROR_REC_URI_TIMEOUT = 10708, /* 0x29D4 */
- MSP_ERROR_REC_URI_FETCH_ERROR = 10709, /* 0x29D5 */
- /* Error codes of Speech Detector 10800(0x2A30) */
- MSP_ERROR_EP_GENERAL = 10800, /* 0x2A30 */
- MSP_ERROR_EP_NO_SESSION_NAME = 10801, /* 0x2A31 */
- MSP_ERROR_EP_INACTIVE = 10802, /* 0x2A32 */
- MSP_ERROR_EP_INITIALIZED = 10803, /* 0x2A33 */
- /* Error codes of TUV */
- MSP_ERROR_TUV_GENERAL = 10900, /* 0x2A94 */
- MSP_ERROR_TUV_GETHIDPARAM = 10901, /* 0x2A95 */ /* Get Busin Param huanid*/
- MSP_ERROR_TUV_TOKEN = 10902, /* 0x2A96 */ /* Get Token */
- MSP_ERROR_TUV_CFGFILE = 10903, /* 0x2A97 */ /* Open cfg file */
- MSP_ERROR_TUV_RECV_CONTENT = 10904, /* 0x2A98 */ /* received content is error */
- MSP_ERROR_TUV_VERFAIL = 10905, /* 0x2A99 */ /* Verify failure */
- /* Error codes of IMTV */
- MSP_ERROR_IMTV_SUCCESS = 11000, /* 0x2AF8 */ /* 成功 */
- MSP_ERROR_IMTV_NO_LICENSE = 11001, /* 0x2AF9 */ /* 试用次数结束,用户需要付费 */
- MSP_ERROR_IMTV_SESSIONID_INVALID = 11002, /* 0x2AFA */ /* SessionId失效,需要重新登录通行证 */
- MSP_ERROR_IMTV_SESSIONID_ERROR = 11003, /* 0x2AFB */ /* SessionId为空,或者非法 */
- MSP_ERROR_IMTV_UNLOGIN = 11004, /* 0x2AFC */ /* 未登录通行证 */
- MSP_ERROR_IMTV_SYSTEM_ERROR = 11005, /* 0x2AFD */ /* 系统错误 */
- /* Error codes of HCR */
- MSP_ERROR_HCR_GENERAL = 11100,
- MSP_ERROR_HCR_RESOURCE_NOT_EXIST = 11101,
- /* Error codes of http 12000(0x2EE0) */
- MSP_ERROR_HTTP_BASE = 12000, /* 0x2EE0 */
- /*Error codes of ISV */
- MSP_ERROR_ISV_NO_USER = 13000, /* 32C8 */ /* the user doesn't exist */
- }
- public enum SynthStatus
- {
- MSP_TTS_FLAG_STILL_HAVE_DATA = 1,
- MSP_TTS_FLAG_DATA_END = 2,
- MSP_TTS_FLAG_CMD_CANCELED = 0
- }
- #endregion
- #region TTS dll import
- [DllImport("libmsc.so", EntryPoint = "MSPLogin", CallingConvention = CallingConvention.Cdecl)]
- public static extern int MSPLogin(string user, string password, string configs);
- [DllImport("libmsc.so", EntryPoint = "MSPLogout", CallingConvention = CallingConvention.Cdecl)]
- public static extern int MSPLogout();
- [DllImport("libmsc.so", EntryPoint = "QTTSSessionBegin", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr QTTSSessionBegin(string _params, ref int errorCode);
- [DllImport("libmsc.so", EntryPoint = "QTTSTextPut", CallingConvention = CallingConvention.Cdecl)]
- public static extern int QTTSTextPut(string sessionID, string textString, uint textLen, string _params);
- [DllImport("libmsc.so", EntryPoint = "QTTSAudioGet", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr QTTSAudioGet(string sessionID, ref uint audioLen, ref SynthStatus synthStatus, ref int errorCode);
- [DllImport("libmsc.so", EntryPoint = "QTTSAudioInfo", CallingConvention = CallingConvention.Cdecl)]
- public static extern IntPtr QTTSAudioInfo(string sessionID);
- [DllImport("libmsc.so", EntryPoint = "QTTSSessionEnd", CallingConvention = CallingConvention.Cdecl)]
- public static extern int QTTSSessionEnd(string sessionID, string hints);
- #endregion
- /// <summary>
- /// 生成语音文件
- /// </summary>
- /// <param name="text"></param>
- /// <param name="filename"></param>
- /// <param name="speaker"></param>
- /// <param name="speed"></param>
- /// <returns></returns>
- public static bool GetAudio(string text, string filename, string speaker, int speed)
- {
- IntPtr session_ID = IntPtr.Zero;
- try
- {
- string login_configs = $"appid =xxx ";//登录参数,自己注册后获取的appid
- string type = speaker;
- uint audio_len = 0;
- SynthStatus synth_status = SynthStatus.MSP_TTS_FLAG_STILL_HAVE_DATA;
- var ret = LinuxXFTTSUtils.MSPLogin(string.Empty, string.Empty, login_configs);
- //MSPLogin方法返回失败
- if (ret != (int)ErrorCode.MSP_SUCCESS)
- {
- Console.WriteLine("1");
- return false;
- }
- //string _params = $"engine_type = purextts,rdn = 2, speed = {speed}, volume = 100, rcn = 0, voice_name={type}, tts_res_path =fo|res\\xtts\\{type}.jet;fo|res\\xtts\\common.jet, sample_rate = 16000";
- string _params = $"engine_type = purextts,voice_name={speaker}, text_encoding = UTF8, tts_res_path = fo|res/xtts/{speaker}.jet;fo|res/xtts/common.jet, sample_rate = 16000, speed = {speed}, volume = 100, pitch = 50, rdn = 2";
- //string _params = "ssm=1,ent=sms16k,vcn=xiaoyan,spd=medium,aue=speex-wb;7,vol=x-loud,auf=audio/L16;rate=16000";
- //string @params = "engine_type = local,voice_name=xiaoyan,speed=50,volume=50,pitch=50,rcn=1, text_encoding = UTF8, background_sound=1,sample_rate = 16000";
- session_ID = LinuxXFTTSUtils.QTTSSessionBegin(_params, ref ret);
- //QTTSSessionBegin方法返回失败
- if (ret != (int)ErrorCode.MSP_SUCCESS)
- {
- return false;
- }
- ret = LinuxXFTTSUtils.QTTSTextPut(Ptr2Str(session_ID), text, (uint)Encoding.Default.GetByteCount(text), string.Empty);
- //QTTSTextPut方法返回失败
- if (ret != (int)ErrorCode.MSP_SUCCESS)
- {
- return false;
- }
- MemoryStream memoryStream = new MemoryStream();
- memoryStream.Write(new byte[44], 0, 44);
- while (true)
- {
- IntPtr source = LinuxXFTTSUtils.QTTSAudioGet(Ptr2Str(session_ID), ref audio_len, ref synth_status, ref ret);
- if (source != IntPtr.Zero)
- {
- byte[] array = new byte[(int)audio_len];
- if (audio_len > 0)
- {
- Marshal.Copy(source, array, 0, (int)audio_len);
- }
- memoryStream.Write(array, 0, array.Length);
- }
- if (synth_status == SynthStatus.MSP_TTS_FLAG_DATA_END || ret != 0)
- break;
- }
- WAVE_Header wave_Header = GetWave_Header((int)memoryStream.Length - 44);
- byte[] array2 = StructToBytes(wave_Header);
- memoryStream.Position = 0L;
- memoryStream.Write(array2, 0, array2.Length);
- memoryStream.Position = 0L;
- if (filename != null)
- {
- var dir = Path.GetDirectoryName(filename);
- if (!Directory.Exists(dir))
- Directory.CreateDirectory(dir);
- FileStream fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write);
- memoryStream.WriteTo(fileStream);
- memoryStream.Close();
- fileStream.Close();
- }
- return true;
- }
- catch (Exception ex)
- {
- return false;
- }
- finally
- {
- LinuxXFTTSUtils.QTTSSessionEnd(Ptr2Str(session_ID), "");
- LinuxXFTTSUtils.MSPLogout();//退出登录
- }
- }
- /// <summary>
- /// 结构体转字符串
- /// </summary>
- /// <param name="structure"></param>
- /// <returns></returns>
- private static byte[] StructToBytes(object structure)
- {
- int num = Marshal.SizeOf(structure);
- IntPtr intPtr = Marshal.AllocHGlobal(num);
- byte[] result;
- try
- {
- Marshal.StructureToPtr(structure, intPtr, false);
- byte[] array = new byte[num];
- Marshal.Copy(intPtr, array, 0, num);
- result = array;
- }
- finally
- {
- Marshal.FreeHGlobal(intPtr);
- }
- return result;
- }
- /// <summary>
- /// 结构体初始化赋值
- /// </summary>
- /// <param name="data_len"></param>
- /// <returns></returns>
- private static WAVE_Header GetWave_Header(int data_len)
- {
- return new WAVE_Header
- {
- RIFF_ID = 1179011410,
- File_Size = data_len + 36,
- RIFF_Type = 1163280727,
- FMT_ID = 544501094,
- FMT_Size = 16,
- FMT_Tag = 1,
- FMT_Channel = 1,
- FMT_SamplesPerSec = 16000,
- AvgBytesPerSec = 32000,
- BlockAlign = 2,
- BitsPerSample = 16,
- DATA_ID = 1635017060,
- DATA_Size = data_len
- };
- }
- /// <summary>
- /// 语音音频头
- /// </summary>
- private struct WAVE_Header
- {
- public int RIFF_ID;
- public int File_Size;
- public int RIFF_Type;
- public int FMT_ID;
- public int FMT_Size;
- public short FMT_Tag;
- public ushort FMT_Channel;
- public int FMT_SamplesPerSec;
- public int AvgBytesPerSec;
- public ushort BlockAlign;
- public ushort BitsPerSample;
- public int DATA_ID;
- public int DATA_Size;
- }
- /// 指针转字符串
- /// </summary>
- /// <param name="p">指向非托管代码字符串的指针</param>
- /// <returns>返回指针指向的字符串</returns>
- public static string Ptr2Str(IntPtr p)
- {
- List<byte> lb = new List<byte>();
- while (Marshal.ReadByte(p) != 0)
- {
- lb.Add(Marshal.ReadByte(p));
- p = p + 1;
- }
- return Encoding.Default.GetString(lb.ToArray());
- }
- }
- }
复制代码 上面分别是Windows的普通版与Linux高品质版的调用代码,比较凌乱,用的时候可以再封装一下,还要记得把之前记下来的APPID填到代码里。
四、调用
- [ApiController]
- [Route("[controller]")]
- public class TextToSpeechController : ControllerBase
- {
- [HttpGet]
- public FileStreamResult GetWav(string text,string speaker)
- {
- var fileName = Guid.NewGuid().ToString() + ".wav";
- var mimeType = "application/....";
- if(string.IsNullOrEmpty(speaker))
- speaker = "xiaofeng";
- if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- LinuxXFTTSUtils.GetAudio(text, fileName, speaker, 50);
- else if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- WindowsXFTTSUtils.GetAudio(text, fileName, speaker, 50);
- Stream stream = System.IO.File.OpenRead(fileName);
- System.IO.File.Delete(fileName);
- return new FileStreamResult(stream, mimeType)
- {
- FileDownloadName = fileName
- };
- }
- }
复制代码 注意需要把下载的SDK包里面的bin目录内的文件拷贝到运行目录,如果是linux版,需要从libs里面拷贝libmsc.so库,speaker可以填xiaofeng或者xiaoyan,分别是男女声,需要更多的发音人可以去购买。
代码基本完整提供了,各位直接复制粘贴使用即可,离线SDK可以免费体验30天,过期了需要购买或者重新注册创建新应用来延续使用。不过既然都是离线版了,直接把电脑时间固定住应该也能继续白嫖。哈哈,个人学习使用的话可以,商用版还是要购买噢。
来源:https://www.cnblogs.com/DriftingLeaf/archive/2023/08/22/17648569.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|