System.Speech.Synthesis 的事件信息中的流编号在哪里?

Where is the stream number in the event info for System.Speech.Synthesis?

可以让 SpeechSynthesizer 以异步方式朗读文本,例如:

Private WithEvents _Synth As New SpeechSynthesizer

Private Sub TextBox1_KeyUp(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyUp
    If e.KeyCode = Keys.Enter Then
        _Synth.SpeakAsync(New Prompt(Me.TextBox1.Text))
    End If
End Sub

SpeechSynthesizer 生成的事件使我们能够分辨出计算机语音正在说什么。

例如,您可以通过选择这样的字符来可视化语音输出:

Private Sub _Synth_SpeakProgress(sender As Object, e As SpeakProgressEventArgs) Handles _Synth.SpeakProgress

    Me.TextBox1.SelectionStart = e.CharacterPosition
    Me.TextBox1.SelectionLength = e.CharacterCount

End Sub

然而,当 SpeakAsync 被重复调用时(例如,当我们告诉 SpeechSyntesizer 说出相同的文本时,它正在说话),语音请求被排队,并且 SpeechSynthesizer 一一播放。

但是,我一直没能查明合成器当前在说哪个请求。 SpeakProgressEventArgs 不显示 this:

使用 SAPI5,事件提供了 StreamNumber:

Parameters
StreamNumber
    The stream number which generated the event. When a voice enqueues more than one stream by speaking asynchronously, the stream number is necessary to associate an event with the appropriate stream.

使用这个 StreamNumber,你总能知道 SpeechSynthesizer 正在播放/说话的内容。

System.Speech.Synthesis 实现是 SAPI5 实现的现代版本。

但是,我就是找不到 StreamNumber 指标或类似信息。

System.Speech.Synthesis 提供有关刚刚发生的一切的信息,因此它极不可能不提供它正在处理的请求的信息。

如何找回?

还有另一种方法可以获取当前正在处理的句子。您可以为您的句子分配选择编号,然后您可以通过获取该句子的索引来识别语音;您可以进一步处理条件。使用 SpeechRecognized 方法的 SpeechRecognizedEventArgs 参数获取句子索引。

void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
  string txt = e.Result.Text;
  int sentenceIndex = txt.IndexOf("My Sentence");

  if (sentenceIndex >= 0)
  {
    Console.WriteLine("Currently Speaking Sentence: My Sentence, with index number: " 
                 + sentenceIndex);
  }

  //.... some code here
}

遵循完整示例 here


编辑 1:

The class-scope SpeechSynthesizer object gives the application the ability to speak. The SpeechRecognitionEngine object allows the application to listen for and recognize spoken words or phrases.

为了澄清我关于使用 Prompt Class 来保存您需要的任何标识状态的评论,请考虑以下内容,其中 Prompt 保存对源 TextBox.[=23 的引用=]

Imports System.Speech.Synthesis
Public Class MyPrompt : Inherits Prompt
    Private tbRef As WeakReference(Of TextBox)

    Public Sub New(textBox As TextBox)
        MyBase.New(textBox.Text)
        ' only hold a weak reference to the TextBox
        ' to avoid any disposal issues
        tbRef = New WeakReference(Of TextBox)(textBox)
    End Sub

    Public ReadOnly Property SourceTextBox As TextBox
        Get
            Dim ret As TextBox = Nothing
            tbRef.TryGetTarget(ret)
            Return ret
        End Get
    End Property
End Class

现在你的原始代码可以写成:

Imports System.Speech.Synthesis

Public Class Form1
    Private WithEvents _Synth As New SpeechSynthesizer

    Private Sub TextBox1_KeyUp(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyUp
        If e.KeyCode = Keys.Enter Then
            ' use a custom prompt to store the TextBox
            _Synth.SpeakAsync(New MyPrompt(Me.TextBox1))
        End If
    End Sub

    Private Sub _Synth_SpeakProgress(sender As Object, e As SpeakProgressEventArgs) Handles _Synth.SpeakProgress
        Dim mp As MyPrompt = TryCast(e.Prompt, MyPrompt)
        If mp IsNot Nothing Then
            Dim tb As TextBox = mp.SourceTextBox
            If tb IsNot Nothing Then
                ' set the selection in the source TextBox
                tb.SelectionStart = e.CharacterPosition
                tb.SelectionLength = e.CharacterCount
            End If
        End If
    End Sub

End Class

编辑:

OP 希望在调用 SpeechSynthesizer.SpeakAsync(created_prompt).

后将其与 SpeakSsmlAsync method. That in itself is not possible as that method creates a base Prompt using the Prompt(String, SynthesisTextFormat) Constructor 和 returns 一起使用创建的 Prompt

下面是派生的 Prompt class,它接受 ssml 字符串或 PromptBuilder instance 以及一个整数标识符。 新版本的 MyPrompt 使用 ssml 和整数标识符。

Imports System.Speech.Synthesis

Public Class MyPromptV2 : Inherits Prompt
    Public Sub New(ssml As String, identifier As Int32)
        MyBase.New(ssml, SynthesisTextFormat.Ssml)
        Me.Identifier = identifier
    End Sub

    Public Sub New(builder As PromptBuilder, identifier As Int32)
        MyBase.New(builder)
        Me.Identifier = identifier
    End Sub

    Public ReadOnly Property Identifier As Int32
End Class

...

Imports System.Speech.Synthesis

Public Class Form1
    Private WithEvents _Synth As New SpeechSynthesizer

    Private Sub TextBox1_KeyUp(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyUp
        If e.KeyCode = Keys.Enter Then
            ' build some ssml from the text
            Dim pb As New PromptBuilder
            pb.AppendText(TextBox1.Text)
            ' use ssml and and integer
            _Synth.SpeakAsync(New MyPrompt(pb.ToXml, 10))
            ' or 
            '_Synth.SpeakAsync(New MyPrompt(pb, 10))
        End If
    End Sub

    Private Sub _Synth_SpeakProgress(sender As Object, e As SpeakProgressEventArgs) Handles _Synth.SpeakProgress
        Dim mp As MyPromptV2 = TryCast(e.Prompt, MyPromptV2)
        If mp IsNot Nothing Then
            Select Case mp.Identifier
                Case 10
                    TextBox1.SelectionStart = e.CharacterPosition
                    TextBox1.SelectionLength = e.CharacterCount
            End Select
        End If
    End Sub
End Class