unity 2022 TTS文本转语音方法,异步不堵塞,windows

前言

TTS方法有很多,如果想跨平台那就需要外部插件,而如果仅仅是windows那就没必要用插件来占用空间了。

具体方法:

随便找个空物体,添加以下脚本,然后在需要播报语音的位置添加这行代码即可播报:

        FlexibleTTS.Speak("确认定铲");

特点1:使用windows内置的tts功能,不用外部插件,节省空间。

特点2:不直接与api通讯,而是通过powershell来转接,原因是每台电脑的tts_api地址可能不同。

特点3:异步,不堵塞主线程

这是完整脚本:

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

public class FlexibleTTS : MonoBehaviour
{
    private static Process _psProcess;
    private static StreamWriter _inputWriter;
    private static bool _isChineseSupported;

    // 初始化长驻进程(建议在游戏启动时调用)
    [RuntimeInitializeOnLoadMethod]
    private static void Initialize()
    {
        StartPowerShellProcess();
    }

    private static void StartPowerShellProcess()
    {
        try {
            var psi = new ProcessStartInfo
            {
                FileName = "powershell.exe",
                Arguments = "-NoLogo -NoProfile -Command -",
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding = Encoding.UTF8
            };

            _psProcess = new Process { StartInfo = psi };
            _psProcess.OutputDataReceived += (sender, e) => UnityEngine.Debug.Log($"PS Output: {e.Data}");
            _psProcess.ErrorDataReceived += (sender, e) => UnityEngine.Debug.LogError($"PS Error: {e.Data}");
            _psProcess.Start();

            _inputWriter = _psProcess.StandardInput;
            _psProcess.BeginOutputReadLine();
            _psProcess.BeginErrorReadLine();

            // 检测中文语音支持
            _inputWriter.WriteLine(@"
                Add-Type -AssemblyName System.Speech;
                $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;
                $chineseVoice = $speak.GetInstalledVoices() | 
                    Where-Object { $_.VoiceInfo.Culture.Name -eq 'zh-CN' } | 
                    Select-Object -First 1;
                if ($chineseVoice -ne $null) { 
                    $speak.SelectVoice($chineseVoice.VoiceInfo.Name);
                    'CHINESE_SUPPORTED'
                } else { 
                    'CHINESE_NOT_SUPPORTED' 
                }
            ");
            _inputWriter.Flush();
        }
        catch (System.Exception e) {
            UnityEngine.Debug.LogError($"TTS Init Failed: {e.Message}");
        }
    }

    // 动态配置语音引擎(可选)
    public static void ConfigureVoice(string cultureName = "zh-CN", string voiceName = null)
    {
        if (_inputWriter == null || _psProcess.HasExited) return;

        _inputWriter.WriteLine($@"
            Add-Type -AssemblyName System.Speech;
            $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;
            {(string.IsNullOrEmpty(voiceName) ?
                $"$voice = $speak.GetInstalledVoices() | Where-Object {{ $_.VoiceInfo.Culture.Name -eq '{cultureName}' }} | Select-Object -First 1;" :
                $"$voice = $speak.GetInstalledVoices() | Where-Object {{ $_.VoiceInfo.Name -like '*{voiceName}*' }} | Select-Object -First 1;")}
            if ($voice -ne $null) {{ 
                $speak.SelectVoice($voice.VoiceInfo.Name);
                'VOICE_CONFIGURED'
            }} else {{
                'VOICE_NOT_FOUND'
            }}
        ");
        _inputWriter.Flush();
    }


    public static void Speak(string text)
    {
        if (_inputWriter == null || _psProcess.HasExited) {
            StartPowerShellProcess();
            return;
        }

        try {
            // 将文本转换为Base64编码
            byte[] textBytes = Encoding.UTF8.GetBytes(text);
            string base64Text = Convert.ToBase64String(textBytes);

            _inputWriter.WriteLine($@"
            $bytes = [System.Convert]::FromBase64String('{base64Text}');
            $decodedText = [System.Text.Encoding]::UTF8.GetString($bytes);
            $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;
            $speak.Speak($decodedText);
        ");
            _inputWriter.Flush();
        }
        catch (Exception e) {
            UnityEngine.Debug.LogError($"TTS Error: {e.Message}");
        }
    }

    // 异步语音合成(不阻塞主线程)
    public static async Task SpeakAsync(string text)
    {
        await Task.Run(() => Speak(text));
    }

    // 清理资源
    private void OnApplicationQuit()
    {
        if (_inputWriter != null) {
            _inputWriter.WriteLine("exit");
            _inputWriter.Close();
        }
        _psProcess?.Kill();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值