How To: Teach Your Apps To Speak With System.Speech.SpeechSynthesizer Part 2#

In part 1 of this series i showed you how to specify the voice, gender, rate and volume of the our SpeechSynthesizer object. This time i'm going to show you how to use predefined Voices in your machine and utilize it as hints to your SpeechSynthesizer object.

The first thing that I did to our sample project is change the UI since we would not need the Gender and Age combo box in our form. The result is a UI like this:

Next, we need to figure out a way to extract the names of the installed voices in our machine. To this we need to use the SpeechSynthesizer.GetInstalledVoices() method. This method, when invoked returns a readonly collection of TTS(text-to-speech) voices also known as InstalledVoice objects that are readily available in your machine. The InstalledVoice object contains a property called VoiceInfo which represents the voice information about that TTS voice. To begin our project we need to get all the VoiceInfo objects on each and every InstalledVoice. Below is a code snippet showing how we can accomplish this task:

//create a new speechsynthesizer object
static SpeechSynthesizer speechSynth = new SpeechSynthesizer();
/// <summary>
/// a method that returns all the currently installed voice
/// info objects in the machine
/// </summary>
/// <returns>a list of VoiceInfo objects</returns>
private static List<VoiceInfo> GetInstalledVoices()
{
    //get the current cultureinfo
    CultureInfo currentCulture = CultureInfo.CurrentCulture;

    //use linq to select each voiceinfo object from the intalledvoices collection
    var listOfVoiceInfo = from voice
                              in speechSynth.GetInstalledVoices(currentCulture)
                          select voice.VoiceInfo;

    //return the selected voiceinfo objects
    return listOfVoiceInfo.ToList<VoiceInfo>();
}

Next, we need to bind the resulting list to our voiceComboBox.

private void MainForm_Load(object sender, EventArgs e)
{
    BindData();
}

/// <summary>
/// Bind the voices to our combobox
/// </summary>
private void BindData()
{
    //get the installed voices
    List<VoiceInfo> listOfVoices = GetInstalledVoices();
    //bind the list to our combobox
    voicesComboBox.DataSource = listOfVoices;
    voicesComboBox.DisplayMember = "Name";
}

And finally we need to create the logic inside our button click event to initiate our SpeechSynthesizer

private void speakUpButton_Click(object sender, EventArgs e)
{
    //get the values specified in our form
    string messageToSay = wordsTextBox.Text;
    int selectedVolume = volumeTrackBar.Value;
    int selectedVoiceRate = voiceRateTrackBar.Value;

    //get the selected voice info
    VoiceInfo vi = voicesComboBox.SelectedItem as VoiceInfo;
                
    //specify the volume for our SpeechSynthesizer object
    speechSynth.Volume = selectedVolume;
    //specify the rate  for our SpeechSynthesizer object
    speechSynth.Rate = selectedVoiceRate;
    //specify the voice info specifying the voice to use
    speechSynth.SelectVoice(vi.Name);
    //say the message
    speechSynth.SpeakAsync(messageToSay);
}

And we are done ;) Running the application would show as all the installed TTS voice in our machine. One thing to note is that this list is machine dependent and different machines might contain different voices.

Clicking the "Speak!" button should echo our selected voice.

Next time I'll show you how to export the resulting speech to a wave file. HTH

Tuesday, September 23, 2008 8:54:03 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

Goosh: The Unofficial Google Command Line#

Ever wondered how google would look like if it was on terminal mode (a la *Nix shell)? Then checkout Goosh! Goosh is a project that Stefhan Grothkopp started. The application behaves similar to a unix-shell wherein you type commands and it returns results based on your request (which in this case is web search results). I personally love the idea and have been using the tool since i found it.

This reminds me of the days when terminals were hip and cool. I do wish that the background was black though and the fonts converted to green to give more terminal-like feel to it but either way its two thumbs up for me ;)

Friday, September 19, 2008 12:20:01 AM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

How To: Teach Your Apps To Speak With System.Speech.SpeechSynthesizer#

One of the cool things that came out with .NET 3.x is the addition of System.Speech library. This library is a collection of classes that enables you to do alot of speech related things like speech recognition and text-to-speech conversion. It's a handful to talk about so i suggest you read up MSDN to learn more about this library[1][2][3].

