You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中使用SpInprocRecoContext识别语音事件及获取SAPI音素集

我来帮你搞定这两个和SAPI 5.4、SpInprocRecoContext相关的问题,结合你修改Windows语音词典的项目场景来一步步拆解:

一、使用SpInprocRecoContext识别语音事件

SpInprocRecoContext是SAPI的进程内识别上下文,和SpSharedRecoContext的核心区别在于它不依赖系统共享的识别服务,更适合离线处理(比如你要处理WAV文件的场景)。要识别语音事件,核心步骤是初始化上下文、绑定音频源、设置识别语法、注册事件回调:

  1. 初始化Inproc识别上下文与音频输入
    首先要创建SpInprocRecoContext实例,如果你是处理WAV文件,需要用SpFileStream加载音频文件并设置为上下文的音频输入流:

    using SpeechLib;
    
    // 创建进程内识别上下文
    var recoContext = new SpInprocRecoContext();
    // 加载WAV文件作为音频源(确保WAV是PCM格式,16位、16kHz单声道,符合SAPI要求)
    var audioStream = new SpFileStream();
    audioStream.Open(@"C:\your-audio-file.wav", SpeechStreamFileMode.SSFMOpenForRead, false);
    recoContext.AudioInputStream = audioStream;
    
  2. 设置识别语法并注册事件
    你需要创建针对目标词汇的语法(如果是全局识别可以用系统语法,但你的场景是指定词汇,所以自定义语法更高效),然后注册Recognition事件(识别完成时触发)和Hypothesis事件(识别过程中的临时结果):

    // 创建自定义语法
    var grammar = recoContext.CreateGrammar(1);
    grammar.DictationSetState(SpeechRuleState.SGDSDisabled); // 禁用听写模式
    // 方式1:从XML文件加载语法
    grammar.CmdLoadFromFile(@"C:\your-custom-grammar.xml", SpeechLoadOption.SLOStatic);
    // 方式2:直接添加单个指定词汇
    // var rule = grammar.Rules.Add("TargetWord", SpeechRuleAttributes.SRATopLevel | SpeechRuleAttributes.SRADynamic, 1);
    // rule.InitialState.AddWordTransition(null, "你的目标词汇", "", 1, null);
    // grammar.Rules.Commit();
    
    // 注册识别事件
    recoContext.Recognition += new _ISpRecoContextEvents_RecognitionEventHandler(RecoContext_Recognition);
    recoContext.Hypothesis += new _ISpRecoContextEvents_HypothesisEventHandler(RecoContext_Hypothesis);
    
    // 启动识别
    recoContext.Recognizer.SetRecoState(SpeechRecoState.SPRSActive);
    
  3. 实现事件回调逻辑
    在事件方法里处理识别结果,比如获取识别到的文本、置信度或者后续要提取的音素:

    private void RecoContext_Recognition(int StreamNumber, object StreamPosition, SpeechRecognitionType RecognitionType, ISpRecoResult Result)
    {
        // 获取识别到的文本
        string recognizedText = Result.PhraseInfo.GetText(0, -1, true);
        Console.WriteLine($"识别完成:{recognizedText}");
    
        // 音素提取逻辑会在第二部分详细说明
    }
    
    private void RecoContext_Hypothesis(int StreamNumber, object StreamPosition, ISpRecoResult Result)
    {
        string tempText = Result.PhraseInfo.GetText(0, -1, true);
        Console.WriteLine($"临时识别结果:{tempText}");
    }
    
二、获取指定词汇的SAPI音素集(基于WAV文件输入)

你的核心需求是用SpInprocRecoContext处理WAV,然后提取指定词汇的音素。这里的关键是确保识别结果精准匹配目标词汇,然后从ISpRecoResult中提取音素信息:

  1. 构建精准匹配的自定义语法
    为了避免识别歧义,最好创建只包含目标词汇的极简语法,比如:

    var grammar = recoContext.CreateGrammar(1);
    grammar.DictationSetState(SpeechRuleState.SGDSDisabled);
    var rule = grammar.Rules.Add("TargetVocab", SpeechRuleAttributes.SRATopLevel | SpeechRuleAttributes.SRADynamic, 1);
    // 添加你需要获取音素的指定词汇,比如"苹果"
    rule.InitialState.AddWordTransition(null, "苹果", "", 1, null);
    grammar.Rules.Commit();
    grammar.CmdSetRuleState("TargetVocab", SpeechRuleState.SGDSActive);
    
  2. 从识别结果中提取音素
    在Recognition事件的ISpRecoResult对象中,你可以通过两种方式获取音素:

    private void RecoContext_Recognition(int StreamNumber, object StreamPosition, SpeechRecognitionType RecognitionType, ISpRecoResult Result)
    {
        // 方式1:直接获取词汇的音素字符串(SAPI采用美式音标变体,格式如"AA1 P AH0 L")
        ISpPhraseElements elements = Result.PhraseInfo.Elements;
        for (int i = 0; i < elements.Count; i++)
        {
            ISpPhraseElement element = elements.Item(i);
            string phonemes = element.Phonetic;
            if (!string.IsNullOrEmpty(phonemes))
            {
                Console.WriteLine($"词汇「{element.DisplayText}」的音素集:{phonemes}");
            }
        }
    
        // 方式2:获取带时间戳的详细音素信息
        SpPhoneme[] phonemeArray;
        Result.GetPhonemes(out phonemeArray);
        foreach (var phoneme in phonemeArray)
        {
            Console.WriteLine($"音素ID:{phoneme.PhonemeID},起始位置:{phoneme.StartTime},结束位置:{phoneme.EndTime}");
        }
    }
    
  3. 关键注意事项

    • 确保WAV文件格式符合SAPI要求:必须是PCM编码、16位深度、16kHz采样率、单声道,否则SAPI无法正确解析音频。
    • 如果识别结果不准确,可以调整AddWordTransition的第4个参数(权重值,越大优先级越高),或者提前用SpLexicon类预查词汇的标准音素做对比。
    • 处理完音频后记得释放资源:audioStream.Close(); recoContext = null;

内容的提问来源于stack exchange,提问作者Exergist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:41:41