| Join | Help

A Fun Windows Form Application

Ever play around with the Text-To-Speech in Windows XP? I thought that was fun when XP first came out and I always made it say crazy stuff, especially during computer lab. Later as a developer I wanted to implement this into a Windows Application I was making, just for fun.

The Speech API (SAPI) is a COM library, and it is no secret to .NET Developers that .NET has excellent support for COM libraries. The sapi.dll can usually be found in C:\Program Files\Common Files\Microsoft Shared\Speech. Using the .NET SDK, we can easily make a managed assembly for this using the Type Library Import, tlbimp.exe. You can run it from the SDK Command prompt in the start menu. Using the command prompt we can generate the Managed Version of it, what I called sapi.net.dll using this in the .NET SDK Command Prompt:

C:\Program Files\Microsoft.NET\SDK\v2.0 64bit>tlbimp "C:\Program Files\Common Files\Microsoft Shared\Speech\sapi.dll" /out:C:\sapi.net.dll

The Type Library Mashaler won't be able to completely marshal it for you, but it will be able to do enough of it for us to get what we want. (Note that in my example I used the 64-bit platform, so your SDK path won't be the same). This will generate the Assembly we need for making a taking application.

So now we can use this assembly in a Windows Form Project, and all we have to do is add a reference for it.

The primary interface and class we will be using is SpVoice and SpVoiceClass, which were made by our type library importer. SpVoiceClass is what we will use to make our application talk. The method "Speak" accepts two arguements, the text to be spoken (as a string) and flags (as an int enumeration). Type Library Importer automatically generated a flag enumeration called SpeechVoiceSpeakFlags. The two I use in this application is SVSFIsNotXML and SVSFlagsAsync. SVSFlagsAsync is important so your thread won't lockup when you start speaking. Optionally, you can use your own worker thread, which is recommended since we don't want to be talking on the UI thread:

private SpVoiceClass voice = new SpVoiceClass ();

SpVoiceClass voice = new SpVoiceClass ();

ThreadPool . QueueUserWorkItem(( delegate ( object arg)
{
voice . Speak( "Hello!" , SpeechVoiceSpeakFlags . SVSFIsNotXML | SpeechVoiceSpeakFlags . SVSFlagsAsync);
}),
null );

this.voice is an instance of the SpVoiceClass class.

Assuming one has Office installed, you have extra voices. I got bored of Microsoft Sam so I wanted to use others voices, for which I created a helper method like this:

static List < DictionaryEntry > AvailableVoices
{
get
{
SpVoiceClass voice = new SpVoiceClass ();
List < DictionaryEntry > voices = new List < DictionaryEntry > ();
for ( int i = 0 ; i < voice . GetVoices( null , null ) . Count; i ++ )
voices
. Add( new System . Collections . DictionaryEntry (voice . GetVoices( null , null ) . Item(i) . GetDescription(System . Globalization . CultureInfo . CurrentCulture . LCID), voice . GetVoices( null , null ) . Item(i)));
return voices;
}
}

The reasoning for using a List filled with DictionaryEntry's is for databinding purposes, since the binding must implement the interface IList. This returns a List of DictionaryEntries, the dictionary key being the voices name, the value being the actual voice itself, which is the interface ISpObjectToken. So now we have a list of the voices installed on the machine.

The SpVoiceClass has a method called SetVoice which accepts an ISpObjectToken for setting the voice.

The SpVoice class can also allow you to save a WAV recording of the voice, just by changing around the output stream. I used a BackgroundWorker class to help me with this so I can do it on another thread.

The stream we will be using for this is SpFileStreamClass, which must exist on the same thread as the SpVoice class, so we need to pass it as an arguement in the RunWorkAsync method.

You can download the full sourcecode and run it for yourself here: Speech

Share this post: | bookmark it! | digg it! | reddit! | kick it! | live it!
Published Monday, October 16, 2006 8:40 PM by Kevin Jones
Filed under: , ,

Comments

# How to use Microsoft's Speech API (SAPI) in a managed application (C# - VB .Net)

Thursday, November 02, 2006 9:08 AM by Blake

Sometime soon, I plan on releasing a cool application that uses text-to-speech. Some of you might have

Leave a Comment

(required)  
(required)  
(optional)
(required)