Unity使用sherpa-onnx实现说话人识别

网友软绵绵的面包人推荐,模型3dspeaker_speech_eres2net_base_200k_sv_zh-cn_16k-common.onnx的效果比3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx要好

在这里插入图片描述

具体代码

using System;
using System.Collections.Generic;
using System.IO;
using SherpaOnnx;
using UnityEngine;

public class SpeakerIdentification : MonoBehaviour
{
    SpeakerEmbeddingExtractor extractor;
    SpeakerEmbeddingManager manager;
    string pathRoot;
    string modelPath;

    OfflineSpeechDenoiser offlineSpeechDenoiser = null;

    string[] testFiles;

    // Start is called before the first frame update
    void Start()
    {
        pathRoot = Util.GetPath();
        modelPath = pathRoot + "/3dspeaker_speech_eres2net_base_200k_sv_zh-cn_16k-common.onnx";

    }

    public void Init()
    {
        OfflineSpeechDenoiserGtcrnModelConfig osdgmc = new OfflineSpeechDenoiserGtcrnModelConfig();
        osdgmc.Model = pathRoot + "/gtcrn_simple.onnx";
        OfflineSpeechDenoiserModelConfig osdmc = new OfflineSpeechDenoiserModelConfig();
        osdmc.NumThreads = 1;
        osdmc.Provider = "cpu";
        osdmc.Debug = 0;
        osdmc.Gtcrn = osdgmc;
        OfflineSpeechDenoiserConfig osdc = new OfflineSpeechDenoiserConfig();
        osdc.Model = osdmc;
        offlineSpeechDenoiser = new OfflineSpeechDenoiser(osdc);
        //byte[] bytes = File.ReadAllBytes(pathRoot + "/xuefei.wav");
        //float[] data = BytesToFloat(bytes);
        //DenoisedAudio denoisedAudio = offlineSpeechDenoiser.Run(data, 16000);

        //if (denoisedAudio.SaveToWaveFile(pathRoot + "/xuefei1.wav"))
        //{

        //}

        var config = new SpeakerEmbeddingExtractorConfig();
        config.Model = modelPath;
        config.Debug = 1;
        extractor = new SpeakerEmbeddingExtractor(config);
        manager = new SpeakerEmbeddingManager(extractor.Dim);

        var spk1Files =
            new string[] {
          pathRoot+"/xuefei1.wav",
            };
        var spk1Vec = new float[spk1Files.Length][];

        for (int i = 0; i < spk1Files.Length; ++i)
        {
            spk1Vec[i] = ComputeEmbedding(extractor, spk1Files[i]);
        }

        // 给注册音频降噪一下
        //byte[] bytes = File.ReadAllBytes(pathRoot + "/xuefei1.wav");
        //float[] data = BytesToFloat(bytes);
        //DenoisedAudio denoisedAudio = offlineSpeechDenoiser.Run(data, 16000);
        //if (denoisedAudio.SaveToWaveFile(pathRoot + "/xuefei1.wav"))
        //{

        //}

        //注册说话人
        if (!manager.Add("xuefei", spk1Vec))
        {
            Debug.LogError("Failed to register xuefei");
        }

        var allSpeakers = manager.GetAllSpeakers();
        foreach (var s in allSpeakers)
        {
            Debug.Log(s);
        }

        //验证测试
        testFiles =
        new string[] {
          pathRoot+"/test1.wav",
          pathRoot+"/test2.wav",
          pathRoot+"/test3.wav",
        };
        float threshold = 0.6f;
        foreach (var file in testFiles)
        {
            var embedding = ComputeEmbedding(extractor, file);
            var name = manager.Search(embedding, threshold);
            if (name == "")
            {
                name = "<Unknown>";
            }
            Debug.Log(file + " :" + name);
        } 
    }

    /// <summary>
    /// 说话人识别 用的临时数据
    /// </summary>
    List<float> audioData = new List<float>();
    public void AcceptData(float[] data)
    {
        audioData.AddRange(data);
    }

    float threshold = 0.6f;

    public void Search()
    { 
        string filePath = pathRoot + "/" + DateTime.Now.ToFileTime().ToString() + ".wav";
        //DenoisedAudio denoisedAudio = offlineSpeechDenoiser.Run(audioData.ToArray(), 16000); 
        //if (denoisedAudio.SaveToWaveFile(filePath))
        //{

        //}
        Util.SaveClip(1, 16000, audioData.ToArray(), filePath);
        var embedding = ComputeEmbedding(extractor, filePath);
        string name = manager.Search(embedding, threshold);
        if (name == "")
        {
            name = "<Unknown>";
        }
        Debug.Log("name:" + name);
        audioData.Clear();
    }

