如何在SpeechSynthesizer中使用词典?

时间:2012-07-17 19:05:37

标签: c# text-to-speech

我正在执行一些文字转语音,我想在词典文件中指定一些特殊的发音。我已经逐字地运行了MSDN's AddLexicon example,它说的是句子,但使用给定的词典,似乎有些东西被打破了。

以下是提供的示例:

using System;
using Microsoft.Speech.Synthesis;

namespace SampleSynthesis
{
  class Program
  {
    static void Main(string[] args)
    {

      // Initialize a new instance of the SpeechSynthesizer.
      using (SpeechSynthesizer synth = new SpeechSynthesizer())
      {

        // Configure the audio output. 
        synth.SetOutputToDefaultAudioDevice();

        PromptBuilder builder = new PromptBuilder();
        builder.AppendText("Gimme the whatchamacallit.");

        // Append the lexicon file.
        synth.AddLexicon(new Uri("c:\\test\\whatchamacallit.pls"), "application/pls+xml");

        // Speak the prompt and play back the output file.
        synth.Speak(builder);
      }

      Console.WriteLine();
      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
    }
  }
}

和词典文件:

<lexicon version="1.0" 
      xmlns="http://www.w3.org/2005/01/pronunciation-lexicon"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://www.w3.org/2005/01/pronunciation-lexicon 
        http://www.w3.org/TR/2007/CR-pronunciation-lexicon-20071212/pls.xsd"
      alphabet="x-microsoft-ups" xml:lang="en-US">


  <lexeme>
    <grapheme> whatchamacallit </grapheme>
    <phoneme> W S1 AX T CH AX M AX K S2 AA L IH T </phoneme>
  </lexeme>

</lexicon>

控制台打开,说出文字,但不使用新发音。我当然按规定将文件保存到c:\test\whatchamacallit.pls

我尝试过Uri和文件位置的变体(例如@"C:\Temp\whatchamacallit.pls"@"file:///c:\test\whatchamacallit.pls"),绝对和相对路径,将其复制到构建文件夹等等。

我运行了Process Monitor,文件未被访问。如果它是一个目录/文件权限问题(它不是),我仍然会看到访问被拒绝的消息,但是我没有记录任何引用,除了偶尔从我的文本编辑器。我确实在尝试File.OpenRead时看到了该文件。

不幸的是,使用垃圾Uri时没有错误消息。

在进一步调查中,我意识到这个例子来自Microsoft.Speech.Synthesis,而我在这里使用System.Speech.Synthesis。但是从我可以看出它们是相同的,除了一些额外的信息和示例,并且两者都指向相同的规范。这仍然是问题吗?

我确认该项目已设置为使用正确的.NET Framework 4。

我将MSDN中的示例与examples from the referenced spec进行了比较,并尝试了这些,但它没有帮助。考虑到文件似乎没有被访问,我并不感到惊讶。

(我可以正常使用PromptBuilder.AppendTextWithPronunciation,但对于我的用例来说,这是一个不好的选择。)

MSDN上的示例是否已损坏?如何在SpeechSynthesizer中使用词典?

3 个答案:

答案 0 :(得分:10)

经过大量的研究和陷阱,我可以向你保证,你的假设是完全错误的。 出于某种原因System.Speech.Synthesis.SpeechSynthesizer.AddLexicon()将词典添加到内部列表中,但根本不使用它。 似乎之前没有人尝试使用它,这个错误被忽视了。

另一方面,

Microsoft.Speech.Synthesis.SpeechSynthesizer.AddLexicon()(属于Microsoft Speech SDK)按预期工作(它将词典传递给COM对象,该对象将其解释为广告)。

请参阅本指南,了解如何安装SDK:http://msdn.microsoft.com/en-us/library/hh362873%28v=office.14%29.aspx

注意:

  • 有人报告64位版本导致COM异常(因为库没有正确安装),我在64位Windows 7机器上证实了这一点
    • 使用x86版本可以解决问题
  • 确保在SDK之前安装运行时
  • 请务必同时安装运行时语言(如链接页面所示),因为SDK不使用默认的系统语音引擎

答案 1 :(得分:1)

最近我在Windows 10上对此进行了研究。

我发现了两件事。

您使用的任何语音都必须与Lexicon文件中的语言匹配。 在词典中,您具有以下语言:

<lexicon version="1.0"
      xmlns="http://www.w3.org/2005/01/pronunciation-lexicon"
      alphabet="x-microsoft-ups" xml:lang="en-US">

我发现我可以将Lexicon命名为“ blue.en-US.pls”,并使用“ blue.en-GB.pls”进行复制。里面会有xml:lang =“ en-GB”

在您要使用的代码中:

string langFile = Path.Combine(_appPath, $"blue.{synth.Voice.Culture.IetfLanguageTag}.pls");
synth.AddLexicon(new Uri(langFile), "application/pls+xml");

我发现的另一件事是,它根本不适用于“ Microsoft Zira Desktop-English(United States)”。我不知道为什么 这似乎是Windows 10上的默认声音。

在此处访问并更改您的默认语音: %windir%\ system32 \ speech \ SpeechUX \ SAPI.cpl

否则,您应该可以通过代码进行设置:

var voices = synth.GetInstalledVoices();
var voice = voices.First(v => v.VoiceInfo.Name.Contains("David"));   // US. David, Hazel, Zira
synth.SelectVoice(voice.VoiceInfo.Name);

我有David(美国)和Hazel(英国),并且与其中任何一个都可以正常工作。

答案 2 :(得分:1)

您可以使用System.Speech.Synthesis.SpeechSynthesizer.SpeakSsml()代替词典。

此代码将“ blue”的发音更改为“ yellow”,将“ dog”的发音更改为“ fish”。

SpeechSynthesizer synth = new SpeechSynthesizer();
string text = "This is a blue dog";
Dictionary<string, string> phonemeDictionary = new Dictionary<string, string> { { "blue", "jelow" }, { "dog", "fyʃ" } };
foreach (var element in phonemeDictionary)
{
   text = text.Replace(element.Key, "<phoneme ph=\"" + element.Value + "\">" + element.Key + "</phoneme>");
}
text = "<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" xml:lang=\"en-US\">" + text + "</speak>";
synth.SpeakSsml(text);