Volunteer .NET Evangelist

A well oiled machine can’t run efficiently, if you grease it with water.
  首页  :: 联系 :: 订阅 订阅  :: 管理

Speech API In WPF

Posted on 2006-02-19 00:18  Sheva  阅读(2555)  评论(2编辑  收藏  举报
    I've been playing with several CTP releases of Windows Presentation Foundation a.k.a Avalon, I have to say I am just so excited by the flexibility and powerfulness of this platform. In Avalon, It's pretty easy to write great looking application without too much sophisticated skills.
    What's more, Avalon also ships with a set of APIs dealing with speech and speech synthesis, which is pretty amazing indeed. I just write a simple application demonstrating the speech capability in Avalon, this application takes advantage of the System.Speech.Synthesis.SpeechSynthesizer class to narrate the text displayed in the RichTextBox control, and simultaneously display each word being spoken out in the RichTextBox, here is the code:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Windows.Media;
using System.Speech.Synthesis;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media.Imaging;

namespace SpeechSynthesis
{
    
public class SpeechWindow : Window
    {
        
private SpeechSynthesizer speechSynthesizer;

        
private String textToSpeak;
        
private RichTextBox speechBox;
        
private Button startButton;
        [STAThread]
        
public static void Main()
        {
            Application app 
= new Application();
            app.Run(
new SpeechWindow());
        }
        
public SpeechWindow()
        {
            
// Set a transparent image as the window background, workaround for the black window problem.
            BitmapImage bitmap = new BitmapImage(new Uri("pack://application:,,/workaround_image.jpg"));
            ImageBrush workaroundImage 
= new ImageBrush(bitmap);
            
this.Background = workaroundImage;

            
this.Title = "Speech API In WPF";

            StackPanel panel 
= new StackPanel();

            
// Start Button
            startButton = new Button();
            startButton.Width 
= 200d;
            startButton.Height 
= 100d;
            BitmapImage backBitmap 
= new BitmapImage(new Uri("pack://application:,,/VistaStartButton.jpg"));
            startButton.Background 
= new ImageBrush(backBitmap);
            startButton.HorizontalAlignment 
= HorizontalAlignment.Stretch;
            startButton.Click 
+= new RoutedEventHandler(StartSpeechHandler);
            startButton.Margin 
= new Thickness(0d);
            startButton.Clip 
= new RectangleGeometry(new Rect(21d, 18d, 160d, 66d), 33d, 33d);

            
// ViewBox used to scale the button to arbitrary size.
            Viewbox vBox = new Viewbox();
            vBox.Width 
= 100d;
            vBox.Height 
= 50d;
            vBox.HorizontalAlignment 
= HorizontalAlignment.Center;
            vBox.Stretch 
= Stretch.UniformToFill;
            vBox.Child 
= startButton;
            panel.Children.Add(vBox);

            
// RichTextBox
            speechBox = new RichTextBox();
            speechBox.HorizontalScrollBarVisibility 
= ScrollBarVisibility.Auto;
            speechBox.VerticalScrollBarVisibility 
= ScrollBarVisibility.Auto;
            speechBox.Width 
= 500d;
            speechBox.Height 
= 300d;
            speechBox.BorderBrush 
= Brushes.Black;
            speechBox.BorderThickness 
= new Thickness(2d);
            speechBox.Margin 
= new Thickness(4244);

            FlowDocument doc 
= new FlowDocument();
            speechBox.Document 
= doc;

            
// Add single paragraph to the document.
            Paragraph p1 = new Paragraph();
            p1.Text 
= "Avalon and Indigo is the future";
            p1.FontFamily 
= new FontFamily("Segoe UI");
            p1.FontSize 
= 30d;
            p1.FontWeight 
= FontWeights.Bold;
            p1.Foreground 
= Brushes.Green;
            p1.Padding 
= new Thickness(0d);
            textToSpeak 
= p1.Text;
            speechBox.Document.Blocks.Add(p1);

            
// Add an empty paragraph for future type-in text effect.
            Paragraph p2 = new Paragraph();
            p2.Text 
= "";
            p2.FontFamily 
= new FontFamily("Segoe UI");
            p2.FontSize 
= 30d;
            p2.FontWeight 
= FontWeights.Bold;
            p2.Foreground 
= Brushes.Green;
            p2.Padding 
= new Thickness(0d);
            speechBox.Document.Blocks.Add(p2);

            panel.Children.Add(speechBox);

            
this.Content = panel;
            
this.ResizeMode = ResizeMode.NoResize;
            
this.SizeToContent = SizeToContent.WidthAndHeight;

            speechSynthesizer 
= new SpeechSynthesizer();  
        }

        
private void StartSpeechHandler(Object sender, RoutedEventArgs e)
        {
            Prompt prompt 
= speechSynthesizer.SpeakTextAsync(textToSpeak);
            speechSynthesizer.SpeakProgress 
+= speechSynthesizer_SpeakProgress;
        }

        
void speechSynthesizer_SpeakProgress(Object sender, SpeakProgressEventArgs e)
        {
           
// Currently we are in another thread rather than the UI thread, so we have to use
            // the Dispatcher object to get UI service for the current thread.
            speechBox.Dispatcher.Invoke(DispatcherPriority.Normal,
                                                    new
 TypeInSpeakingTextCallBack(TypeInSpeakingText), e.Text);
        }

        
private delegate void TypeInSpeakingTextCallBack(String currentSpeakingText);

        
private void TypeInSpeakingText(String currentSpeakingText)
        {
            Run run 
= new Run();
            run.Text 
= currentSpeakingText + " ";
            run.FontFamily 
= new FontFamily("Segoe UI");
            run.FontSize 
= 30d;
            run.FontWeight 
= FontWeights.Bold;
            run.Foreground 
= Brushes.Green;
            Paragraph p 
= speechBox.Document.Blocks.LastBlock as Paragraph;
            p.Inlines.Add(run);
        }
    }
}

And here is the screenshot of application in action:


 
  You probably notice that I just write the whole things in procedural code(C#) rather than in XAML code, because I just find that it's the best way to write all those things in C# code when you learn Avalon, I have to admit that XAML is pretty cool, but sometimes, XAML just hides a lot of important concepts from you,  if you want to learn the nuts and bolds of Avalon, then I recommend you to go the code approach:-)
  Last but not least, one good news is that the speech APIs which are shipped with Avalon can also be used in Winforms applications, for demonstration purpose, I also rewrite this application in Winforms, the source is avalaible here, for avalon version of it,  please check here

   As the narrator pronounces:" Avalon and Indigo is the future!".