Makale Özeti

Birçoğumuz TextToSpeech uygulamalarını kullanmış ya da duymuşuzdur. .Net Framework 3.0'ın çıkması ile birlikte bu işlemi yapabilmemiz için gerekli class'lar bize System.Speech.Synthesis namespace'i altında gelmektedir. İlk kullanım alanları olarak akla bir text dosyasının ses olarak dinlenmesi veya ses dosyasına çevrilmesi, bir add-in yazılarak outlook'ta gelen mailin okutulması, hata mesajı veya uyarı mesajı vereceğimiz noktalarda bu mesajları sesli olarak vermek gelmektedir.

Makale

Merhabalar,

Birçoğumuz TextToSpeech uygulamalarını kullanmış ya da duymuşuzdur. .Net Framework 3.0'ın çıkması ile birlikte bu işlemi yapabilmemiz için gerekli class'lar bize System.Speech.Synthesis namespace'i altında gelmektedir. İlk kullanım alanları olarak akla bir text dosyasının ses olarak dinlenmesi veya ses dosyasına çevrilmesi, bir add-in yazılarak outlook'ta gelen mailin okutulması, hata mesajı veya uyarı mesajı vereceğimiz noktalarda bu mesajları sesli olarak vermek gelmektedir.

Bu makalemde ben System.Speech.Synthesis namespace'i ile gelen SpeechSynthesizer class'ından bahsedeceğim. Bu class sayesinde biraz önce bahsetmiş olduğum örnekler gibi işlemleri ve daha fazlasını uygulamalarınızda gerçekleştirebilirsiniz.İlk olarak SpeechSynthesizer nesnesinin belli başlı property, metod ve event'lerini inceleyelim.

Property

Rate

Yazının karakter tarafından ne kadar hızlı okunacağının belirlendiği property'dir. -10 ve 10 arası değer alır.

State

Yazının okunma durumunun hangi aşamada olduğunun tutulduğu property'dir. SynthesizerState enum'unun Paused, Ready ve Speaking değerlerinden birini alır.

Voice

Yazıyı okuyan sesin Name, Age, Gender, Culture gibi özelliklerinin tutulduğu VoiceInfo tipindeki property'dir.

Volume

Ses düzeyinin belirlendiği property'dir.

Method

AddLexicon

Sözlük ekler.

GetCurrentlySpokenPrompt

Geçerli olan okunan yazının alınmasını sağlar.

GetInstalledVoices

Bilgisayarda kayıtlı olan SpeechSynthesizer seslerinin alınmasını sağlar.

Pause

Okuma işleminin duraklatılmasını sağlar.

RemoveLexicon

Sözlüğün kaldırılması işlemini yapar.

Resume

Duraklamış olan okuma işleminin kaldığı yerden devam etmesini sağlar.

SelectVoice

Sistemde kayıtlı olan seslerden isim parametre gönderilerek yazının hangi ses tarafından okunacağını belirler.

SelectVoiceByHints

Sistemde kayıtlı olan seslerden Cinsiyet, Yaş gibi parametreler gönderilerek yazının okunacağı sesi belirler.

SetOutputToAudioStream

Sesi Audio Stream olarak kaydeder.

SetOutputToDefaultAudioDevice

Sesi varsayılan audio cihazına yönlendirir.

SetOutputToWaveFile

Sesi bir .wav dosyası olarak kaydeder.

SetOutputToWaveStream

Sesi bir wave stream'e atar.

Speak

Okuma işlemini yapar. Ancak okuma işlemi süresince uygulamanız kilitlenir ve uygulama üzerinde başka bir işlem yapamazsınız. Uygulama işlemi tek thread'de çalışır.

SpeakAsync

Okuma işlemini asenkron şekilde yapar. Böylece okuma devam ederken uygulamanız kilitlenmez ve uygulama üzerinde başka işlemler de gerçekleştirebilirsiniz. Asenkron olarak farklı thread'de çalışır.

SpeakAsyncCancel

Parametre aldığı bir Prompt nesnesinin okunma işlemini iptal eder.

SpeakAsyncCancelAll

Bütün okuma işlemlerini iptal eder.

SpeakSsml

SSML text'leri okumaya yarar.

SpeakSsmlAsync

SSML text'leri asenkron biçimde okur.

Event

SpeakCompleted

Okuma işlemi bittiği zaman tetiklenir.

SpeakProgress

Okuma işlemi sırasında tetiklenir.

SpeakStarted

Okuma işlemi başladığı zaman tetiklenir.

StateChanged

Okuma işleminin durumu değiştiği zaman tetiklenir.

VoiceChange

Yazıyı okuyan ses değiştiğinde tetiklenir.

