Java

Rozpoznawanie oraz synteza mowy z wykorzystaniem JSAPI

  • 2012-08-04 17:22
  • 2 komentarze
  • 4803 odsłony
  • Oceń ten tekst jako pierwszy


Rozpoznawanie oraz synteza mowy z wykorzystaniem
Java Speech API.



1. Instalacja

1.1 Sprzęt

Pentium 200 MHz, 64 MB RAM,
zalecane powyżej Pentium 400 MHz, 256 MB RAM.
 
1.2 System operacyjny

Microsoft Windows 98, Me , NT4, 2000 lub XP
 
1.3 Niezbędne składniki

Aby możliwe było kompilowanie oraz uruchamianie programu niezbędne będzie zainstalowanie w systemie następujących składników:
  • J2SDK 1.4.2.02 windows-i586-p
  • Microsoft Speech SDK 5.1
  • Java Media Framework 2.1.1e
  • TalkingJava SDK 1.6.2
1.4 Przebieg instalacji

Instalację należy rozpocząć od zainstalowania w systemie J2SDK 1.4.2.02 windows-i586-p, po której możemy zainstalować środowiska programistyczne (np. JCreator Pro, JBuilder, RealJava czy FreeJava ) w celu rekompilacji programu.

Następnie instalujemy niezbędne silniki (speech recognition and synthesis engine) rozpoznawania oraz syntezy mowy - Microsoft Speech SDK 5.1.
Po tych czynnościach instalujemy pakiet odpowiedzialny za przechwytywanie i odtwarzanie mediów (audio - video) Java Media Framework 2.1.1e.

Po instalacji wyżej wymienionych pakietów instalujemy składnik TalkingJava SDK 1.6.2.
W "Zmiennych środowiskowych? systemu Windows (lub w pliku "autoexec.bat? dla Windows98) ustawiamy zmienne CLASSPATH (wartosc rejestru "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java VM\Classpath") - podając scieżkę do pliku "cgjsapi.jar? oraz PATH ? podając scieżkę do pliku "cgjsapi162.dll? znajdujących sie w katalogu, w którym zainstalowaliśmy składnik TalkingJava SDK1.6.2 lub skopiowac plik "cgjsapi162.dll" do folderu systemowego (np. "c:\windows") .

Nastepnie kopiujemy pliki "cgjsapi.jar" oraz "cgjsapi162.dll" do katalogów lib\ext oraz bin środowiska JRE znajdującego się w zainstalowanym składniku J2SDK 1.4.2.02 windows-i586-p.

W celu rekompilacji gdy korzystamy ze środowiska programistycznego (jak np. JCreator Pro) należy dodać pakiet packet.jar znajdujący się w katalogu instalacyjnym składnika TalkingJava SDK1.6.2 do profili SDK.

Postępujemy następująco: Configure -> Options -> JDK Profiles, następnie klikając dwukrotnie na dołączonym do środowiska JDK( np. j2sdk 1.4.2_02) wybieramy Add -> Add Archive i odnajdujemy na dysku pakiet packet.jar. Podobnie postępujemy z pakietem cgjsapi.jar.



2. Uruchamianie

Aby móc korzystać w pełni sprawnie z programu potrzebny będzie mikrofon. Najlepiej wykorzystać słuchawki z mikrofonem typu headset, co zapewnia optymalne ustawienie odległości mikrofonu od ust i pozwala na uzyskanie lepszych wyników rozpoznawania mowy przez system, ponieważ siła głosu nie zmienia się tak drastycznie (o ile użytkownik jej nie zmieni) jak przy użyciu standardowego mikrofonu trzymanego w ręce gdzie odległość od ust może się niezauważalnie w trakcie wypowiadania komend zmieniać i pogarszać wyniki działania programu.



Po uruchomieniu programu ujrzymy okno konfiguracji JSAPI Speech Engines, w którym należy wybrać odpowiednie profile rozpoznawania oraz syntezy mowy.



Po przejściu na konkretny profil (syntezatora lub rozpoznawcę) uaktywni się przycisk jego właściwości (Recognizer Properties lub Synthesizer Properties ) co umożliwi nam w przypadku syntezatora ustawienie barwy dźwięku oraz szybkości czytania,



natomiast dla modułu rozpoznawania mowy możliwe jest ustawienie szybkości rozpoznawania., pewności (trafności) oraz czasu trwania wypowiedzi.



Jako zaawansowane opcje modułu rozpoznającego mowę należy wyróżnić:

  • trening silnika dla użytkownika (User Training), który składa się z kilkunastu zdań, po przeczytaniu których, system uczy się lepiej rozpoznawać głos danego użytkownika .



  • ustawienia mikrofonu, które umożliwiają optymalne ustawienia poziomu sygnału wejściowego.



3. Opis programu (prosty edytor graficzny sterowany glosem).

3.1 Sprzęt
  • Program testowany, napisany, kompilowany oraz uruchamiany na sprzęcie:
  • procesor: Celeron 562 MHz,
  • pamięć: 320 MB RAM,
  • karta muzyczna: Sound Blaster Live 1024,

