use strict; use warnings; =head1 NAME Speech recognition in Windows using the MS Speech API =head1 DESCRIPTION This is an example of using the Microsoft Speech SDK 5.1 under Windows for command and control speech recognition in Perl. Ported to perl from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/93025 but B. Sample code for using the Microsoft Speech SDK 5.1 via COM (aka Win32::OLE) in Perl. Requires that the SDK be installed; it's a free download from http://microsoft.com/speech After running this, then saying "One", "Two", "Three" or "Four" should display "You said One" etc on the console. The recognition can be a bit shaky at first until you've trained it (via the Speech entry in the Windows Control Panel. =head1 Classes =cut use Win32::OLE qw(EVENTS); use Win32::SAPI5; package SpeechRecognition; =head2 SpeechRecognition Initialize the speech recognition with the passed in list of words =head3 C<< SpeechRecognition->new(qw[ words to add ]) >> Initialize the speech recognition with the passed in list of words =cut sub new { my($self, @wordsToAdd)=@_; $self = bless {}, $self; # For text-to-speech $self->{speaker} = Win32::SAPI5::SpVoice->new() or die " \$^E => $^E\nLastError => ".Win32::OLE->LastError() ; # For speech recognition - first create a listener $self->{listener} = Win32::SAPI5::SpSharedRecognizer->new() or die " \$^E => $^E\nLastError => ".Win32::OLE->LastError() ; # Then a recognition context $self->{context} = $self->{listener}->CreateRecoContext() or die " \$^E => $^E\nLastError => ".Win32::OLE->LastError() ; # which has an associated grammar $self->{grammar} = $self->{context}->CreateGrammar() or die " \$^E => $^E\nLastError => ".Win32::OLE->LastError() ; # Do not allow free word recognition - only command and control # recognizing the words in the grammar only $self->{grammar}->DictationSetState(0); # Create a new rule for the grammar, that is top level (so it begins # a recognition) and dynamic (ie we can change it at runtime) use constant SRATopLevel => 1; #from Enum SpeechRuleAttributes use constant SRADynamic => 32; $self->{wordsRule} = $self->{grammar}->{Rules}->Add( "wordsRule" => SRATopLevel + SRADynamic, 0, ); # Clear the rule (not necessary first time, but if we're changing it # dynamically then it's useful) $self->{wordsRule}->Clear(); # And go through the list of words, adding each to the rule $self->{wordsRule}->{InitialState}->AddWordTransition(undef, $_) for @wordsToAdd; # Set the wordsRule to be active $self->{grammar}->{Rules}->Commit(); $self->{grammar}->CmdSetRuleState("wordsRule", 1); # Commit the changes to the grammar; $self->{grammar}->{Rules}->Commit(); # And add an event handler that's called back when recognition occurs # this part is different with Win32::OLE, needs testing $self->{eventHandler} = ContextEvents->new($self->{context}); $self->{context}->WithEvents('ContextEvents'); # $self->{context}->WithEvents( $self->{eventHandler} ); # Announce we've started using speech synthesis $self->say("Started successfully"); } =head3 C<< $self->say($phrase) >> Speak a word or phrase =cut sub say { my($self,$phrase)=@_; $self->{speaker}->Speak($phrase); } =head2 ContextEvents The callback class that handles the events raised by the speech object. See "Automation | SpSharedRecoContext (Events)" in the MS Speech SDK online help for documentation of the other events supported. @ContextEvents::ISA = Win32::SAPI5::SpSharedRecoContext =cut package ContextEvents; use base qw[ Win32::SAPI5::SpSharedRecoContext ]; =head3 C<< $self->OnRecognition(StreamNumber, StreamPosition, RecognitionType, Result) >> Called when a word/phrase is successfully recognized - ie it is found in a currently open grammar with a sufficiently high confidence =cut sub OnRecognition { my($self, $StreamNumber, $StreamPosition, $RecognitionType, $Result) = @_; my $newResult = $self->{speaker}->Invoke('Dispatch', $Result); print "You said: ", $newResult->{PhraseInfo}->GetText(); } sub Recognition { goto &OnRecognition } 1; package main; unless(caller){ my $speechReco = SpeechRecognition->new( "One", "Two", "Three", "Four" ); while(1){ # not quite sure which one is the equivalent of #pythoncom.PumpWaitingMessages() # Win32::OLE->MessageLoop(); Win32::OLE->SpinMessageLoop(); } }