The app I'm going to show you today is a basic application that shows how to utilize the SpeechSynthesizer class that is located inside the System.Speech.Synthesis namespace.

To start this demo lets add a reference to the System.Speech namespace to our project. You can do this by doing a right-click on References > Add Reference and selecting System.Speech from the list.

Once added we can now beging utilizing this library by adding a using directive pointing to the specific System.Speech namepace that we want to utilize. For this demo we will use System.Speech.Synthesis

Next, we need to create a new SpeechSynthesizer object. SpeechSynthesizer is class that enables you to convert text-to-speech. The class also has several properties and methods that you can use customize the voice information on your speech synthesizer.

Next is the fun part which is making our application say some words. The cool thing about SpeechSynthersizer is that all you need to do to make your application speak is call the SpeechSynthesizer.Speak() method and your done ;)

Run our application and once started you should here the words "Hello, World" spoken by your machine. Pretty cool huh?!

What we did was a simple demonstration on how to make our apps speak with a few lines using SpeechSynthesizer. But what about customizing the voice? Fear not! I created a sample application that will show you how you can customize the synthesizer by specifying the rate, volume, gender and age of the emitted sound. Below is the screenshot showing the UI for the application

And here is the code snippet with comments detailing how to customize our SpeechSynthesizer object.

using System;
using System.Windows.Forms;
using System.Speech.Synthesis;

namespace KeithRull.TalkToMeGoose
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        //create a new speechsynthesizer object
        SpeechSynthesizer speechSynth = new SpeechSynthesizer();

        private void speakUpButton_Click(object sender, EventArgs e)
        {
            //get the values specified in our form
            string messageToSay = wordsTextBox.Text;
            int selectedVolume = volumeTrackBar.Value;
            int selectedVoiceRate = voiceRateTrackBar.Value;
            string selectedGender = genderComboBox.SelectedItem.ToString();
            string selectedAge = ageComboBox.SelectedValue.ToString();

            Type voiceGenderType = typeof(VoiceGender);
            Type voiceAgeType = typeof(VoiceAge);

            //convert the selectedGender value to a VoiceGender
            VoiceGender gender = (VoiceGender)Enum.Parse(voiceGenderType, selectedGender);
            //convert the selectedAge value to a VoiceAge
            VoiceAge age = (VoiceAge)Enum.Parse(voiceAgeType, selectedAge);

            //specify the volume for our SpeechSynthesizer object
            speechSynth.Volume = selectedVolume;
            //specify the rate  for our SpeechSynthesizer object
            speechSynth.Rate = selectedVoiceRate;
            //specify the voice info by using hints regarding the gender and age
            speechSynth.SelectVoiceByHints(gender, age);
            //say the message
            speechSynth.SpeakAsync(messageToSay);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            speechSynth.Speak("Hello, World!");
        }

        /// <summary>
        /// Bind the enums to our combobox
        /// </summary>
        private void BindData()
        {
            BindAgeToComboBox();
            BindGenderToComboBox();
        }

        /// <summary>
        /// bind the VoiceGender enum to our combobox
        /// </summary>
        private void BindGenderToComboBox()
        {
            //convert the enumeration to a string array
            Array voiceGenderArray = Enum.GetValues(typeof(VoiceGender));
            //bind the array to the datasource of our combobox
            genderComboBox.DataSource = voiceGenderArray;
        }

        /// <summary>
        /// Bind the VoiceAge enum to our combobox
        /// </summary>
        private void BindAgeToComboBox()
        {
            //convert the enumeration to a string array
            Array voiceAgeArray = Enum.GetValues(typeof(VoiceAge));
            //bind the array to the datasource of our combobox
            ageComboBox.DataSource = voiceAgeArray;
        }
    }
};

As always, you can download the source code for this project here: KeithRull.TalkToMeGoose1.zip (27.46 KB)

I hope I was able to show you how simple it is to add text to speech functionality to your .NET application. Next time I'll show you how to use predefined voices. Till next time ;)

Thursday, September 18, 2008 6:35:57 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

How To: Detemine The Groups For A Windows User#

Below is a code snippet that allows you to determine what groups a Windows user is part of.