3.2 Narzędzia
  • system operacyjny: Windowws XP Pro,
  • jdk: J2SDK 1.4.2.02 windows-i586-p,
  • środowisko: JCreator Pro version 2.5,

3.3 Opis kodu

Aby możliwe było skorzystanie z mechanizmów JSAPI Engine, niezbędne jest importowanie następujących pakietów

import javax.speech.*;
import javax.speech.recognition.*;
import javax.speech.synthesis.*;


import com.cloudgarden.speech.userinterface.*;
import com.cloudgarden.speech.CGEngineProperties;
import com.cloudgarden.speech.CGEngineCentral;


Pozostałe pakiety są standardowo instalowane z JDK

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*; 



Program składa się z dwóch klas:

public class RozpoznawanieOrazSynteza extends Thread {}
 
Jest to klasa główna ( posiadająca nazwę pliku źródłowego *.java ), w której to umieszczona jest metoda main(), oraz dwa główne obiekty silników rozpoznawania oraz syntezy mowy należące do klas uwidocznionych poniżej, inicjowane wartością null..:

public static Recognizer Rozpoznawca = null;
public static Synthesizer Syntezer = null;


Pozostałe obiekty i pola klasy

Okno klasy Frame służące do wyświetlania informacji (autor, przeznaczenie projektu) na początku programu, oraz napisu "Program zakończony" po wychwyceniu z wypowiedzianych komend słowa "exit".

public static Frame OknoInformacji = null;

 
Etykieta label1 umieszczona na OknieInformacji, na ktorej to zostają wyświetlane wszystkie łańcuchy tekstowe

public static Label label1 = null; 


Trzy zmienne boolowskie służące do sterowania mechanizmami otwierania, rysowania figur oraz zmiany rozmiaru płótna

public static boolean IsOpen = false;
public static boolean IsExist = false;
public static boolean IsResizing = false;


Trzy obiekty klasy Font wykorzystane zostały w celu ustawienia w obiekcie label1 różnych rodzajów czcionek podczas wyświetlania informacji.

public static Font czcionka1 = new Font( "Times New Roman", Font.ROMAN_BASELINE, 24 );
public static Font czcionka2 = new Font( "Verdana", Font.ROMAN_BASELINE, 30 );
public static Font czcionka3 = new Font( "Dialog", Font.ROMAN_BASELINE, 32 ); 


Metody klasy

Dwie poniżej są to metody odpowiedzialne za wyświetlanie informacji podczas startu programu oraz w trakcie jego zakończenia.

public static void Informacje(int czas){}
public static void Wyjscie(int czas){}


Metoda Wait() korzystająca z funkcji sleep(), dziedziczonej z klasy Thread, w celu opóźniania niektórych sekwencji wykonywanego kodu

public static boolean Wait(int milisec){}


Metoda znajdująca się wewnątrz metody main(), odpowiedzialna za obsługę zdarzeń

public void resultAccepted(ResultEvent e) {}


Metoda main()

Inicjalizacja obiektów odpowiedzialnych za wyświetlanie figur geometrycznych

final SterowaneOkno Plotno = new SterowaneOkno();
final Graphics graph = null;


Zawarte w konstrukcji try...catch utworzenie obiektu wybieracz, służącego do konfiguracji silników rozpoznawania oraz syntezy mowy

final SpeechEngineChooser wybieracz = SpeechEngineChooser.getAllEnginesDialog()


Po zebraniu informacji na temat dostępnych silników w systemie następuje uwidocznienie okna JSAPI Speech Engines (omówione w zakładce "Instalacja")

wybieracz.show();


