Unity 科大讯飞-文本转语音-超拟人语音合成

Unity 科大讯飞-文本转语音-超拟人语音合成

1、首先在unity中新建工程;设置一个输入框和按钮,我们要做的就是点击按钮,将输入的文本转语音。
简简单单
2、打开讯飞的超拟人语音合成界面
讯飞超拟人语音合成
讯飞超拟人语音合成-入口

3、进入服务管理,拿到老三样
ID、Secret、Key
4、下载通信工具-WebSocket-sharp
WebSockte-sharp-下载链接
解压后得到该目录
目录
5、在Unity中新建Plugins文件夹,将下载下来的【websocket-sharp】文件夹整个拖入
整个文件夹拖入
6、正常会出现报错
报错
没关系,只需要打开Edit-ProjectSetting-Player-OtherSettings
轻车熟路
差不多下拉到底部位置,取消勾选该选项
取消勾选该选项
报错消失nice!
如果没有报错那就忽略以上内容!

7、编写脚本。

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using WebSocketSharp;

public class XunfeiTTS : MonoBehaviour
{
    // 你的密钥
    private const string APPID = "*********";
    private const string APIKey = "*********";
    private const string APISecret = "*********";

    //固定
    private const string WsUrl = "wss://cbm01.cn-huabei-1.xf-yun.com/v1/private/mcd9m97e6";

    private WebSocket ws;
    private string outputPath;

    public InputField inputField;
    public Button playButton;
    private AudioSource audioSource;

    private readonly Queue<Action> mainThreadActions = new Queue<Action>();

    private void Start()
    {
        audioSource = gameObject.AddComponent<AudioSource>();

        if (playButton != null)
        {
            playButton.onClick.AddListener(OnPlayButtonClicked);
        }
    }

    private void Update()
    {
        while (mainThreadActions.Count > 0)
        {
            Action action = mainThreadActions.Dequeue();
            action?.Invoke();
        }
    }

    public void OnPlayButtonClicked()
    {
        if (inputField != null && !string.IsNullOrEmpty(inputField.text))
        {
            StartTTS(inputField.text, "tts_output.mp3");
        }
        else
        {
        }
    }

    public void StartTTS(string text, string outputFilePath = "demo.mp3")
    {
        outputPath = Path.Combine(Application.persistentDataPath, outputFilePath);

        // Delete existing file if it exists
        if (File.Exists(outputPath))
        {
            File.Delete(outputPath);
        }

        // Create auth URL
        string authUrl = AssembleWsAuthUrl(WsUrl, "GET", APIKey, APISecret);

        // Initialize WebSocket
        ws = new WebSocket(authUrl);
        ws.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;
        ws.SslConfiguration.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;

        // Set up event handlers
        ws.OnMessage += (sender, e) =>
        {
            // This runs on a background thread
            try
            {
                if (e.IsBinary) return;

                var message = JsonUtility.FromJson<TTSResponse>(e.Data);

                if (message.payload != null && message.payload.audio != null)
                {
                    byte[] audioData = Convert.FromBase64String(message.payload.audio.audio);

                    // File operations are thread-safe
                    using (var fileStream = new FileStream(outputPath, FileMode.Append))
                    {
                        fileStream.Write(audioData, 0, audioData.Length);
                    }

                    if (message.payload.audio.status == 2)
                    {
                        // Queue main thread actions
                        mainThreadActions.Enqueue(() =>
                        {
                            Debug.Log("TTS completed. File saved to: " + outputPath);
                            StartCoroutine(PlayAudioFile(outputPath));
                            ws.Close();
                        });
                    }
                }
                else if (message.header.code != 0)
                {
                    mainThreadActions.Enqueue(() =>
                    {
                        ws.Close();
                    });
                }
            }
            catch (Exception ex)
            {
                mainThreadActions.Enqueue(() => Debug.LogError($"错误信息: {ex.Message}"));
            }
        };

        ws.OnError += (sender, e) =>
            mainThreadActions.Enqueue(() => Debug.LogError($"WebSocket错误: {e.Message}"));

        ws.OnClose += (sender, e) =>
            mainThreadActions.Enqueue(() => Debug.Log($"WebSocket已关闭: {e.Reason}"));

        ws.OnOpen += (sender, e) =>
        {
            mainThreadActions.Enqueue(() =>
            {
                Debug.Log("发送中");
                SendTextData(text);
            });
        };

        // Connect
        ws.Connect();
    }