[C#]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Text;

namespace KeithRull.ActiveDirectory.IdentifyingUserGroups
{
    class Program
    {
        static void Main(string[] args)
        {
            //get the WindowsIdentity of the current user
            WindowsIdentity currentWindowsIdentity = WindowsIdentity.GetCurrent();
            //retrieve the groups that the user belongs to
            IdentityReferenceCollection currentWindowsIdentityGroups = currentWindowsIdentity.Groups;
            //iterate thru each group
            foreach (IdentityReference identity in currentWindowsIdentityGroups)
            {
                //translate the identity into an NTAccount identity
                IdentityReference ntAccountIdentityReference = identity.Translate(typeof(NTAccount));
                //get the value
                string groupName = ntAccountIdentityReference.ToString();
                //print to console
                Console.WriteLine(groupName);
            }
            //pause
            Console.ReadLine();
        }
    }
}

[VB.NET]

Imports System 
Imports System.Collections.Generic 
Imports System.Linq 
Imports System.Security.Principal 
Imports System.Text 

Namespace KeithRull.ActiveDirectory.IdentifyingUserGroups 
    Class Program 
        Private Shared Sub Main(ByVal args As String()) 
            'get the WindowsIdentity of the current user 
            Dim currentWindowsIdentity As WindowsIdentity = WindowsIdentity.GetCurrent() 
            'retrieve the groups that the user belongs to 
            Dim currentWindowsIdentityGroups As IdentityReferenceCollection = currentWindowsIdentity.Groups 
            'iterate thru each group 
            For Each identity As IdentityReference In currentWindowsIdentityGroups 
                'translate the identity into an NTAccount identity 
                Dim ntAccountIdentityReference As IdentityReference = identity.Translate(GetType(NTAccount)) 
                'get the value 
                Dim groupName As String = ntAccountIdentityReference.ToString() 
                'print to console 
                Console.WriteLine(groupName) 
            Next 
            'pause 
            Console.ReadLine() 
        End Sub 
    End Class 
End Namespace 

HTH

 

Wednesday, September 17, 2008 9:21:38 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

This will be funny if it happened in real life#

Would you agree? ;)

Wednesday, September 17, 2008 7:59:43 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

Keith's Free eBook Recommendations Of The Month#

Speaking of free books... Below are the list of free ebooks that I recommend reading/downloading for this month. I personally love Karl Seguin's book and giving it 5 out 5 stars is actually an understatement if you ask me. :)

Karl Seguin's Foundation Of Programming: Building Better Software rocks so much I recommended it to everyone I know. This 79 page book is pack with a hearty bowl of software development knowledge that would teach you about the principles of development that you should have known way before you started coding that nightmarish system.

Red Gate's Dissecting SQL Server Execution Plan is a must read for anyone who deals with data on a daily basis. It talks about how to optimize your querries and understand whats causing your querries to sleep on you while being executed.

InfoQ's Domain Driven Design Quickly is a quickly-readable summary and introduction to the fundamentals of DDD that tries to summarizes Eric Evans' book as well as Jimmy Nilsson's Applying Domain Driven Design and various other sources. The book gives you hints and tips about DDD as well as ideas on how to start DDD in your own projects.

Minh T. Nguyen's Visual Studio.NET Tips & Tricks is a must read for all developers who use Visual Studio. Enuff said!

So what are you waiting for? Download and read 'em now!

Thursday, September 11, 2008 11:48:37 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

Free Professional Visual Studio 2008 book? Count me IN!!!#
Thursday, September 11, 2008 11:40:03 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

How To: Color Conversion in .NET#

Ever heard of ColorTranslator? It's a really cool class that you can use to convert colors in .NET. One of the things that it can do is that enables you to convert HTML colors to Windows colors and vice versa. One particular scenario wherein you might want to use this class is when you want to use HTML colors on your WinForm.

Below are examples on how to use this calls:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace ColorTranslatorTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //convert a system.drawing.color to html
            Color c1 = Color.AntiqueWhite;
            button1.BackColor = c1;
            button1.Text = ColorTranslator.ToHtml(c1);

            //convert an html color to a gdi+ color
            string htmlColor = "#FFAD55";
            Color c2 = ColorTranslator.FromHtml(htmlColor);
            button2.BackColor = c2;
            button2.Text = ColorTranslator.ToHtml(c2);

            //convert a win32 color to gdi+ color
            int colorHexadecimalValue = 0xA267;
            Color c3 = ColorTranslator.FromWin32(colorHexadecimalValue);
            button3.BackColor = c3;
            button3.Text = ColorTranslator.ToWin32(c3).ToString("X");
        }
    }
}

