C#调用SAPI语音合成的两种实现方式

顾言
顾言
发布时间:2026-10-14 | 4人浏览过
原创

在Windows环境下开发语音应用,微软内置的SAPI(Speech Application Programming Interface)是最高效的选择。本文详细解析在C#中实现语音合成的两种主流技术路径:一是通过引入COM组件SpeechLib直接调用底层接口,二是利用.NET Framework自带的System.Speech命名空间进行封装操作。

方法一:使用COM组件 SpeechLib

这种方法直接调用系统的SAPI COM对象。其优势在于兼容性较好,能够在XP至Windows 7等系统中稳定运行,并且对发音引擎的控制较为精细。使用前需要在项目中添加对 SPIPELib.dll(或系统自带的SpeechLib类型库)的引用。

第1步:初始化语音对象

通过单例模式管理语音实例,确保内存中的唯一性,并使用 SpVoiceClass 创建语音对象。这种方式需要手动处理对象的生命周期。

public class Speech
{
    private static Speech _Instance = null;
    private SpeechLib.SpVoiceClass voice = null;

    private Speech()
    {
        BuildSpeech();
    }

    public static Speech Instance()
    {
        if (_Instance == null)
            _Instance = new Speech();
        return _Instance;
    }

    private void BuildSpeech()
    {
        if (voice == null)
            voice = new SpVoiceClass();
    }
}

第2步:设置音色与语言切换

SAPI允许获取系统中安装的所有语音列表。可以通过索引选择特定的语音引擎(如中文或英文TTS引擎)。注意:索引位置取决于用户安装的具体语音包,通常第一个为默认中文,第二个可能为英文或其他语言。

private void SetChinaVoice()
{
    // 获取语音列表并选择第0个(通常为中文)
    voice.Voice = voice.GetVoices(string.Empty, string.Empty).Item(0);
}

private void SetEnglishVoice()
{
    // 获取语音列表并选择第1个(需确认系统存在该语音)
    voice.Voice = voice.GetVoices(string.Empty, string.Empty).Item(1);
}

第3步:实现核心朗读逻辑

核心的 Speak 方法使用 SpeakAsync 标志位实现异步朗读,避免阻塞主线程。同时提供音量(Volume)和语速(Rate)的属性封装。

public void Speak(string text, SpeechVoiceSpeakFlags flags)
{
    try
    {
        // SVSFlagsAsync 表示异步朗读
        voice.Speak(text, flags);
    }
    catch (Exception err)
    {
        throw new Exception("朗读失败: " + err.Message);
    }
}

public int Volume
{
    get { return voice.Volume; }
    set { voice.SetVolume((ushort)value); }
}

public int Rate
{
    get { return voice.Rate; }
    set { voice.SetRate(value); }
}

第4步:处理中英文混合朗读

为了获得更自然的发音效果,需要对输入文本进行分词判断,分别调用中文或英文语音对象进行朗读。以下示例展示了简单的字符范围判断逻辑:

public void AnalyseSpeak(string strSpeak)
{
    int iCbeg = 0, iEbeg = 0;
    bool IsChina = true;

    for (int i = 0; i < strSpeak.Length; i++)
    {
        char chr = strSpeak[i];
        // 简单判断是否为ASCII字母(英文)
        if (IsChina)
        {
            if (chr >= 65 && chr <= 122)
            {
                string sub = strSpeak.Substring(iCbeg, i - iCbeg);
                SetChinaVoice();
                Speak(sub, SpeechVoiceSpeakFlags.SVSFlagsAsync);
                iEbeg = i;
                IsChina = false;
            }
        }
        else
        {
            if (chr > 122 || chr < 65)
            {
                string sub = strSpeak.Substring(iEbeg, i - iEbeg);
                SetEnglishVoice();
                Speak(sub, SpeechVoiceSpeakFlags.SVSFlagsAsync);
                iCbeg = i;
                IsChina = true;
            }
        }
    }
    // 处理剩余未朗读的部分
    if (IsChina)
    {
        string sub = strSpeak.Substring(iCbeg);
        SetChinaVoice();
        Speak(sub, SpeechVoiceSpeakFlags.SVSFlagsAsync);
    }
    else
    {
        string sub = strSpeak.Substring(iEbeg);
        SetEnglishVoice();
        Speak(sub, SpeechVoiceSpeakFlags.SVSFlagsAsync);
    }
}

方法二:使用 .NET System.Speech 命名空间

从 .NET Framework 3.0 开始,微软提供了托管类的语音合成 API。这种方法不需要引用外部COM库,代码更加简洁,且自动处理了部分底层资源释放。但需注意,该方法依赖 Windows Vista/7 及以上版本的 SAPI 5.x 集成库。

第1步:引入命名空间与实例化

必须添加对 System.Speech.dll 的引用,并引入 System.Speech.Synthesis 命名空间。使用 SpeechSynthesizer 类作为核心对象。

using System.Speech.Synthesis;

public class TtsReader
{
    private SpeechSynthesizer synth = new SpeechSynthesizer();
    
    public TtsReader(int volume = 80, int rate = 0)
    {
        // 设置音量 [0-100]
        synth.Volume = volume;
        // 设置语速 [-10~10],负值慢,正值快
        synth.Rate = rate;
    }
}

第2步:指定语音引擎

不同操作系统安装的语音包不同。可以通过 SelectVoice 方法指定具体的语音名称,如 Microsoft Lili(中文)或英文语音。ListInstalledVoices 可以列出当前系统所有可用的语音。

public void ReadChinese(string text)
{
    try
    {
        // 指定使用中文语音
        synth.SelectVoice("Microsoft Lili"); 
        // 同步朗读
        synth.Speak(text);
    }
    catch (Exception)
    {
        // 若未找到指定语音,可回退到默认语音
        synth.Speak(text);
    }
}

public void ReadEnglish(string text)
{
    // 指定英文语音,例如 "VW Julie" 或其他已安装的英文名
    synth.SelectVoice("Microsoft Anna");
    synth.SpeakAsync(text);
}

第3步:属性管理与控制

与COM方式类似,可以通过属性封装访问音量和语速。此外,Sysstem.Speech 还支持将语音输出保存为WAV文件,只需调用 SetOutputToWaveFile 即可。

public int Volume
{
    get { return synth.Volume; }
    set { synth.Volume = value; }
}

public int Rate
{
    get { return synth.Rate; }
    set { synth.Rate = value; }
}

// 导出为音频文件示例
public void SaveToWav(string path, string text)
{
    synth.SetOutputToWaveFile(path);
    synth.Speak(text);
    synth.SetOutputToDefaultAudioDevice(); // 恢复默认输出设备
}

总结与对比

两种方式各有适用场景:SPIPELib/SAPI COM 方式灵活性高,适合需要精细控制底层SAPI特性或在旧系统(如XP)上运行的项目,但需要注意COM互操作的性能开销。System.Speech 方式则是现代C#开发的首选,代码可读性强,维护成本低,且天然支持异步操作和音频文件导出,推荐用于Win7及之后的Windows环境开发。

以上就是C#中调用SAPI实现语音合成的2种方法的详细内容,更多关于C#语音合成(SAPI)的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表