diff --git a/src/GF/API.hs b/src/GF/API.hs index 6ba3c261a..469b762ed 100644 --- a/src/GF/API.hs +++ b/src/GF/API.hs @@ -59,6 +59,8 @@ import qualified GF.Embed.EmbedAPI as EA import GF.UseGrammar.Editing +import GF.System.SpeechInput (recognizeSpeech) + ----import GrammarToXML ----import GrammarToMGrammar as M @@ -206,6 +208,14 @@ speechGenerate opts str = do --- system ("echo" +++ "\"" ++ str ++ "\" | festival --tts" ++ lan) return () +-- FIXME: look at flags +speechInput :: Options -> StateGrammar -> IO String +speechInput opt s = recognizeSpeech name opts cfg + where + opts = stateOptions s + name = cncId s + cfg = stateCFG s + optLinearizeTreeVal :: Options -> GFGrammar -> Tree -> String optLinearizeTreeVal opts gr = err id id . optLinearizeTree opts gr diff --git a/src/GF/Shell.hs b/src/GF/Shell.hs index 541f2ea66..eb13cbdf7 100644 --- a/src/GF/Shell.hs +++ b/src/GF/Shell.hs @@ -348,6 +348,7 @@ execC co@(comm, opts0) sa@(sh@(st,(h,_,_,_)),a) = checkOptions st co >> case com CWriteFile file -> justOutputArg opts (writeFile file) sa CAppendFile file -> justOutputArg opts (appendFile file) sa CSpeakAloud -> justOutputArg opts (speechGenerate opts) sa + CSpeechInput -> returnArgIO (speechInput opts gro >>= return . AString) sa CSystemCommand s -> case a of AUnit -> justOutput opts (system s >> return ()) sa _ -> systemArg opts a s sa diff --git a/src/GF/Shell/HelpFile.hs b/src/GF/Shell/HelpFile.hs index 82d3a9713..db8b81a29 100644 --- a/src/GF/Shell/HelpFile.hs +++ b/src/GF/Shell/HelpFile.hs @@ -480,6 +480,14 @@ txtHelpFile = "\n h | sa -- listen to the list of commands" ++ "\n gr -cat=S | l | sa -- generate a random sentence and speak it aloud" ++ "\n" ++ + "\nsi, speech_input: si" ++ + "\n Uses an ATK speech recognizer to get speech input. " ++ + "\n flags:" ++ + "\n -lang: The grammar to use with the speech recognizer." ++ + "\n -cat: The grammar category to get input in." ++ + "\n -language: Use acoustic model and dictionary for this language." ++ + "\n -number: The number of utterances to recognize." ++ + "\n" ++ "\nh, help: h Command?" ++ "\n Displays the paragraph concerning the command from this help file." ++ "\n Without the argument, shows the first lines of all paragraphs." ++ diff --git a/src/GF/Shell/PShell.hs b/src/GF/Shell/PShell.hs index cd54c71ed..77264fee9 100644 --- a/src/GF/Shell/PShell.hs +++ b/src/GF/Shell/PShell.hs @@ -134,6 +134,7 @@ pCommand ws = case ws of "af" : f : s -> aString (CAppendFile (unquote f)) s "rf" : f : [] -> aUnit (CReadFile (unquote f)) "sa" : s -> aString CSpeakAloud s + "si" : [] -> aUnit CSpeechInput "ps" : s -> aString CPutString s "st" : s -> aTerm CShowTerm s "!" : s -> aUnit (CSystemCommand (unwords s)) diff --git a/src/GF/Shell/ShellCommands.hs b/src/GF/Shell/ShellCommands.hs index bf7d4f1ff..27e027c50 100644 --- a/src/GF/Shell/ShellCommands.hs +++ b/src/GF/Shell/ShellCommands.hs @@ -65,6 +65,7 @@ data Command = | CWriteFile FilePath | CAppendFile FilePath | CSpeakAloud + | CSpeechInput | CPutString | CShowTerm | CSystemCommand String @@ -197,6 +198,8 @@ optionsOfCommand co = case co of CWriteFile _ -> none CAppendFile _ -> none CSpeakAloud -> flags "language" + CSpeechInput -> flags "lang cat language number" + CPutString -> both "utf8" "filter length" CShowTerm -> flags "printer" CShowTreeGraph -> opts "c f g o" diff --git a/src/GF/Speech/CFGToFiniteState.hs b/src/GF/Speech/CFGToFiniteState.hs index 5a72f548a..405e4324e 100644 --- a/src/GF/Speech/CFGToFiniteState.hs +++ b/src/GF/Speech/CFGToFiniteState.hs @@ -27,9 +27,8 @@ import GF.Speech.FiniteState import GF.Speech.Relation import GF.Speech.TransformCFG -cfgToFA :: Ident -- ^ Grammar name - -> Options -> CGrammar -> DFA String -cfgToFA name opts = minimize . compileAutomaton start . makeSimpleRegular +cfgToFA :: Options -> CGrammar -> DFA String +cfgToFA opts = minimize . compileAutomaton start . makeSimpleRegular where start = getStartCat opts makeSimpleRegular :: CGrammar -> CFRules diff --git a/src/GF/Speech/PrFA.hs b/src/GF/Speech/PrFA.hs index 79a9356db..1dac4fab0 100644 --- a/src/GF/Speech/PrFA.hs +++ b/src/GF/Speech/PrFA.hs @@ -37,7 +37,7 @@ import Data.Maybe (fromMaybe) faGraphvizPrinter :: Ident -- ^ Grammar name -> Options -> CGrammar -> String faGraphvizPrinter name opts cfg = - prFAGraphviz $ mapStates (const "") $ cfgToFA name opts cfg + prFAGraphviz $ mapStates (const "") $ cfgToFA opts cfg -- | Convert the grammar to a regular grammar and print it in BNF @@ -51,7 +51,7 @@ regularPrinter = prCFRules . makeSimpleRegular faCPrinter :: Ident -- ^ Grammar name -> Options -> CGrammar -> String -faCPrinter name opts cfg = fa2c $ cfgToFA name opts cfg +faCPrinter name opts cfg = fa2c $ cfgToFA opts cfg fa2c :: DFA String -> String fa2c fa = undefined \ No newline at end of file diff --git a/src/GF/Speech/PrSLF.hs b/src/GF/Speech/PrSLF.hs index 9e497872e..eb9055d0b 100644 --- a/src/GF/Speech/PrSLF.hs +++ b/src/GF/Speech/PrSLF.hs @@ -48,16 +48,15 @@ data SLFEdge = SLFEdge { eId :: Int, eStart :: Int, eEnd :: Int } slfPrinter :: Ident -- ^ Grammar name -> Options -> CGrammar -> String -slfPrinter name opts cfg = prSLF (automatonToSLF $ mkSLFFA name opts cfg) "" +slfPrinter name opts cfg = prSLF (automatonToSLF $ mkSLFFA opts cfg) "" slfGraphvizPrinter :: Ident -- ^ Grammar name - -> Options -> CGrammar -> String + -> Options -> CGrammar -> String slfGraphvizPrinter name opts cfg = - prFAGraphviz $ mapStates (fromMaybe "") $ mapTransitions (const "") $ mkSLFFA name opts cfg + prFAGraphviz $ mapStates (fromMaybe "") $ mapTransitions (const "") $ mkSLFFA opts cfg -mkSLFFA :: Ident -- ^ Grammar name - -> Options -> CGrammar -> FA State (Maybe String) () -mkSLFFA name opts cfg = oneFinalState Nothing () $ moveLabelsToNodes $ dfa2nfa $ cfgToFA name opts cfg +mkSLFFA :: Options -> CGrammar -> FA State (Maybe String) () +mkSLFFA opts cfg = oneFinalState Nothing () $ moveLabelsToNodes $ dfa2nfa $ cfgToFA opts cfg automatonToSLF :: FA State (Maybe String) () -> SLF automatonToSLF fa = SLF { slfNodes = map mkSLFNode (states fa), diff --git a/src/GF/System/ATKSpeechInput.hs b/src/GF/System/ATKSpeechInput.hs new file mode 100644 index 000000000..8c0ed303e --- /dev/null +++ b/src/GF/System/ATKSpeechInput.hs @@ -0,0 +1,65 @@ +---------------------------------------------------------------------- +-- | +-- Module : GF.System.ATKSpeechInput +-- Maintainer : BB +-- Stability : (stable) +-- Portability : (non-portable) +-- +-- > CVS $Date: 2005/05/10 15:04:01 $ +-- > CVS $Author: bringert $ +-- > CVS $Revision: 1.2 $ +-- +-- Use ATK and Speech.ATKRec for speech input. +----------------------------------------------------------------------------- + +module GF.System.ATKSpeechInput (recognizeSpeech) where + +import GF.Infra.Ident (Ident, prIdent) +import GF.Infra.Option (Options) +import GF.Conversion.Types (CGrammar) +import GF.Speech.PrSLF + +import Speech.ATKRec + +import Control.Monad +import Data.IORef +import System.IO +import System.IO.Unsafe + +-- FIXME: get these from somewhere else + +config = "/home/bjorn/projects/atkrec/atkrec.cfg" + +res = "/home/bjorn/src/atk/Resources" +hmmlist = res ++ "/UK_SI_ZMFCC/hmmlistbg" +mmf0 = res ++ "/UK_SI_ZMFCC/WI4" +mmf1 = res ++ "/UK_SI_ZMFCC/BGHMM2" +dict = res ++ "/beep.dct" + +initialized :: IORef Bool +initialized = unsafePerformIO $ newIORef False + +initATK :: IO () +initATK = do + b <- readIORef initialized + when (not b) $ do + hPutStrLn stderr "Initializing..." + initialize config + loadHMMSet "hmm_english" hmmlist mmf0 mmf1 + loadDict "dict_english" dict + writeIORef initialized True + +recognizeSpeech :: Ident -- ^ Grammar name + -> Options -> CGrammar -> IO String +recognizeSpeech name opts cfg = + do + let slf = slfPrinter name opts cfg + n = prIdent name + slfName = "gram_" ++ n + recName = "rec_english_" ++ n + initATK + loadGrammarString slfName slf + createRecognizer recName "hmm_english" "dict_english" slfName + hPutStrLn stderr "Listening..." + s <- recognize recName + return s diff --git a/src/GF/System/NoSpeechInput.hs b/src/GF/System/NoSpeechInput.hs new file mode 100644 index 000000000..2f967f66f --- /dev/null +++ b/src/GF/System/NoSpeechInput.hs @@ -0,0 +1,17 @@ +---------------------------------------------------------------------- +-- | +-- Module : GF.System.NoSpeechInput +-- Maintainer : BB +-- Stability : (stable) +-- Portability : (portable) +-- +-- > CVS $Date: 2005/05/10 15:04:01 $ +-- > CVS $Author: bringert $ +-- > CVS $Revision: 1.2 $ +-- +-- Dummy speech input. +----------------------------------------------------------------------------- + +module GF.System.NoSpeechInput (recognizeSpeech) where + +recognizeSpeech = fail "No speech input available" diff --git a/src/GF/System/SpeechInput.hs b/src/GF/System/SpeechInput.hs new file mode 100644 index 000000000..6c2374473 --- /dev/null +++ b/src/GF/System/SpeechInput.hs @@ -0,0 +1,27 @@ +{-# OPTIONS -cpp #-} + +---------------------------------------------------------------------- +-- | +-- Module : GF.System.SpeechInput +-- Maintainer : BB +-- Stability : (stable) +-- Portability : (portable) +-- +-- > CVS $Date: 2005/05/10 15:04:01 $ +-- > CVS $Author: bringert $ +-- > CVS $Revision: 1.2 $ +-- +-- Uses the right speech recognition library for speech input. +----------------------------------------------------------------------------- + +module GF.System.SpeechInput (recognizeSpeech) where + +#ifdef USE_ATK + +import GF.System.ATKSpeechInput (recognizeSpeech) + +#else + +import GF.System.NoSpeechInput (recognizeSpeech) + +#endif diff --git a/src/HelpFile b/src/HelpFile index d87be7d05..880876f16 100644 --- a/src/HelpFile +++ b/src/HelpFile @@ -451,6 +451,14 @@ sa, speak_aloud: sa String h | sa -- listen to the list of commands gr -cat=S | l | sa -- generate a random sentence and speak it aloud +si, speech_input: si + Uses an ATK speech recognizer to get speech input. + flags: + -lang: The grammar to use with the speech recognizer. + -cat: The grammar category to get input in. + -language: Use acoustic model and dictionary for this language. + -number: The number of utterances to recognize. + h, help: h Command? Displays the paragraph concerning the command from this help file. Without the argument, shows the first lines of all paragraphs. diff --git a/src/Makefile b/src/Makefile index d011cd636..b59ff6676 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,6 +48,10 @@ ifeq ("$(INTERRUPT)","yes") GHCFLAGS += -DUSE_INTERRUPT endif +ifeq ("$(ATK)","yes") + GHCFLAGS += -DUSE_ATK +endif + ifeq ("$(ENABLE_JAVA)", "yes") BUILD_JAR=jar else diff --git a/src/config.mk.in b/src/config.mk.in index c13563992..1a44f80c9 100644 --- a/src/config.mk.in +++ b/src/config.mk.in @@ -27,6 +27,8 @@ READLINE = @READLINE@ INTERRUPT = @INTERRUPT@ +ATK = @ATK@ + ENABLE_JAVA = @ENABLE_JAVA@ JAVAC = "@JAVAC@" diff --git a/src/configure.ac b/src/configure.ac index 64e1015bc..bfab7aebf 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -115,6 +115,41 @@ esac AC_SUBST(INTERRUPT) +dnl *********************************************** +dnl ATK speech recognition +dnl *********************************************** + +AC_ARG_WITH(atk, + AC_HELP_STRING([--with-atk=], + [Choose whether to compile in support for speech + recognition using ATK. Requires ATK and libatkrec. + Available alternatives are: 'yes', 'no' + (default = no)]), + [ATK="$withval"], + [ATK="no"]) + +case $ATK in + yes) + AC_MSG_CHECKING([for atkrec package]) + ATKREC_VERSION=`ghc-pkg latest atkrec` + if test "$ATKREC_VERSION" = ""; then + AC_MSG_RESULT(['not found']) + AC_MSG_WARN([Disabling ATK support.]) + ATK="no" + else + AC_MSG_RESULT([$ATKREC_VERSION]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([Bad value for --with-atk: $ATK]) + + ;; +esac + +AC_SUBST(ATK) + dnl *********************************************** dnl java stuff dnl ***********************************************