Şimdi örnek bir uygulama üzerinden giderek SpeechSynthesizer class'ı ile text okunması, .wav dosyasına kaydedilmesi gibi işlemleri nasıl yapabileceğimizi inceleyelim. Yeni bir solution oluşturup, yeni bir Windows uygulaması ekleyelim. Ardından da kullanacağımız formu aşağıdaki gibi dizayn edelim:



Formda, yazıyı okuyacak olan sesi cinsiyet ve yaş kriterlerine göre belirleyebileceğimiz bir alan bulunuyor. Bunun yanısıra kullanıcı isterse Sese Göre kısmından Microsoft Sam, Michael gibi karakterleri de seçerek yazıyı okutabiliyor olacak. Okunacak olan yazının yazılacağı textbox'ın altındaki konuş butonu textbox'daki yazının cinsiyet - yaşa göre veya sese göre seçeneklerinden birine göre seçilmiş olan karakter tarafından okunmasını sağlayacak. Duraklat butonu ile okuma işlemini duraklatacağız, Devam Et butonu ile duraklamış olan okumayı devam ettireceğiz, İptal Et butonu ile okuma işlemini iptal edeceğiz. .wav yap butonu ile de yazıyı .wav dosyası olarak kaydedeceğiz. Durum label'ında SpeechSynthesizer nesnesinin State property'sinde tutulan değerleri yazı okundukça değiştireceğiz. SSML butonu ile de bir SSML metnini okuyacağız. Kodu yazmaya başlayalım:

SpeechSynthesizer s;

public
frmSynthesizer()
{
    InitializeComponent();
    s = new SpeechSynthesizer();
    s.SpeakProgress += new EventHandler<SpeakProgressEventArgs>(s_SpeakProgress);
    s.StateChanged += new EventHandler<StateChangedEventArgs>(s_StateChanged);
    s.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(s_SpeakCompleted);
}
private
void frmSynthesizer_Load(object sender, EventArgs e)
{
    FillGenderCombo();
    FillVoiceAgeCombo();
    FillVoicesCombo();
}

Class level bir SpeechSynthesizer nesnesi tanımladıktan sonra formun constructor'ında instance'ını alıyoruz ve SpeakProgress, StateChanged, SpeakCompleted event'lerini handle etmek için tanımlıyoruz. Ardından da formun load'ında form üstündeki Cinsiyet, Yaş ve Ses combobox'larını doldurmak üzere yazdığımız metodları çağırıyoruz. Bu metodların da kodları aşağıdaki gibi:

private void FillGenderCombo()
{
    cmbGender.DataSource = Enum.GetValues(typeof(VoiceGender));
}
private
void FillVoiceAgeCombo()
{
    cmbAge.DataSource = Enum.GetValues(typeof(VoiceAge));
}
private
void FillVoicesCombo()
{
    foreach
(InstalledVoice iv in s.GetInstalledVoices())
    {
        cmbVoice.Items.Add(iv.VoiceInfo.Name);
    }
}

FillGenderCombo metodunda VoiceGender enum'unu, FillVoiceAgeCombo metodunda ise VoiceAge enum'unu ilgili combobox'lara datasource olarak atıyoruz. FillVoicesCombo metodunda ise SpeechSynthesizer nesnesinin GetInstalledVoices metodunu kullanarak aldığımız InstalledVoice nesnelerinin isimlerini Ses combobox'ına ekliyoruz. Bu aşamada yapacağımız bir şey daha bulunuyor. Ses combobox'ının selected index'i her değiştiğinde seçili olan sesin bazı bilgilerini hemen altta bulunan Ses Özellikleri label'ına yazdıralım:

private void cmbVoice_SelectedIndexChanged(object sender, EventArgs e)
{
    IEnumerable
<InstalledVoice> v = from a in s.GetInstalledVoices() where a.VoiceInfo.Name == cmbVoice.SelectedItem.ToString() select a;
    lblVoiceProperties.Text = "Cinsiyet: " + v.First<InstalledVoice>().VoiceInfo.Gender.ToString() + "\r\nYaş: " + v.First<InstalledVoice>().VoiceInfo.Age.ToString() +
    "\r\nAçıklama: "
+ v.First<InstalledVoice>().VoiceInfo.Description;  
}

Kodda da görüldüğü gibi SpeechSynthesizer  nesnesinin GetInstalledVoices fonksiyonu ile InstalledVoice collection'ı için ufak bir linq sorgusu yazdık. Ardından da select yaptığımız InstalledVoice nesnesinin Gender, Age ve Description property'lerini formdaki label'a yazdırdık. Buraya kadar uygulamayı çalıştırıp, geldiğimiz noktayı inceleyelim:



Uygulamayı çalıştırdığımızda Cinsiyet, Yaş ve Ses combobox'larının dolduğunu göreceğiz. Ses combobox'ındaki seçili öğeyi değiştirdiğimizde ise Ses Özellikleri label'ında ilgili sesin özellikleri yazıyor olacaktır. Şimdi Konuş butonunun kodunu yazalım:

private void btnSpeak_Click(object sender, EventArgs e)
{
    if
(rbtnGenderAge.Checked)
    {
        s.SelectVoiceByHints((System.Speech.Synthesis.VoiceGender)cmbGender.SelectedItem, (System.Speech.Synthesis.VoiceAge)cmbAge.SelectedItem);
    }
    else
if (rbtnVoice.Checked)
    {
        s.SelectVoice(cmbVoice.SelectedItem.ToString());
    }
    s.SpeakAsync(txtSubject.Text);
}

Cinsiyet - Yaşa Göre radiobutton'ı seçili ise SelectVoiceByHints metodunu, Sese Göre radiobutton'ı seçili ise SelectVoice metodunu çağırarak yazıyı okuyacak sesin özelliklerini belirliyoruz. Ardından da SpeakAsync metodu ile txtSubject textbox'ındaki yazıyı okutuyoruz. Şimdi diğer butonların kodunu yazalım:

private void btnPause_Click(object sender, EventArgs e)
{
    s.Pause();
}
private
void btnResume_Click(object sender, EventArgs e)
{
    s.Resume();
}
private
void btnCancel_Click(object sender, EventArgs e)
{
    Prompt
p = s.GetCurrentlySpokenPrompt();
   
s.SpeakAsyncCancel(p);
}
private
void btnWav_Click(object sender, EventArgs e)
{
    s.SetOutputToWaveFile(@"C:\io.wav");
    s.SpeakAsync(txtSubject.Text); 
}
private
void btnSSML_Click(object sender, EventArgs e)
{
    s.SpeakSsmlAsync(txtSubject.Text);
}

Duraklat ve Devam Et buton'larının click event'lerinde SpeechSynthesizer nesnesinin Pause ve Resume metodlarını çağırdık. İptal butonunda ise GetCurrentlySpokenPrompt metodu ile mevcut olan okuma işlemini aldık ve SpeakAsyncCancel metoduna parametre göndererek işlemi iptal ettik. .wav dosyası kaydetmek için SetOutputToWaveFile metodunu çağırdık. SSML hakkında daha detaylı bilgiyi bir sonraki makalemde veriyor olacağım. Ancak şimdi kısaca değinmek gerekirse SSML yani Speech Synthesis Markup Language, metin okuma işlemlerini XML tabanlı metinler vasıtasıyla yapmamızı sağlayan standarda verilen isimdir. SSML, metin okuma işlemlerinde kullanıcıya farklı platformlarda telaffuz, ses seviyesi, hız, cinsiyet gibi parametreleri kontrol etme imkanını sağlar. Aşağıdaki örnek SSML metnini uygulamamızdaki textbox'a yapıştırıp SSML butonuna tıklayarak metni okutabilirsiniz:

<?xml version="1.0"?>

<!DOCTYPE speak PUBLIC "-//W3C//DTD SYNTHESIS 1.0//EN"
            "http://www.w3.org/TR/speech-synthesis/synthesis.dtd">
<speak version="1.0"
        xmlns="
http://www.w3.org/2001/10/synthesis"
        xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.w3.org/2001/10/synthesis
       
http://www.w3.org/TR/speech-synthesis/synthesis.xsd"
       
xml:lang="en-US">
<p>
    <voice gender="male">
    <s>You can find information on the Web in a variety of ways.</s>
    <s>Click the Search button on the toolbar to gain access to a number of search providers. Type a word or phrase in the Search box.</s>
    </voice>
</p>
<p>
    <voice gender="female">
    Type go, find, or ? followed by a word or phrase in the Address bar. Internet Explorer starts a search using its predetermined search provider.
    </voice>
</p>
<p>
    <voice gender="male">
    After you go to a Web page, you can search for specific text on that page by clicking the Edit menu, and then clicking Find.
    </voice>
</p>
</speak>

Son olarak SpeechSynthesizer nesnesinin bazı event'lerine örnekler verelim:

void s_SpeakProgress(object sender, SpeakProgressEventArgs e)
{
    lblProgress.Text = e.Text;
}
void s_SpeakCompleted(object sender, SpeakCompletedEventArgs e)
{
    lblProgress.Text = "";
}
void
s_StateChanged(object sender, StateChangedEventArgs e)
{
    lblState.Text = "Eski durum: " + e.PreviousState.ToString() + " Yeni durum: " + e.State;
}

SpeakProgress event'inde yani metin okunurken lblProgress label'ının Text property'sine metnin okunan kısmını yazıyoruz. SpeakCompleted event'inde ise lblProgress label'ının text'ini temizliyoruz. StateChanged event'inde ise SpeechSynthesizer nesnesinin durumu değiştikçe lblState label'ına eski durumu ve yeni durumu yazdırıyoruz.

Işıl Orhanel
http://www.isilorhanel.net

Örnek uygulamayı buradan indirebilirsiniz.