Text to Speech With Highlight Text Support in WPF

In this article you will learn how to highlight TEXT while text is being read in WPF.

We have all heard about "Text to Speech" software, in other words TTS / speech synthesis or we can also say a speech engine. This software is used to transform the text into speech and is commonly used with voice recognition software or programs. In my previous article "Text to Speech" I have described it in detail.

How Text to Speech works

Applications initiate speech generation by sending a set of words to the Speech Manager and the speech manager is responsible for sending the text to a speech synthesizer. To determine how to pronounce text it uses built-in dictionaries and pronunciation rules. The speech synthesizer uses these rules and the available PlainTalk voices to convert typed text into various kinds of sound, with various tonal qualities, to produce speech.

Users who have more RAM and processing power may choose a higher-quality voice, that may use a higher-quality synthesizer. A higher-quality synthesizer spends more time analyzing the original text, to try and produce sound that we more easily recognize as regular speech.

Now, here I am explaining the highlighting of text while it is being read, in other words when we write something on the window and command it to speak, then the word that is spoken should be highlighted also. For this I have made some changes in my application "TEXT TO SPEECH".

The following are are the changes.

In "MainWindow.xaml.cs" add these two methods in which the first one is for the highlighting and the second one is to find the same word to highlight that is being spoken:

private void HighlightWordInRichTextBox(RichTextBox richTextBox, String word, SolidColorBrush color)
{
   
//clear all formatings
    
TextRange textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox1.Document.ContentEnd);
    textRange.ApplyPropertyValue(
TextElement.BackgroundProperty, null);
 

    //Current word at the pointer
    
TextRange tr = FindWordFromPosition(textPointer, word);
 

    if (!object.Equals(tr, null))
    {
    
     //set the pointer to the end of "word"
         textPointer = tr.End;
 

         //apply highlight color
         tr.ApplyPropertyValue(
TextElement.BackgroundProperty, color);
        }
    }

private TextRange FindWordFromPosition(TextPointer position, string word)
{
   
while (position != null)
    {
       
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
        {
           
string textRun = position.GetTextInRun(LogicalDirection.Forward);

 

            // Find the starting index of any substring that matches "word".
           
int indexInRun = textRun.IndexOf(word);
           
if (indexInRun >= 0)
            {
               
TextPointer start = position.GetPositionAtOffset(indexInRun);
               
TextPointer end = start.GetPositionAtOffset(word.Length);
               
return new TextRange(start, end);
            }
        }
        position = position.GetNextContextPosition(
LogicalDirection.Forward);
    }

 

    // position will be null if "word" is not found.
   
return null;
}

Also add these few lines to the method:

void synthesizer_SpeakProgress(object sender, SpeakProgressEventArgs e)
{
   
//show the synthesizer's current progress
    labelProgress.Content = e.Text;
   
SolidColorBrush highlightColor = new SolidColorBrush(Colors.Yellow);
   
HighlightWordInRichTextBox(richTextBox1, e.Text, highlightColor);
}

After making all these changes "Run" your application; your window should be something like this:


 Text-to-Speech1.png

Text-to-Speech2.png