    public float[] ComputeEmbedding(SpeakerEmbeddingExtractor extractor, string filename)
    {
        byte[] bytes = File.ReadAllBytes(filename);
        float[] data = BytesToFloat(bytes);
        var stream = extractor.CreateStream();
        stream.AcceptWaveform(16000, data);
        stream.InputFinished();
        var embedding = extractor.Compute(stream);
        return embedding;
    }

    public float[] ComputeEmbedding(SpeakerEmbeddingExtractor extractor, int sample, float[] data)
    {
        var stream = extractor.CreateStream();
        stream.AcceptWaveform(sample, data);
        stream.InputFinished();
        var embedding = extractor.Compute(stream);
        return embedding;
    }

    public float[] BytesToFloat(byte[] byteArray)
    {
        float[] sounddata = new float[byteArray.Length / 2];
        for (int i = 0; i < sounddata.Length; i++)
        {
            sounddata[i] = BytesToFloat(byteArray[i * 2], byteArray[i * 2 + 1]);
        }
        return sounddata;
    }

    private float BytesToFloat(byte firstByte, byte secondByte)
    {
        //小端和大端顺序要调整
        short s;
        if (BitConverter.IsLittleEndian)
            s = (short)((secondByte << 8) | firstByte);
        else
            s = (short)((firstByte << 8) | secondByte);
        // convert to range from -1 to (just below) 1
        return s / 32768.0F;
    }
}

最后是工程地址

https://github.com/xue-fei/sherpa-onnx-unity

### 使用Sherpa ONNXUnity中进行语音识别 #### 下载并配置必要的依赖项 为了使 Sherpa ONNX 能够在 Unity 中工作,首先需要确保安装了所有必需的库和工具。这通常涉及下载特定版本的 Sherpa ONNX 库以及任何其他所需的第三方组件[^2]。 ```csharp using UnityEngine; // 导入所需命名空间 using System.Runtime.InteropServices; // 用于调用本地函数 ``` #### 集成语音识别模型到Unity项目 一旦准备好了开发环境,下一步就是集成预先训练好的语音识别模型至 Unity 工程内。考虑到性能优化与兼容性的需求,建议选用官方提供的适用于目标平台(如Android、iOS 或 Windows)的最佳实践指南来完成此过程[^1]。 #### 编写C#脚本来处理音频输入及结果解析 通过编写自定义 C# 类可以轻松地捕获麦克风数据流并将这些信息传递给底层的 Sherpa ONNX 引擎以执行实际的识别任务。下面是一个简单的例子展示了如何设置这样的逻辑: ```csharp public class SpeechRecognizer : MonoBehaviour { private IntPtr recognizer; void Start() { // 初始化语音识别引擎实例 recognizer = InitSpeechRecognizer(); // 开始监听来自用户的语音命令 Microphone.Start(null, true, 10, AudioSettings.outputSampleRate); } void Update() { if (Microphone.IsRecording(null)) { float[] samples = new float[AudioSettings.outputSampleRate]; AudioClip clip = Microphone.GetPosition(null) != null ? Microphone.Start().samples : null; if(clip.GetData(samples)){ ProcessAudioSamples(samples); } } } [DllImport("__Internal")] private static extern IntPtr InitSpeechRecognizer(); [DllImport("__Internal")] private static extern string Recognize(IntPtr handle, float[] audioData); private void ProcessAudioSamples(float[] data){ Debug.Log($"Recognized Text: {Recognize(recognizer, data)}"); } } ``` 上述代码片段假设存在两个外部方法 `InitSpeechRecognizer` 和 `Recognize` 来初始化语音识别器对象并与之交互。这两个方法的具体实现在不同平台上会有所差异,并且可能涉及到跨平台插件或原生代码的支持[^3]。 #### 解决潜在的技术挑战 值得注意的是,在某些情况下可能会遇到一些技术难题,比如当尝试将 Sherpa ONNX 整合进 Unity 的时候遇到了不寻常的声音问题——即所谓的“奇怪尾音”。尽管这个问题只发生在编辑器模式下而不在最终发布的应用程序里显现出来,仍然值得进一步调查其背后的原因以便更好地理解整个系统的运作机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地狱为王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值