Główny blok programy umieszczony w konstrukcji try...catch (ponieważ mogą w nim występować sytuacje wyjątkowe), w którym ustalone reguły gramatyczne zostają porównywane z otrzymanymi po rozpoznaniu komendami słownymi

 try{
    FinalResult r =(FinalResult)(e.getSource());
    Grammar gram = r.getGrammar();
 
    if(gram instanceof RuleGrammar) {
       String tags[] = ((FinalRuleResult)r).getTags();
 
             //ciąg_warunków if()
                        .
                        .
                        .
             if( tags[0].equals("ustalony_TAG") )
                        {
                         //reakcje_systemu
                        }
 
  catch(Exception e1) 
              {
               //reakcja_na_wystąpienie_wyjątku
              }

 
Obiekty odpowiedzialne za nasłuchiwanie wejścia mikrofonowego oraz jego przetwarzanie:

RecognizerAudioAdapter raud = new TestAudioListener();
Rozpoznawca.getAudioManager().addAudioListener(raud);
Rozpoznawca.addEngineListener(new TestEngineListener());


Alokacja głównego obiektu Rozpoznawca, oraz ustawienie profili mówcy, wcześniej wybranych w oknie konfiguracji dla rozpoznawania

Rozpoznawca.allocate();
SpeakerProfile profil = wybieracz.getSpeakerProfile();
Rozpoznawca.getSpeakerManager().setCurrentSpeaker(profil);
Rozpoznawca.waitEngineState(Recognizer.ALLOCATED);


Alokacja obiektu syntezatora mowy Syntezer

Syntezer.allocate();
Syntezer.waitEngineState(Synthesizer.ALLOCATED);
Syntezer.resume();


Przypisanie odpowiedniego głosu syntezatora, wcześniej wybranego w oknie konfiguracji syntezy

SynthesizerProperties syth_prop = Syntezer.getSynthesizerProperties();
syth_prop.setVoice(wybieracz.getVoice());


Utworzenie obowiązującej gramatyki rozpocznie się utworzeniem sekwencji reguł z podanymi poniżej TAG-ami

RuleSequence rs1 = new RuleSequence();
RuleTag regula_1 = new RuleTag(new RuleToken("komenda_1"),"TAG_1");
. 
. 
. 
RuleTag regula_n = new RuleTag(new RuleToken("komenda_n"),"TAG_N");


Po tej czynności każda z reguł zostaję dołączona do możliwych wariantów komend rozpoznawanych

RuleAlternatives wariant = new 
RuleAlternatives();
wariant.append(regula_1); 
. 
. 
. 
wariant.append(regula_n);


Następnie odbywa się utworzenie obiektu przechowującego naszą gramatykę, ustawienie reguł oraz uaktywnienie jej

RuleGrammar gramatyka = Rozpoznawca.newRuleGrammar("Gramatyka_1");
gramatyka.setRule("Reguły_1",wariant,true);
gramatyka.setEnabled(true);


Ostatecznie w konstrukcji finally...try...catch zostają zwolnione obiekty rozpoznawania oraz syntezy:
 
finally {
        try { Syntezer.deallocate();
              Rozpoznawca.deallocate();
              Rozpoznawca.waitEngineState(Synthesizer.DEALLOCATED);
              Syntezer.waitEngineState(Synthesizer.DEALLOCATED);
              } 
 
        catch(Exception e2) {
              e2.printStackTrace(System.out);
             }


class SterowaneOkno extends Frame {}

Klasa dziedzicząca z klasy Frame, która posłuży nam jako płótno edytora do wyświetlania zachodzących zdarzeń w programie

Pola klasy
 
public static int RysowanyElement = 0;
public static int KolorPlotna = 0;


Zmienne odpowiedzialne za ustalenie punktu początkowego, rozmiaru oraz przesunięcia, po modyfikacji których w trakcie działania programu możemy dowolnie manipulować figurami

public int x0 = 50; 
public int y0 = 50;
 
public int Rozmiar = 0;
public int szerokosc = 400;
public int wysokosc = 400;
 
public int Xoffset = 0;
public int Yoffset = 0;


Konstruktor

Odpowiada za ustawienie wybranych wartości początkowych nowo tworzonego obiektu


public SterowaneOkno()
        {
          setTitle("Plotno");
          setSize(500, 500);
          setLocation(200,200);
          setBackground(Color.gray);
        }


Metody klasy:

Główną metodą znajdującą się w klasie SterowaneOkno jest paint(), która przykrywa metodę klasy Frame. Odpowiedzialna za malowanie odpowiednich figur geometrycznych oraz zmianę koloru tła formularza Plotno podczas reakcji systemu na rozpoznanie wypowiadanej komendy słownej.

public void paint(Graphics powierzchnia){}


Realizują to dwa mechnizmy switch():

switch(KolorPlotna){}{
           //warianty_zmiany_tla
         }
 
switch(RysowanyElement){}{
           //warianty_rysowania_figur
         }



4. Sterowanie

Opis komend głosowych akceptowanych przez aplikacje

4.1. Sterowanie aplikacją
  • Exit ? wyjście z programu,
  • Open ? otwarcie płótna (formatki),
  • Close- schowanie płótna (formatki),
4.2. Powtorzenie sekwencji słów przez syntezator mowy
  • One ? wypowiedziane przez syntezator zostaną słowa - ?You speak One?.
  • Two - wypowiedziane przez syntezator zostaną słowa - ?You speak Two?.
  • Three - wypowiedziane przez syntezator zostaną słowa - ?You speak Three?.
  • Four - wypowiedziane przez syntezator zostaną słowa - ?You speak Four?.
4.4. Sterowanie wewnątrz aplikacji
  • Size? zmiana rozmiaru płótna,
  • Remove ? usuniecie figury oraz ustawienie białego koloru tła,
4.1 Ustawienie kolorów tła płótna  
  • White- ustawiony zostanie kolor biały,
  • Gray - ustawiony zostanie kolor szary,
  • Blue - ustawiony zostanie kolor niebieski,
  • Green - ustawiony zostanie kolor zielony,
  • Yellow - ustawiony zostanie kolor żółty,
4.2 Rysowanie podstawowych figur geometrycznych
  • Line ? na płótnie narysowana zostanie linia,
  • Circle - na płótnie narysowane zostanie kolo,
  • Rect- na płótnie narysowany zostanie prostokąt,
  • Fill ? wypelnienie aktualnie narysowanej figury.
4.3 Manipulacja figurami geometrycznymi
  • Grow ? powiększenie figury,
  • Reduce ? zmniejszenie figury,
  • Left ? przesuniecie w lewo,
  • Right - przesuniecie w prawo,
  • Up - przesuniecie w górę,
  • Down - przesuniecie w dół,

5.Przebieg działania programu

5.1. Po skompilowaniu oraz uruchomieniu programu

Ukazuje się okno konfiguracji JSAPI Speech Engines (omówione dokładniej w zakładce "Instalacja"), w którym dokonujemy ustawienia odpowiednich profili syntezy oraz rozpoznawania mowy. Gdy ukończymy etap konfiguracji zatwierdzając przyciskiem "OK", okno zostanie zamknięte a program uruchomi się w konsoli.



W pierwszych liniach oznaczonych symboliką

com.cloudgarden.speech.CGxxxxxxxxxxxxxx


następuje inicjalizacja oraz alokacja silników rozpoznawania i syntezy mowy
W ostatniej linii startowej programu możemy ujrzeć wpis

com.cloudgarden.speech.CGRecognizer@19a029e recognizerListening


co oznacza, iż program przeszedł w tryb nasłuchiwania mikrofonu. Od tej pory wychwytuje sygnał z wejścia mikrofonowego cyklicznie odpytując port karty muzycznej o czym świadczą pojawiające się (kilka razy/sek) komunikaty AudioLevel x.xx , przedstawiające poziom sygnału pobranego z mikrofonu.



Gdy poziom sygnału przekroczy pewną wartość graniczną system wychwyci to i podda klasyfikacji w celu rozpoznania co uwidocznione wyżej na screenie konsoli w trakcie działania poleceniami:

AudioLevel 0.49 
Speech started 
recognizerProcessing 
Speech stopped


Po czym program przechodzi dalej w tryb nasłuchiwania recognizerListening

5.2. Synteza

W trakcie działania możemy także ujrzeć znajdujące się w lewym górnym rogu ekranu usta położone na formatce, obrazujące wypowiedzi syntezatora podczas jego działania, które są obiektem klasy Mouth należącej do silnika syntezy mowy umieszczone w pakiecie

com.cloudgarden.speech.userinterface.Mouth; 




5.3. Rezultaty

Poniżej przedstawiono prosty przykład reakcji formatki programu na wypowiedzenie następującej sekwencji komend głosowych. Po każdej syntezator wypowiada także stosowne komentarze oznaczające prawidłowe rozpoznanie polecenia.

> open - circle - fill - blue <




Ostatnia komenda zostaje uwidoczniona na pasku tytułu formularza Płótno.


6. Listing omawianego projektu

Jest w fazie rozwoju więc trzeba go traktowac jako propozycja do rozbudowy i popracowania nad nim.


import package examples;
 
//zaimportowane pakiety z potrzebnymi klasami 
import examples.*;
import examples.synthesis.*;
 
//podstawowe pakiety Javy  
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;
 
//pakiety z modulami syntezy oraz rozpoznawania  -------------------------------
import javax.speech.*;
import javax.speech.recognition.*;
import javax.speech.synthesis.*;
 
import com.cloudgarden.speech.userinterface.*;
import com.cloudgarden.speech.CGEngineProperties;
import com.cloudgarden.speech.CGEngineCentral;
 
//-----klasy pomocnicze---
 
class SterowaneOkno extends Frame {
 
  public static int RysowanyElement = 0;
  public static int KolorPlotna = 0;
  public int Rozmiar = 0;
  public int Xoffset = 0;
  public int Yoffset = 0;
  public int x0 = 50; 
  public int y0 = 50;
  public int szerokosc = 400;
  public int wysokosc = 400;
 
  //konstruktor
  public SterowaneOkno(){
    setTitle("Plotno");
    setSize(500, 500);
    setLocation(200,200);
    setBackground(Color.gray);
    }
 
 
 
  //przykryta metoda paint klasy Frame
  public void paint(Graphics powierzchnia){
    switch(KolorPlotna){
      case  0 : setBackground(Color.white);
                break;
      case  1 : setBackground(Color.gray);
                break;
      case  2 : setBackground(Color.blue);
                break;
      case  3 : setBackground(Color.green);
                break;
      case  4 : setBackground(Color.yellow);
                break;
                }//!switch
 
    if(RysowanyElement == 0) return;
 
    else{
       switch(RysowanyElement){
         case  1 : powierzchnia.drawLine(50 + Xoffset, 50 + Yoffset,
                   400+ Rozmiar+ Xoffset, 400+ Rozmiar + Yoffset);
                   break;
         case  2 : powierzchnia.drawOval(50 + Xoffset, 50 + Yoffset,
                   400+ Rozmiar, 400+ Rozmiar);
                   break;
         case  3 : powierzchnia.drawRect(x0 + Xoffset,y0 +
                   Yoffset,szerokosc + Rozmiar,wysokosc+ Rozmiar);
                   break;        
         case  4 : powierzchnia.fillRect(x0 + Xoffset,y0 + 
                   Yoffset,szerokosc+ Rozmiar,wysokosc+ Rozmiar);
                   break;
         case  5 : powierzchnia.fillOval(50 + Xoffset, 50 + Yoffset,
                   400+ Rozmiar, 400+ Rozmiar);
                   break;        
                   }//!switch
          }//!else
   }//!paint
}//!SterowaneOkno
 
 
//------------------------------------------------------------------------------
 
 
//główna klasa  ----------------------------------------------------------------
 
public class RozpoznawanieOrazSynteza extends Thread {
  //główne obiekty programu (speech syntezier & speech recognition)
  public static Recognizer  Rozpoznawca = null;
  public static Synthesizer Syntezer = null;
 
  //obiekty służące do sterowania
  public static Frame OknoInformacji = null;    
  public static Label label1 = null;    
 
  //pomocnicze zmienne                
  public static boolean IsOpen = false;
  public static boolean IsExist = false;
  public static boolean IsResizing = false;
  public static int  OnClose = 0; 
 
  //czcionki
  public static Font czcionka1 = new Font( "Times New Roman", Font.ROMAN_BASELINE, 24 );
  public static Font czcionka2 = new Font( "Verdana", Font.ROMAN_BASELINE, 30 );
  public static Font czcionka3 = new Font( "Dialog", Font.ROMAN_BASELINE, 32 );
 
  //metody  --------------------------------------------------------------------
 
  //-------------------------------------
  public static void Informacje(int czas){
    OknoInformacji = new Frame("Program demonstrujacy sterowanie komputerem za pomoca głosu.");
    label1 = new Label("", Label.CENTER);
    label1.setBackground(Color.blue);
    label1.setForeground(Color.white);
    label1.setFont(czcionka3);
    OknoInformacji.setSize(1024,768);
    OknoInformacji.add(label1);
    OknoInformacji.setVisible(true);        
    label1.setText("Pomysł dla serwisu 4programmers.net");
    Wait(czas + 2000);
    label1.setFont(czcionka3);
    label1.setText("Program napisany przy użyciu pakietów Java Speech API");
    Wait(czas);
    label1.setFont(czcionka2);
    label1.setText("Autor:  Łukasz Mazur");
    Wait(czas);
    label1.setText("[email protected]");
    Wait(czas);
    label1.setFont(czcionka1);
    label1.setText("W oknie konfiguracji JSAPI Speech Engines proszę o ustawienie profili");
    Wait(czas);
    }//!Informacje
 
 
  //-------------------------------------
  public static void Wyjscie(int czas){
    OknoInformacji.setVisible(true);        
    label1.setFont(czcionka3);
    label1.setText("Pragram zakończony");
    Wait(czas);
    }//!Wyjscie
 
  //-------------------------------------
  public static boolean Wait(int milisec)
    {
     try{
         sleep(milisec);
         return true;
         }//try
     catch(InterruptedException e)
         {
          System.out.println("Wyjątek !");    
          return false;
         }//catch
    }//!Wait
 
  //matoda main  -----------------------------------------------------------------
  public static void main(String[] args){
    final SterowaneOkno Plotno = new  SterowaneOkno();
    final Graphics graph = null;
    //Informacje(4000);
 
    try{
       final SpeechEngineChooser wybieracz = SpeechEngineChooser.getAllEnginesDialog();
       //OknoInformacji.hide();
 
       wybieracz.show();
       RecognizerModeDesc desc = wybieracz.getRecognizerModeDesc();
       Rozpoznawca = Central.createRecognizer(desc);
       Rozpoznawca.addResultListener(new ResultAdapter() {
 
       //wykonywanie akcji po klasyfikacji wypowiedzi -----------------------
       public void resultAccepted(ResultEvent e) {
 
       try{
           FinalResult r =(FinalResult)(e.getSource());
           Grammar gram = r.getGrammar();
 
           if(gram instanceof RuleGrammar) {
              String tags[] = ((FinalRuleResult)r).getTags();
              if(tags == null || tags.length == 0) return;
 
              //--------------------------------------------------
              if(tags[0].equals("OPEN") && IsOpen ==false){
                Syntezer.speak("open window",null);
                Plotno.setVisible(true);
                IsOpen = true;}                              
 
              if(tags[0].equals("CLOSE") && IsOpen == true){
                Syntezer.speak("close window",null);
                Plotno.hide();
                IsOpen = false;}
 
              if(tags[0].equals("EXIT")){
                Syntezer.speak("Goodbyee !!!",null);
                Plotno.setTitle("Goodbyee !!!");
                Wyjscie(1000);
                System.exit(0);}
 
              //----------------------------------------------------------------   
              if(tags[0].equals("ONE"))   Syntezer.speak("You speak One",null);
              if(tags[0].equals("TWO"))   Syntezer.speak("You speak Two",null);
              if(tags[0].equals("THREE")) Syntezer.speak("You speak Three",null);
              if(tags[0].equals("FOUR"))  Syntezer.speak("You speak four",null);
              //----------------------------------------------------------------                               
 
              if(tags[0].equals("SIZE") && IsOpen == true ){   
                Syntezer.speak("I'am resizing ",null);                                                                                        if(IsResizing == false){
                Plotno.setLocation(50, 50);
                Plotno.setSize(800, 800);
                Plotno.setTitle("Plotno   -   resizing");
                IsResizing = true;
                }
              else{
                Plotno.setLocation(200, 200);
                Plotno.setSize(500, 500);
                Plotno.setTitle("Plotno   -   resizing");
                IsResizing = false;}}        
 
              if(tags[0].equals("REMOVE") && IsOpen == true ){   
                Syntezer.speak("I'am removing ",null);
                Plotno.setTitle("Plotno");
                Plotno.RysowanyElement = 0;
                Plotno.KolorPlotna = 0;
                IsExist = false;
                Plotno.repaint();                                  
                Plotno.removeAll();}
 
              //----------------------------------------------------------------   
              if(tags[0].equals("WHITE") && IsOpen == true ){   
                Syntezer.speak("Set white background ",null);
                Plotno.KolorPlotna = 0;;
                Plotno.setTitle("Plotno   -   white");
                Plotno.setVisible(true);
                Plotno.repaint();}    
 
              if(tags[0].equals("GRAY") && IsOpen == true ){   
                Syntezer.speak("Set gray background ",null);
                Plotno.KolorPlotna = 1;;
                Plotno.setTitle("Plotno   -   gray");
                Plotno.setVisible(true);
                Plotno.repaint();}     
 
              if(tags[0].equals("BLUE") && IsOpen == true ){   
                Syntezer.speak("Set blue background ",null);
                Plotno.KolorPlotna = 2;
                Plotno.setTitle("Plotno   -   blue");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("GREEN") && IsOpen == true ){   
                Syntezer.speak("Set gren background ",null);
                Plotno.KolorPlotna = 3;
                Plotno.setTitle("Plotno   -   green");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("YELLOW") && IsOpen == true ){   
                Syntezer.speak("Set yellow background ",null);                     
                Plotno.KolorPlotna = 4;
                Plotno.setTitle("Plotno   -   yellow");
                Plotno.setVisible(true);                        
                Plotno.repaint();
 
              //--------------------------------------------------
              if(tags[0].equals("LINE") && IsOpen == true ){   
                Syntezer.speak("I draw line",null);                                     
                Plotno.RysowanyElement = 1;
                Plotno.setTitle("Plotno   -   line");
                Plotno.setVisible(true);                        
                IsExist = true;
                Plotno.repaint();}
 
              if(tags[0].equals("CIRCLE") && IsOpen == true ){   
                Syntezer.speak("I draw circle",null);                                       
                Plotno.RysowanyElement = 2;
                Plotno.setVisible(true);                        
                IsExist = true;
                Plotno.repaint();}
 
              if(tags[0].equals("RECT") && IsOpen == true ){   
                Syntezer.speak("I draw rectangle",null);                         
                Plotno.RysowanyElement = 3;
                Plotno.setTitle("Plotno   -   rect");
                Plotno.setVisible(true);                        
                IsExist = true;                                     
                Plotno.repaint();}
 
              if(tags[0].equals("FILL") && IsOpen == true ){
                if(Plotno.RysowanyElement != 2 && Plotno.RysowanyElement != 3)
                  Syntezer.speak("There is nothing to fill",null);
 
                if(Plotno.RysowanyElement == 3){
                  Syntezer.speak("I fill rectangle",null);
                  Plotno.RysowanyElement = 4;
                  Plotno.setTitle("Plotno   -   fill rect");
                  Plotno.setVisible(true);                        
                  Plotno.repaint();}
 
                if(Plotno.RysowanyElement == 2){
                  Syntezer.speak("I fill circle",null);
                  Plotno.RysowanyElement = 5;
                  Plotno.setTitle("Plotno   -   fill circle");
                  Plotno.setVisible(true);                        
                  Plotno.repaint();}
                }
 
              if((IsExist == false) && (tags[0].equals("LEFT") || 
                tags[0].equals("RIGHT") ||tags[0].equals("UP") || 
                tags[0].equals("DOWN") || tags[0].equals("GROW")|| 
                tags[0].equals("REDUCE"))) 
                Syntezer.speak("There is nothing to control",null);;                                                        
 
              if(tags[0].equals("GROW") && IsOpen == true && IsExist == true ){   
                Syntezer.speak("I'am growing figure",null);                          
                Plotno.Rozmiar += 50;
                Plotno.setTitle("Plotno   -   grow");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("REDUCE") && IsOpen == true&& IsExist == true ){ 
                Syntezer.speak("I'am reduce figure",null);                          
                Plotno.Rozmiar -= 50;
                Plotno.setTitle("Plotno   -   reduce");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("LEFT") && IsOpen == true&& IsExist == true  ){   
                Syntezer.speak("Moving left",null);                                          
                Plotno.Xoffset -= 50;
                Plotno.setTitle("Plotno   -   left");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("RIGHT") && IsOpen == true && IsExist == true ){   
                Syntezer.speak("Moving right",null);                                     
                Plotno.Xoffset += 50;
                Plotno.setTitle("Plotno   -   right");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("UP") && IsOpen == true&& IsExist == true  ){   
                Syntezer.speak("Moving up",null);                                         
                Plotno.Yoffset -= 50;
                Plotno.setTitle("Plotno   -   up");
                Plotno.setVisible(true);                        
                Plotno.repaint();}
 
              if(tags[0].equals("DOWN") && IsOpen == true && IsExist == true ){   
                Syntezer.speak("Moving down",null);
                Plotno.setTitle("Plotno   -   down");
                Plotno.Yoffset += 50;
                Plotno.setVisible(true);                        
                Plotno.repaint();}
                //Recognizer.deallocate();
              } 
            else{
              ResultToken[] toks = r.getBestTokens();
              String result = "";
              for(int i = 0; i < toks.length; i++) result+= " " +toks[i].getSpokenText();
              Syntezer.speak(result,null);
              }//!else
 
            }//!try 
          catch(Exception e1) {
            e1.printStackTrace(System.out);
            }//!catch
          }
        }
      );
 
  RecognizerAudioAdapter raud = new TestAudioListener();
  Rozpoznawca.getAudioManager().addAudioListener(raud);
  Rozpoznawca.addEngineListener(new TestEngineListener());
  Rozpoznawca.allocate();
  SpeakerProfile profil = wybieracz.getSpeakerProfile();
  Rozpoznawca.getSpeakerManager().setCurrentSpeaker(profil);
  Rozpoznawca.waitEngineState(Recognizer.ALLOCATED);
 
 
  //----------Reguly gramatyczne------------------- 
  RuleSequence rs1 = new RuleSequence();
 
  //sterowanie aplikacją 
  RuleTag regula1 = new RuleTag(new RuleToken("exit"),"EXIT");
  RuleTag regula2 = new RuleTag(new RuleToken("open"),"OPEN");
  RuleTag regula3 = new RuleTag(new RuleToken("close"),"CLOSE");
 
  //po wypowiedzeniu zostanie powtorzone przez syntezator mowy                   
  RuleTag regula4 = new RuleTag(new RuleToken("one"),"ONE");
  RuleTag regula5 = new RuleTag(new RuleToken("two"),"TWO");
  RuleTag regula6 = new RuleTag(new RuleToken("three"),"THREE");
  RuleTag regula7 = new RuleTag(new RuleToken("four"),"FOUR");
 
  //sterowanie wewnątrz aplikacji
  RuleTag regula8 = new RuleTag(new RuleToken("size"),"SIZE");
  RuleTag regula9 = new RuleTag(new RuleToken("remove"),"REMOVE");
 
  //kolory tla plotna
  RuleTag regula10 = new RuleTag(new RuleToken("white"),"WHITE");
  RuleTag regula11 = new RuleTag(new RuleToken("gray"),"GRAY");                
  RuleTag regula12 = new RuleTag(new RuleToken("blue"),"BLUE");
  RuleTag regula13 = new RuleTag(new RuleToken("green"),"GREEN");
  RuleTag regula14 = new RuleTag(new RuleToken("yellow"),"YELLOW");
 
  //rysowanie podstawowych figur geometrycznych
  RuleTag regula15 = new RuleTag(new RuleToken("line"),"LINE");
  RuleTag regula16 = new RuleTag(new RuleToken("circle"),"CIRCLE");
  RuleTag regula17 = new RuleTag(new RuleToken("rect"),"RECT");
  RuleTag regula18 = new RuleTag(new RuleToken("fill"),"FILL");
 
  //manipulacja figuraimi
  RuleTag regula19 = new RuleTag(new RuleToken("grow"),"GROW");
  RuleTag regula20 = new RuleTag(new RuleToken("reduce"),"REDUCE");
  RuleTag regula21 = new RuleTag(new RuleToken("left"),"LEFT");
  RuleTag regula22 = new RuleTag(new RuleToken("right"),"RIGHT");
  RuleTag regula23 = new RuleTag(new RuleToken("up"),"UP");
  RuleTag regula24 = new RuleTag(new RuleToken("down"),"DOWN");
  RuleAlternatives wariant = new RuleAlternatives();
  wariant.append(regula2);
  wariant.append(regula3);
  wariant.append(regula4);
  wariant.append(regula5);
  wariant.append(regula6);
  wariant.append(regula7);
  wariant.append(regula8);
  wariant.append(regula9);
  wariant.append(regula10);
  wariant.append(regula11);
  wariant.append(regula12);
  wariant.append(regula13);
  wariant.append(regula14);
  wariant.append(regula15);
  wariant.append(regula16);
  wariant.append(regula17);
  wariant.append(regula18);
  wariant.append(regula19);
  wariant.append(regula20);
  wariant.append(regula21);
  wariant.append(regula22);
  wariant.append(regula23);
  wariant.append(regula24);
 
  RuleGrammar gramatyka = Rozpoznawca.newRuleGrammar("Gramatyka_1");
  gramatyka.setRule("Reguły_1",wariant,true);
  gramatyka.setEnabled(true);
 
  //-------------------------------------------------------------
  //Aby komputer po rozpoznaniu wypowiedzianego slowa przetworzyl
  //i wypowiedzial poprzez syntezator najbardziej zbliżone słowo 
  //do tego co rozpoznał należy odznaczyć poniższe dwie linie                
  //DictationGrammar dictGram = rec.getDictationGrammar(null);
  //dictGram.setEnabled(true);
  //-------------------------------------------------------------
 
  Syntezer = Central.createSynthesizer(null);
  Syntezer.addEngineListener(new TestEngineListener());
  Syntezer.allocate();
  Syntezer.waitEngineState(Synthesizer.ALLOCATED);
  Syntezer.resume();
  SynthesizerProperties syth_prop = Syntezer.getSynthesizerProperties();
  syth_prop.setVoice(wybieracz.getVoice());
 
  SpeakableListener spList = new TestSpeakableListener();
  Syntezer.addSpeakableListener(spList);
 
  SynthesizerProperties props = Syntezer.getSynthesizerProperties();
 
  syth_prop.setVolume(1.0f);
  syth_prop.setSpeakingRate(200.0f);
 
  Rozpoznawca.commitChanges();
  Rozpoznawca.requestFocus();
  Rozpoznawca.resume();
  Rozpoznawca.waitEngineState(Recognizer.DEALLOCATED);
 
  Syntezer.waitEngineState(Synthesizer.QUEUE_EMPTY);
  }catch(Exception e) {
    e.printStackTrace(System.out);
  }catch(Error e1) {
     e1.printStackTrace(System.out);
  }finally {
     try{
         Syntezer.deallocate();
         Rozpoznawca.deallocate();
         Rozpoznawca.waitEngineState(Synthesizer.DEALLOCATED);
         Syntezer.waitEngineState(Synthesizer.DEALLOCATED);
         } 
     catch(Exception e2) {
       e2.printStackTrace(System.out);
       }
    System.exit(0);
     }
    }
}//!RozpoznawanieOrazSynteza 
 



7. Rozbudowa oraz możliwości dalszej modyfikacji kodu

Program ma stosunkowo prostą budowę pod względem składni kodu więc istnieje w miarę łatwe rozbudowanie tego prostego edytora graficznego o nowe funkcje, ponieważ ideą tego projektu było pokazanie zasady sterowania aplikacją za pomocą głosu i syntezy mowy toteż możliwości edytora są niewielkie.

7.1. Możliwości modyfikacji

Aby powiększyć zbiór komend głosowych akceptowanych przez aplikację w trakcie działania musimy dodać nowe reguły gramatyczne

Umożliwia nam to klasa RuleTag, a dokonujemy tego w sposób następujący:

  • tworzymy nowy obiekt klasy RuleTag

RuleTag nowe_reguła = new RuleTag(new RuleToken("komenda"),"TAG");


  • po utworzeniu tego obiektu musimy uaktywnić w danej gramatyce istnienie tej reguły

RuleAlternatives ra = new RuleAlternatives();
ra.append(nowa_regula); 


  • gdy system zostanie już powiadomiony o możliwości wystąpienia po rozpoznaniu mowy takiej komendy należy przypisać odpowiednią akcję do tego zdarzenia, które znajduje się w ciele funkcji

public void resultAccepted(ResulyEvent e)
  { 
    //akcja_systemu
  }


co demonstruję poniżej:

Grammar gram = r.getGrammar();//pobranie utworzonej gramatyki


jeżeli wypowiedziane słowo poddane klasyfikacji przez system jest instancją aktualnie zdefiniowanej gramatyki

if(gram instanceof RuleGrammar)


to przypisujemy TAG słowa ze zbioru komend ( gramatyki ) do zdefiniowanego indntyfikatora, który jest łańcuchem (klasa String)

String identyfikator[] = ((FinalRuleResult)r).getTags();


Pozostaje tylko napisanie kodu jaki się wykona po przypisaniu TAG-u do zmiennej identyfikator, której klasa posiada metode equals(), co ułatwi porównywanie łańcuchów.

if( identyfikator[0].equals("TAG"))
  {
    //kod_reakcji_systemu
  }


Po dokonaniu zmian podczas rekompilacji kodu proponuje użycia bardziej rozbudowanych i zaawansowanych środowisk programistycznych z możliwością dołączania wielu pakietów rozszerzających możliwości języka (JavaExtension), w opcjach jdk
np: JCreator Pro, JBuilder, RealJava czy FreeJava


7.2. Propozycje rozbudowy

  • zwiększenie zbioru rysowanych figur geometrycznych,
  • wzbogacenie możliwości wypełniania tła oraz figur w pełnej palecie kolorów,
  • więcej możliwości manipulacji na płótnie obiektami,
  • większy zbiór komend dotyczących sterowania przebiegiem działania aplikacji
  • możliwość wyboru konkretnej figury (ustawienie skupienia) przy większej ilości obiektów na płótnie.




all rights reserved
artykuł napisany dla serwisu 4programmers.net
wszelkie pytania i uwagi na: [email protected]


... miłego experymentowania.
korekty nie wykluczone



Łukasz M.

2 komentarze

johnyjj2 2009-08-27 11:47

Tutorial jest po prostu świetny :-)
Pozdrawiam!

Coldpeer 2006-08-13 16:29

1) Zapowiada się ciekawie :)

2) Mała uwaga: tam gdzie masz kody, szczególnie ten jeden długi, fajnie by było jakbyś pozamieniał tabulatory na spacje (preferuję: 2 spacje == 1 tabulacja), dlatego, że kod staje bardzo nieczytelny na stronie.

3) Jestem za zmianą nazwy tego artykułu z "JSAPI" na "Rozpoznawanie oraz synteza mowy z wykorzystaniem JSAPI".