=====Speech Recognition (Shared)=====
//by Rob Jeffs, February 2017//\\ \\ The code below demonstrates Command and Control speech recognition for a Shared Recognizer, via the API route (not COM automation/ActiveX). Although, confusingly, the first unavoidable step is to create an instance of a speech recognizer object using COM automation!\\ \\ Microsoft's online documentation provided the basis for this demonstration, including examples of xml Grammar files. The documentation contains object method lists in VTable order, which relate to the offsets in the SYS commands below; however, be aware that method tables include methods inherited from other objects.\\ \\ When running the code, the operating system may open a set-up wizard if speech recognition hasn't been used before. Because we're using a shared recognizer, this means that the desktop and other applications may also be listening for commands spoken by the user. A small 'User Interface' should appear, through which the microphone can be turned on and off. A related menu can be accessed via the icon bar, and it may be necessary to adjust the speech recognition language to English-US via the Control Panel / Advanced Speech Options. (The best results were obtained using a plug in microphone, without training.)\\ \\ Note: IIDFromString and CLSIDFromString perform identical functions
INSTALL @lib$+"COMLIB"
PROC_cominit
SYS "GetModuleHandle","OLE32.DLL" TO O%
SYS "GetProcAddress",O%,"IIDFromString" TO `IIDFromString`
SYS "GetProcAddress",O%,"CoTaskMemFree" TO `CoTaskMemFree`
DIM spevent{idpt%,stream%,audio_lo%,audio_hi%,wparam%,lparam%}:REM SPEVENT structure
DIM multib% 255:REM For converting 8 bit ASCII to 16 bit
ON CLOSE PROCcleanup:QUIT
ON ERROR PROCcleanup:REPORT:END
sr%=0:rc%=0:grammar%=0:REM Object pointers
PROCinit_speech_recog(@dir$+"GrammarColor.xml","ruleColors")
text%=0:REM Pointer to text returned from Recognition Result
PRINT"Listening..."
REPEAT
REM Poll the speech recognition event queue
spevent.lparam%=0
REM GetEvents by calling RecoContext method
SYS !(!rc%+44),rc%,1,spevent{},0
IF spevent.lparam%<>0 THEN
REM GetText by calling a Result method (Result is object in lparam%)
SYS !(!spevent.lparam%+20),spevent.lparam%,-1,-1,0,^text%,0
REM Make string from GetText
T$="":a=0
REPEAT
c=text%?a:a+=2:IF c<>0 THEN T$+=CHR$(c)
UNTIL c=0
PRINT T$
REM Release memory used for GetText
SYS `CoTaskMemFree`,text%
REM lparam% contains object pointer to RecoResult
PROC_releaseobject(spevent.lparam%)
ENDIF
WAIT 4
UNTIL FALSE
END
DEF PROCinit_speech_recog(P$,R$)
LOCAL C%,I%
REM Create Shared Recognizer
DIM C% LOCAL 15,I% LOCAL 15
PROCconvert_to_wide("{C2B5F241-DAA0-4507-9E16-5A1EAA2B7A5C}"):REM IID_ISpRecognizer
SYS `IIDFromString`,multib%,I%
PROCconvert_to_wide("{3BEE4890-4FE9-4A37-8C1E-5E7E12791C1F}"):REM CLSID_SpSharedRecognizer
SYS `CLSIDFromString`,multib%,C%
SYS `CoCreateInstance`,C%,0,15,I%,^sr%:REM CLSCTX_ALL
REM Create RecoContext by calling a SharedRecognizer method
SYS !(!sr%+48),sr%,^rc%
REM Create Grammar object by calling a RecoContext method
SYS !(!rc%+56),rc%,0,0,^grammar%
REM Load Grammar file (xml) by calling a Grammar method
PROCconvert_to_wide(P$)
SYS !(!grammar%+52),grammar%,multib%,0
REM Set Rule State to active by calling a Grammar method
PROCconvert_to_wide(R$)
SYS !(!grammar%+72),grammar%,multib%,0,1
ENDPROC
DEF PROCconvert_to_wide(T$)
SYS "MultiByteToWideChar",0,0,T$,-1,multib%,LEN(T$)+1
ENDPROC
DEF PROCcleanup
ON ERROR OFF
IF grammar%>0 THEN PROC_releaseobject(grammar%)
IF rc%>0 THEN PROC_releaseobject(rc%):REM RecoContext
IF sr%>0 THEN PROC_releaseobject(sr%):REM Shared Recognizer
PROC_comexit
ENDPROC
Here's the xml source required for recognizing the names of BASIC colours. It can be entered via Notepad and should be saved as GrammarColor.xml
- red
- green
- yellow
- blue
- magenta
- cyan
- white
- black