    private void SendTextData(string text)
    {
        var requestData = new TTSRequest
        {
            header = new CommonArgs { app_id = APPID, status = 2 },
            parameter = new BusinessArgs
            {
                tts = new TTSConfig
                {
                    vcn = "x4_lingxiaoxuan_oral",
                    volume = 50,
                    rhy = 0,
                    speed = 50,
                    pitch = 50,
                    bgs = 0,
                    reg = 0,
                    rdn = 0,
                    audio = new AudioConfig
                    {
                        encoding = "lame",
                        sample_rate = 24000,
                        channels = 1,
                        bit_depth = 16,
                        frame_size = 0
                    }
                }
            },
            payload = new DataPayload
            {
                text = new TextData
                {
                    encoding = "utf8",
                    compress = "raw",
                    format = "plain",
                    status = 2,
                    seq = 0,
                    text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text))
                }
            }
        };

        string jsonData = JsonUtility.ToJson(requestData);
        ws.Send(jsonData);
    }

    private IEnumerator PlayAudioFile(string filePath)
    {
        yield return new WaitForSeconds(0.5f);

        if (!File.Exists(filePath))
        {
            yield break;
        }

        string url = "file://" + filePath;
        using (WWW www = new WWW(url))
        {
            yield return www;

            if (string.IsNullOrEmpty(www.error))
            {
                audioSource.clip = www.GetAudioClip(false, false, AudioType.MPEG);
                while (audioSource.clip.loadState == AudioDataLoadState.Loading)
                {
                    yield return null;
                }

                if (audioSource.clip.loadState == AudioDataLoadState.Loaded)
                {
                    audioSource.Play();
                }
                else
                {
                }
            }
            else
            {
            }
        }
    }

    private string AssembleWsAuthUrl(string requestUrl, string method, string apiKey, string apiSecret)
    {
        Uri uri = new Uri(requestUrl);
        string host = uri.Host;
        string path = uri.AbsolutePath;

        string date = DateTime.UtcNow.ToString("r");
        string signatureOrigin = $"host: {host}\ndate: {date}\n{method} {path} HTTP/1.1";

        byte[] signatureSha = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret))
            .ComputeHash(Encoding.UTF8.GetBytes(signatureOrigin));
        string signature = Convert.ToBase64String(signatureSha);

        string authorizationOrigin = $"api_key=\"{apiKey}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{signature}\"";
        string authorization = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorizationOrigin));

        string query = $"?host={Uri.EscapeDataString(host)}&date={Uri.EscapeDataString(date)}&authorization={Uri.EscapeDataString(authorization)}";

        return requestUrl + query;
    }

    private void OnDestroy()
    {
        if (ws != null && ws.IsAlive)
        {
            ws.Close();
        }
    }

    // Data classes for JSON serialization
    [Serializable]
    private class TTSRequest
    {
        public CommonArgs header;
        public BusinessArgs parameter;
        public DataPayload payload;
    }

    [Serializable]
    private class CommonArgs
    {
        public string app_id;
        public int status;
    }

    [Serializable]
    private class BusinessArgs
    {
        public TTSConfig tts;
    }

    [Serializable]
    private class TTSConfig
    {
        public string vcn;
        public int volume;
        public int rhy;
        public int speed;
        public int pitch;
        public int bgs;
        public int reg;
        public int rdn;
        public AudioConfig audio;
    }

    [Serializable]
    private class AudioConfig
    {
        public string encoding;
        public int sample_rate;
        public int channels;
        public int bit_depth;
        public int frame_size;
    }

    [Serializable]
    private class DataPayload
    {
        public TextData text;
    }

    [Serializable]
    private class TextData
    {
        public string encoding;
        public string compress;
        public string format;
        public int status;
        public int seq;
        public string text;
    }

    [Serializable]
    private class TTSResponse
    {
        public ResponseHeader header;
        public ResponsePayload payload;
    }

    [Serializable]
    private class ResponseHeader
    {
        public int code;
        public string message;
        public string sid;
    }

    [Serializable]
    private class ResponsePayload
    {
        public ResponseAudio audio;
    }

    [Serializable]
    private class ResponseAudio
    {
        public string audio;
        public int status;
    }
}

8、添加脚本,添加对应组件
9、测试成功在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值