HTH

Friday, September 05, 2008 5:59:10 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

Refreshing views with sp_refreshview#

One of the common problems that you would encounter when you are building applications that utilize views is that sometimes there are cases wherein a view gets out of date. This happens when you add a new column to a table a view is refrencing.

To fix this some people would delete the view and recreate it but there is better solution called sp_refreshview. sp_refreshview updates the metadata for the specified non-schema-bound view. Persistent metadata for a view can become outdated because of changes to the underlying objects upon which the view depends[description from msdn].

Here's a remark from MSDN regarding sp_refreshview:

"If a view is not created with schemabinding, sp_refreshview should be run when changes are made to the objects underlying the view that affect the definition of the view. Otherwise, the view might produce unexpected results when it is queried."

The syntax is pretty straight-forward

   EXECUTE sp_refreshview '<view name>'

Once executed the views definition would be updated.

What if I want to execute sp_refreshview on all the views in my database? The answer is to create a cursor that would execute sp_refreshview on each of your view. Below is a script that does exacrly what you need:

--Refresh the underlying metadata of all views
DECLARE @viewName AS VARCHAR(255)

DECLARE listOfViews CURSOR FOR
SELECT [name] 
FROM sysobjects 
WHERE xtype = 'V'


OPEN listOfViews

    FETCH NEXT FROM listOfViews into @viewName

    WHILE (@@FETCH_STATUS <> -1)
    BEGIN

        FETCH NEXT FROM listOfViews INTO @viewName
        EXEC sp_refreshview @viewName

    END

CLOSE listOfViews

DEALLOCATE listOfViews

HTH

SQL
Tuesday, August 19, 2008 7:49:57 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

sp_recompile is your friend#

I've been doing a  lot of code deployments lately and I've come across several occasions wherein my stored procedures wouldn't run as fast as expected compared to it's previously known execution time. The problem lies on the statistics not getting updated after change has been made against an index or other object that may affect efficiency. Since stored procedures are compiled, recompiling them would update these statistics.

Here's a remark about sp_recompile taken from the MSDN website

"The queries used by stored procedures and triggers are optimized only when they are compiled. As indexes or other changes that affect statistics are made to the database, compiled stored procedures and triggers may lose efficiency. By recompiling stored procedures and triggers that act on a table, you can reoptimize the queries."

The syntax is pretty straight-forward:

EXEC sp_recompile '<name of your sp>'

Once executed the stored procedure would then be marked for recompilation and would then be recompiled on the next execution. Niffty huh?!

But what if I want to recompile all my stored procedures? Well, fear not! You can use a cursor that would iterate on all the stored procedure in your current database and execute an sp_recompile against all of them. Below is the script to accomplish this task:

--Recompile all stored procedures on the current database
DECLARE @StoredProcedureName AS VARCHAR(255)

DECLARE listOfStoredProcedure CURSOR FOR
SELECT [Name] FROM sysobjects 
WHERE XTtype = 'P'


OPEN listOfStoredProcedure

    FETCH NEXT FROM listOfStoredProcedure into @StoredProcedureName

    WHILE (@@FETCH_STATUS <> -1)
    BEGIN

        FETCH NEXT FROM listOfStoredProcedure INTO @StoredProcedureName
        EXEC sp_recompile @StoredProcedureName

    END

CLOSE listOfStoredProcedure

DEALLOCATE listOfStoredProcedure

GO

HTH

*Note: sp_recompile can also recompile triggers

SQL
Tuesday, August 19, 2008 7:31:14 PM (GMT Daylight Time, UTC+01:00) #    Comments [0]  | 

 

All content © 2010, Keith Rull
On this page
This site
Calendar
<September 2008>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
Archives
Sitemap
Blogroll OPML
Disclaimer

Powered by: newtelligence dasBlog 2.3.9074.18820

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts


Pick a theme: